# HG changeset patch # User lana # Date 1445537588 25200 # Node ID 643e2fbeccc328c64d73ee90e669c93cffd183b9 # Parent 5e522d8ea16c039b14706d441a14727eefd1ff28# Parent 0729c02cb8457f9d3ef4c99db9e005793a282d6b Merge diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/ImmutableOopMapSet.java Thu Oct 22 11:13:08 2015 -0700 @@ -67,9 +67,6 @@ } } - public void visitValueLocation(Address valueAddr) { - } - public void visitNarrowOopLocation(Address narrowOopAddr) { addressVisitor.visitCompOopAddress(narrowOopAddr); } @@ -216,9 +213,9 @@ } } - // We want narow oop, value and oop oop_types - OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[]{ - OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE + // We want narow oop and oop oop_types + OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] { + OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE }; { @@ -231,8 +228,6 @@ // to detect in the debugging system // assert(Universe::is_heap_or_null(*loc), "found non oop pointer"); visitor.visitOopLocation(loc); - } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) { - visitor.visitValueLocation(loc); } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) { visitor.visitNarrowOopLocation(loc); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -49,7 +49,6 @@ // Types of OopValues static int UNUSED_VALUE; static int OOP_VALUE; - static int VALUE_VALUE; static int NARROWOOP_VALUE; static int CALLEE_SAVED_VALUE; static int DERIVED_OOP_VALUE; @@ -73,7 +72,6 @@ REGISTER_MASK_IN_PLACE = db.lookupIntConstant("OopMapValue::register_mask_in_place").intValue(); UNUSED_VALUE = db.lookupIntConstant("OopMapValue::unused_value").intValue(); OOP_VALUE = db.lookupIntConstant("OopMapValue::oop_value").intValue(); - VALUE_VALUE = db.lookupIntConstant("OopMapValue::value_value").intValue(); NARROWOOP_VALUE = db.lookupIntConstant("OopMapValue::narrowoop_value").intValue(); CALLEE_SAVED_VALUE = db.lookupIntConstant("OopMapValue::callee_saved_value").intValue(); DERIVED_OOP_VALUE = db.lookupIntConstant("OopMapValue::derived_oop_value").intValue(); @@ -82,7 +80,6 @@ public static abstract class OopTypes { public static final OopTypes UNUSED_VALUE = new OopTypes() { int getValue() { return OopMapValue.UNUSED_VALUE; }}; public static final OopTypes OOP_VALUE = new OopTypes() { int getValue() { return OopMapValue.OOP_VALUE; }}; - public static final OopTypes VALUE_VALUE = new OopTypes() { int getValue() { return OopMapValue.VALUE_VALUE; }}; public static final OopTypes NARROWOOP_VALUE = new OopTypes() { int getValue() { return OopMapValue.NARROWOOP_VALUE; }}; public static final OopTypes CALLEE_SAVED_VALUE = new OopTypes() { int getValue() { return OopMapValue.CALLEE_SAVED_VALUE; }}; public static final OopTypes DERIVED_OOP_VALUE = new OopTypes() { int getValue() { return OopMapValue.DERIVED_OOP_VALUE; }}; @@ -105,7 +102,6 @@ // Querying public boolean isOop() { return (getValue() & TYPE_MASK_IN_PLACE) == OOP_VALUE; } - public boolean isValue() { return (getValue() & TYPE_MASK_IN_PLACE) == VALUE_VALUE; } public boolean isNarrowOop() { return (getValue() & TYPE_MASK_IN_PLACE) == NARROWOOP_VALUE; } public boolean isCalleeSaved() { return (getValue() & TYPE_MASK_IN_PLACE) == CALLEE_SAVED_VALUE; } public boolean isDerivedOop() { return (getValue() & TYPE_MASK_IN_PLACE) == DERIVED_OOP_VALUE; } @@ -117,7 +113,6 @@ int which = (getValue() & TYPE_MASK_IN_PLACE); if (which == UNUSED_VALUE) return OopTypes.UNUSED_VALUE; else if (which == OOP_VALUE) return OopTypes.OOP_VALUE; - else if (which == VALUE_VALUE) return OopTypes.VALUE_VALUE; else if (which == NARROWOOP_VALUE) return OopTypes.NARROWOOP_VALUE; else if (which == CALLEE_SAVED_VALUE) return OopTypes.CALLEE_SAVED_VALUE; else if (which == DERIVED_OOP_VALUE) return OopTypes.DERIVED_OOP_VALUE; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java Thu Oct 22 11:13:08 2015 -0700 @@ -31,6 +31,5 @@ public interface OopMapVisitor { public void visitOopLocation(Address oopAddr); public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr); - public void visitValueLocation(Address valueAddr); public void visitNarrowOopLocation(Address narrowOopAddr); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java Thu Oct 22 11:13:08 2015 -0700 @@ -536,9 +536,6 @@ } } - public void visitValueLocation(Address valueAddr) { - } - public void visitNarrowOopLocation(Address compOopAddr) { addressVisitor.visitCompOopAddress(compOopAddr); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Thu Oct 22 11:13:08 2015 -0700 @@ -1220,9 +1220,6 @@ oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE); buf.append(omvIterator.iterate(oms, "NarrowOops:", false)); - oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE); - buf.append(omvIterator.iterate(oms, "Values:", false)); - oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); buf.append(omvIterator.iterate(oms, "Callee saved:", true)); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/bsd/makefiles/compiler1.make --- a/hotspot/make/bsd/makefiles/compiler1.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/bsd/makefiles/compiler1.make Thu Oct 22 11:13:08 2015 -0700 @@ -28,4 +28,7 @@ VM_SUBDIR = client +# We don't support the JVMCI in a client VM. +INCLUDE_JVMCI := false + CFLAGS += -DCOMPILER1 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/bsd/makefiles/gcc.make --- a/hotspot/make/bsd/makefiles/gcc.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/bsd/makefiles/gcc.make Thu Oct 22 11:13:08 2015 -0700 @@ -149,6 +149,7 @@ PCH_FLAG/sharedRuntimeTrig.o = $(PCH_FLAG/NO_PCH) PCH_FLAG/sharedRuntimeTrans.o = $(PCH_FLAG/NO_PCH) PCH_FLAG/unsafe.o = $(PCH_FLAG/NO_PCH) + PCH_FLAG/jvmciCompilerToVM.o = $(PCH_FLAG/NO_PCH) endif else # ($(USE_CLANG), true) @@ -313,10 +314,11 @@ # Work around some compiler bugs. ifeq ($(USE_CLANG), true) - # Clang <= 6.1 + # Clang < 6 | <= 6.1 | <= 7.0 ifeq ($(shell expr \ $(CC_VER_MAJOR) \< 6 \| \ - \( $(CC_VER_MAJOR) = 6 \& $(CC_VER_MINOR) \<= 1 \) \ + \( $(CC_VER_MAJOR) = 6 \& $(CC_VER_MINOR) \<= 1 \) \| \ + \( $(CC_VER_MAJOR) = 7 \& $(CC_VER_MINOR) \<= 0 \) \ ), 1) OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT) OPT_CFLAGS/unsafe.o += -O1 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/bsd/makefiles/jsig.make --- a/hotspot/make/bsd/makefiles/jsig.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/bsd/makefiles/jsig.make Thu Oct 22 11:13:08 2015 -0700 @@ -62,7 +62,7 @@ $(LIBJSIG): $(JSIGSRCDIR)/jsig.c $(LIBJSIG_MAPFILE) @echo $(LOG_INFO) Making signal interposition lib... $(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \ - $(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) -o $@ $< + $(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) $(EXTRA_CFLAGS) -o $@ $< ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) ifeq ($(OS_VENDOR), Darwin) $(DSYMUTIL) $@ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/bsd/makefiles/minimal1.make --- a/hotspot/make/bsd/makefiles/minimal1.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/bsd/makefiles/minimal1.make Thu Oct 22 11:13:08 2015 -0700 @@ -38,6 +38,7 @@ INCLUDE_NMT := false INCLUDE_TRACE := false INCLUDE_CDS := false +INCLUDE_JVMCI := false CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" CFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/excludeSrc.make --- a/hotspot/make/excludeSrc.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/excludeSrc.make Thu Oct 22 11:13:08 2015 -0700 @@ -106,6 +106,25 @@ memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp endif +ifneq (,$(findstring $(Platform_arch_model), x86_64, sparc)) + # JVMCI is supported only on x86_64 and SPARC. +else + INCLUDE_JVMCI := false +endif + +ifeq ($(INCLUDE_JVMCI), false) + CXXFLAGS += -DINCLUDE_JVMCI=0 + CFLAGS += -DINCLUDE_JVMCI=0 + + jvmci_dir := $(HS_COMMON_SRC)/share/vm/jvmci + jvmci_dir_alt := $(HS_ALT_SRC)/share/vm/jvmci + jvmci_exclude := $(notdir $(wildcard $(jvmci_dir)/*.cpp)) \ + $(notdir $(wildcard $(jvmci_dir_alt)/*.cpp)) + Src_Files_EXCLUDE += $(jvmci_exclude) \ + jvmciCodeInstaller_aarch64.cpp jvmciCodeInstaller_ppc.cpp jvmciCodeInstaller_sparc.cpp \ + jvmciCodeInstaller_x86.cpp +endif + -include $(HS_ALT_MAKE)/excludeSrc.make .PHONY: $(HS_ALT_MAKE)/excludeSrc.make diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,122 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute 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. +# + +default: all + +include $(SPEC) +include MakeBase.gmk +include JavaCompilation.gmk +include SetupJavaCompilers.gmk + +GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.vm.ci +SRC_DIR := $(HOTSPOT_TOPDIR)/src/jdk.vm.ci/share/classes + +################################################################################ +# Compile the annotation processor + +$(eval $(call SetupJavaCompilation, BUILD_JVMCI_OPTIONS, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(SRC_DIR)/jdk.vm.ci.options/src \ + $(SRC_DIR)/jdk.vm.ci.options.processor/src \ + $(SRC_DIR)/jdk.vm.ci.inittimer/src, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jvmci_options, \ + JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.options.jar, \ +)) + +$(eval $(call SetupJavaCompilation, BUILD_JVMCI_SERVICE, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(SRC_DIR)/jdk.vm.ci.service/src \ + $(SRC_DIR)/jdk.vm.ci.service.processor/src, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jvmci_service, \ + JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.service.jar, \ +)) + +################################################################################ + +PROC_SRC_SUBDIRS := \ + jdk.vm.ci.compiler \ + jdk.vm.ci.hotspot \ + jdk.vm.ci.hotspot.amd64 \ + jdk.vm.ci.hotspot.sparc \ + # + +PROC_SRC_DIRS := $(patsubst %, $(SRC_DIR)/%/src, $(PROC_SRC_SUBDIRS)) + +PROC_SRCS := $(filter %.java, $(call CacheFind, $(PROC_SRC_DIRS))) + +ALL_SRC_DIRS := $(wildcard $(SRC_DIR)/*/src) +SOURCEPATH := $(call PathList, $(ALL_SRC_DIRS)) +PROCESSOR_PATH := $(call PathList, \ + $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.options.jar \ + $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.ci.service.jar) + +$(GENSRC_DIR)/_gensrc_proc_done: $(PROC_SRCS) \ + $(BUILD_JVMCI_OPTIONS) $(BUILD_JVMCI_SERVICE) + $(MKDIR) -p $(@D) + $(eval $(call ListPathsSafely,PROC_SRCS,$(@D)/_gensrc_proc_files)) + $(JAVA_SMALL) $(NEW_JAVAC) \ + -XDignore.symbol.file \ + -sourcepath $(SOURCEPATH) \ + -implicit:none \ + -proc:only \ + -processorpath $(PROCESSOR_PATH) \ + -d $(GENSRC_DIR) \ + -s $(GENSRC_DIR) \ + @$(@D)/_gensrc_proc_files + $(TOUCH) $@ + +TARGETS += $(GENSRC_DIR)/_gensrc_proc_done + +################################################################################ + +$(GENSRC_DIR)/META-INF/services/jdk.vm.ci.options.OptionDescriptors: \ + $(GENSRC_DIR)/_gensrc_proc_done + $(MKDIR) -p $(@D) + ($(CD) $(GENSRC_DIR)/META-INF/jvmci.options && \ + $(RM) -f $@; \ + for i in $$(ls); do \ + echo $${i}_OptionDescriptors >> $@; \ + done) + +TARGETS += $(GENSRC_DIR)/META-INF/services/jdk.vm.ci.options.OptionDescriptors + +################################################################################ + +$(GENSRC_DIR)/_providers_converted: $(GENSRC_DIR)/_gensrc_proc_done + $(MKDIR) -p $(GENSRC_DIR)/META-INF/services + ($(CD) $(GENSRC_DIR)/META-INF/jvmci.providers && \ + for i in $$($(LS)); do \ + c=$$($(CAT) $$i | $(TR) -d '\n\r'); \ + $(ECHO) $$i >> $(GENSRC_DIR)/META-INF/services/$$c; \ + done) + $(TOUCH) $@ + +TARGETS += $(GENSRC_DIR)/_providers_converted + +################################################################################ + +all: $(TARGETS) + +.PHONY: default all diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/linux/makefiles/compiler1.make --- a/hotspot/make/linux/makefiles/compiler1.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/linux/makefiles/compiler1.make Thu Oct 22 11:13:08 2015 -0700 @@ -28,4 +28,7 @@ VM_SUBDIR = client +# We don't support the JVMCI in a client VM. +INCLUDE_JVMCI := false + CFLAGS += -DCOMPILER1 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/linux/makefiles/gcc.make --- a/hotspot/make/linux/makefiles/gcc.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/linux/makefiles/gcc.make Thu Oct 22 11:13:08 2015 -0700 @@ -213,12 +213,16 @@ # Since GCC 4.3, -Wconversion has changed its meanings to warn these implicit # conversions which might affect the values. Only enable it in earlier versions. ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "0" + # GCC < 4.3 WARNING_FLAGS += -Wconversion endif ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 8 \) \))" "1" + # GCC >= 4.8 # This flag is only known since GCC 4.3. Gcc 4.8 contains a fix so that with templates no # warnings are issued: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11856 WARNING_FLAGS += -Wtype-limits + # GCC < 4.8 don't accept this flag for C++. + WARNING_FLAGS += -Wno-format-zero-length endif endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/linux/makefiles/minimal1.make --- a/hotspot/make/linux/makefiles/minimal1.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/linux/makefiles/minimal1.make Thu Oct 22 11:13:08 2015 -0700 @@ -38,6 +38,7 @@ INCLUDE_NMT := false INCLUDE_TRACE := false INCLUDE_CDS := false +INCLUDE_JVMCI := false CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" CFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\" diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/solaris/makefiles/compiler1.make --- a/hotspot/make/solaris/makefiles/compiler1.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/solaris/makefiles/compiler1.make Thu Oct 22 11:13:08 2015 -0700 @@ -28,4 +28,7 @@ VM_SUBDIR = client +# We don't support the JVMCI in a client VM. +INCLUDE_JVMCI := false + CFLAGS += -DCOMPILER1 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/windows/build_vm_def.sh --- a/hotspot/make/windows/build_vm_def.sh Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/windows/build_vm_def.sh Thu Oct 22 11:13:08 2015 -0700 @@ -52,6 +52,7 @@ CAT="$MKS_HOME/cat.exe" RM="$MKS_HOME/rm.exe" DUMPBIN="link.exe /dump" +export VS_UNICODE_OUTPUT= if [ "$1" = "-nosa" ]; then echo EXPORTS > vm.def diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/windows/create_obj_files.sh --- a/hotspot/make/windows/create_obj_files.sh Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/windows/create_obj_files.sh Thu Oct 22 11:13:08 2015 -0700 @@ -111,6 +111,7 @@ COMPILER2_SPECIFIC_FILES="opto libadt bcEscapeAnalyzer.cpp c2_* runtime_*" COMPILER1_SPECIFIC_FILES="c1_*" +JVMCI_SPECIFIC_FILES="*jvmci* *JVMCI*" SHARK_SPECIFIC_FILES="shark" ZERO_SPECIFIC_FILES="zero" @@ -119,11 +120,11 @@ # Exclude per type. case "${TYPE}" in - "compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; + "compiler1") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; "compiler2") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; "tiered") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${ZERO_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES}" ;; - "zero") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; - "shark") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES}" ;; + "zero") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${SHARK_SPECIFIC_FILES} ciTypeFlow.cpp" ;; + "shark") Src_Files_EXCLUDE="${Src_Files_EXCLUDE} ${COMPILER1_SPECIFIC_FILES} ${COMPILER2_SPECIFIC_FILES} ${JVMCI_SPECIFIC_FILES} ${ZERO_SPECIFIC_FILES}" ;; esac # Special handling of arch model. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/windows/makefiles/compile.make --- a/hotspot/make/windows/makefiles/compile.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/windows/makefiles/compile.make Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ # /nologo Supress copyright message at every cl.exe startup # /W3 Warning level 3 # /Zi Include debugging information +# /d2Zi+ Extended debugging symbols for optimized code (/Zo in VS2013 Update 3 and later) # /WX Treat any warning error as a fatal error # /MD Use dynamic multi-threaded runtime (msvcrt.dll or msvc*NN.dll) # /MTd Use static multi-threaded runtime debug versions @@ -57,7 +58,7 @@ # Let's add debug information when Full Debug Symbols is enabled !if "$(ENABLE_FULL_DEBUG_SYMBOLS)" == "1" -CXX_FLAGS=$(CXX_FLAGS) /Zi +CXX_FLAGS=$(CXX_FLAGS) /Zi /d2Zi+ !endif # Based on BUILDARCH we add some flags and select the default compiler name diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/windows/makefiles/projectcreator.make --- a/hotspot/make/windows/makefiles/projectcreator.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/windows/makefiles/projectcreator.make Thu Oct 22 11:13:08 2015 -0700 @@ -145,6 +145,10 @@ -ignorePath_TARGET tiered \ -ignorePath_TARGET c1_ +ProjectCreatorIDEOptionsIgnoreJVMCI=\ + -ignorePath_TARGET src/share/vm/jvmci \ + -ignorePath_TARGET vm/jvmci + ProjectCreatorIDEOptionsIgnoreCompiler2=\ -ignorePath_TARGET compiler2 \ -ignorePath_TARGET tiered \ @@ -165,6 +169,8 @@ ################################################## ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \ -define_compiler1 COMPILER1 \ + -define_compiler1 INCLUDE_JVMCI=0 \ +$(ProjectCreatorIDEOptionsIgnoreJVMCI:TARGET=compiler1) \ $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=compiler1) ################################################## diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/make/windows/makefiles/vm.make --- a/hotspot/make/windows/makefiles/vm.make Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/make/windows/makefiles/vm.make Thu Oct 22 11:13:08 2015 -0700 @@ -40,7 +40,7 @@ !endif !if "$(Variant)" == "compiler1" -CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1" +CXX_FLAGS=$(CXX_FLAGS) /D "COMPILER1" /D INCLUDE_JVMCI=0 !endif !if "$(Variant)" == "compiler2" @@ -152,6 +152,7 @@ VM_PATH=$(VM_PATH);../generated/jvmtifiles VM_PATH=$(VM_PATH);../generated/tracefiles VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/c1 +VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/jvmci VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/compiler VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/code VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/interpreter @@ -163,6 +164,7 @@ VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/cms VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/g1 VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/asm +VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/logging VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/memory VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/oops VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/prims @@ -232,6 +234,9 @@ {$(COMMONSRC)\share\vm\classfile}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(COMMONSRC)\share\vm\jvmci}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(COMMONSRC)\share\vm\gc\parallel}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< @@ -250,6 +255,9 @@ {$(COMMONSRC)\share\vm\asm}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(COMMONSRC)\share\vm\logging}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(COMMONSRC)\share\vm\memory}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< @@ -330,6 +338,9 @@ {$(ALTSRC)\share\vm\asm}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< +{$(ALTSRC)\share\vm\logging}.cpp.obj:: + $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< + {$(ALTSRC)\share\vm\memory}.cpp.obj:: $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $< diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/aarch64.ad --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Thu Oct 22 11:13:08 2015 -0700 @@ -1039,6 +1039,7 @@ bool leading_membar(const MemBarNode *barrier); bool is_card_mark_membar(const MemBarNode *barrier); + bool is_CAS(int opcode); MemBarNode *leading_to_normal(MemBarNode *leading); MemBarNode *normal_to_leading(const MemBarNode *barrier); @@ -1057,6 +1058,9 @@ bool unnecessary_volatile(const Node *barrier); bool needs_releasing_store(const Node *store); + // predicate controlling translation of CompareAndSwapX + bool needs_acquiring_load_exclusive(const Node *load); + // predicate controlling translation of StoreCM bool unnecessary_storestore(const Node *storecm); %} @@ -1088,15 +1092,58 @@ // str // dmb ish // + // We can also use ldaxr and stlxr to implement compare and swap CAS + // sequences. These are normally translated to an instruction + // sequence like the following + // + // dmb ish + // retry: + // ldxr rval raddr + // cmp rval rold + // b.ne done + // stlxr rval, rnew, rold + // cbnz rval retry + // done: + // cset r0, eq + // dmb ishld + // + // Note that the exclusive store is already using an stlxr + // instruction. That is required to ensure visibility to other + // threads of the exclusive write (assuming it succeeds) before that + // of any subsequent writes. + // + // The following instruction sequence is an improvement on the above + // + // retry: + // ldaxr rval raddr + // cmp rval rold + // b.ne done + // stlxr rval, rnew, rold + // cbnz rval retry + // done: + // cset r0, eq + // + // We don't need the leading dmb ish since the stlxr guarantees + // visibility of prior writes in the case that the swap is + // successful. Crucially we don't have to worry about the case where + // the swap is not successful since no valid program should be + // relying on visibility of prior changes by the attempting thread + // in the case where the CAS fails. + // + // Similarly, we don't need the trailing dmb ishld if we substitute + // an ldaxr instruction since that will provide all the guarantees we + // require regarding observation of changes made by other threads + // before any change to the CAS address observed by the load. + // // In order to generate the desired instruction sequence we need to // be able to identify specific 'signature' ideal graph node // sequences which i) occur as a translation of a volatile reads or - // writes and ii) do not occur through any other translation or - // graph transformation. We can then provide alternative aldc - // matching rules which translate these node sequences to the - // desired machine code sequences. Selection of the alternative - // rules can be implemented by predicates which identify the - // relevant node sequences. + // writes or CAS operations and ii) do not occur through any other + // translation or graph transformation. We can then provide + // alternative aldc matching rules which translate these node + // sequences to the desired machine code sequences. Selection of the + // alternative rules can be implemented by predicates which identify + // the relevant node sequences. // // The ideal graph generator translates a volatile read to the node // sequence @@ -1163,6 +1210,15 @@ // get if it is fed and feeds a cpuorder membar and if its feed // membar also feeds an acquiring load. // + // Finally an inlined (Unsafe) CAS operation is translated to the + // following ideal graph + // + // MemBarRelease + // MemBarCPUOrder + // CompareAndSwapX {CardMark}-optional + // MemBarCPUOrder + // MemBarAcquire + // // So, where we can identify these volatile read and write // signatures we can choose to plant either of the above two code // sequences. For a volatile read we can simply plant a normal @@ -1177,6 +1233,14 @@ // and MemBarVolatile and instead plant a simple stlr // instruction. // + // when we recognise a CAS signature we can choose to plant a dmb + // ish as a translation for the MemBarRelease, the conventional + // macro-instruction sequence for the CompareAndSwap node (which + // uses ldxr) and then a dmb ishld for the MemBarAcquire. + // Alternatively, we can elide generation of the dmb instructions + // and plant the alternative CompareAndSwap macro-instruction + // sequence (which uses ldaxr). + // // Of course, the above only applies when we see these signature // configurations. We still want to plant dmb instructions in any // other cases where we may see a MemBarAcquire, MemBarRelease or @@ -1194,7 +1258,8 @@ // relevant dmb instructions. // - // graph traversal helpers used for volatile put/get optimization + // graph traversal helpers used for volatile put/get and CAS + // optimization // 1) general purpose helpers @@ -1220,16 +1285,19 @@ return NULL; } - if (!ctl || !mem || !ctl->is_Proj() || !mem->is_Proj()) + if (!ctl || !mem || !ctl->is_Proj() || !mem->is_Proj()) { return NULL; + } membar = ctl->lookup(0); - if (!membar || !membar->is_MemBar()) + if (!membar || !membar->is_MemBar()) { return NULL; - - if (mem->lookup(0) != membar) + } + + if (mem->lookup(0) != membar) { return NULL; + } return membar->as_MemBar(); } @@ -1259,8 +1327,9 @@ } } - if (child == NULL) + if (child == NULL) { return NULL; + } for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); @@ -1283,15 +1352,18 @@ { int opcode = barrier->Opcode(); // if this is a release membar we are ok - if (opcode == Op_MemBarRelease) + if (opcode == Op_MemBarRelease) { return true; + } // if its a cpuorder membar . . . - if (opcode != Op_MemBarCPUOrder) + if (opcode != Op_MemBarCPUOrder) { return false; + } // then the parent has to be a release membar MemBarNode *parent = parent_membar(barrier); - if (!parent) + if (!parent) { return false; + } opcode = parent->Opcode(); return opcode == Op_MemBarRelease; } @@ -1314,11 +1386,13 @@ bool is_card_mark_membar(const MemBarNode *barrier) { - if (!UseG1GC && !(UseConcMarkSweepGC && UseCondCardMark)) + if (!UseG1GC && !(UseConcMarkSweepGC && UseCondCardMark)) { return false; - - if (barrier->Opcode() != Op_MemBarVolatile) + } + + if (barrier->Opcode() != Op_MemBarVolatile) { return false; + } ProjNode *mem = barrier->proj_out(TypeFunc::Memory); @@ -1333,8 +1407,8 @@ } - // 3) helper predicates to traverse volatile put graphs which may - // contain GC barrier subgraphs + // 3) helper predicates to traverse volatile put or CAS graphs which + // may contain GC barrier subgraphs // Preamble // -------- @@ -1404,8 +1478,7 @@ // currently being unmarked in which case the volatile put graph // will look slightly different // - // MemBarRelease - // MemBarCPUOrder___________________________________________ + // MemBarRelease____________________________________________ // || \\ Ctl \ Ctl \ \\ Mem \ // || StoreN/P[mo_release] CastP2X If LoadB | // | \ / \ | @@ -1419,7 +1492,7 @@ // memory flow includes the following subgraph: // // MemBarRelease - // MemBarCPUOrder + // {MemBarCPUOrder} // | \ . . . // | StoreX[mo_release] . . . // | / @@ -1431,8 +1504,48 @@ // detected starting from any candidate MemBarRelease, // StoreX[mo_release] or MemBarVolatile. // + // A simple variation on this normal case occurs for an unsafe CAS + // operation. The basic graph for a non-object CAS is + // + // MemBarRelease + // || + // MemBarCPUOrder + // || \\ . . . + // || CompareAndSwapX + // || | + // || SCMemProj + // | \ / + // | MergeMem + // | / + // MemBarCPUOrder + // || + // MemBarAcquire + // + // The same basic variations on this arrangement (mutatis mutandis) + // occur when a card mark is introduced. i.e. we se the same basic + // shape but the StoreP/N is replaced with CompareAndSawpP/N and the + // tail of the graph is a pair comprising a MemBarCPUOrder + + // MemBarAcquire. + // + // So, in the case of a CAS the normal graph has the variant form + // + // MemBarRelease + // MemBarCPUOrder + // | \ . . . + // | CompareAndSwapX . . . + // | | + // | SCMemProj + // | / . . . + // MergeMem + // | + // MemBarCPUOrder + // MemBarAcquire + // + // This graph can also easily be detected starting from any + // candidate MemBarRelease, CompareAndSwapX or MemBarAcquire. + // // the code below uses two helper predicates, leading_to_normal and - // normal_to_leading to identify this configuration, one validating + // normal_to_leading to identify these normal graphs, one validating // the layout starting from the top membar and searching down and // the other validating the layout starting from the lower membar // and searching up. @@ -1450,7 +1563,9 @@ // they are only inserted for object puts. This significantly // complicates the task of identifying whether a MemBarRelease, // StoreX[mo_release] or MemBarVolatile forms part of a volatile put - // when using these GC configurations (see below). + // when using these GC configurations (see below). It adds similar + // complexity to the task of identifying whether a MemBarRelease, + // CompareAndSwapX or MemBarAcquire forms part of a CAS. // // In both cases the post-write subtree includes an auxiliary // MemBarVolatile (StoreLoad barrier) separating the object put and @@ -1489,7 +1604,8 @@ // (LoadB) from the card. Ctl and Mem are fed to the If via an // intervening StoreLoad barrier (MemBarVolatile). // - // So, with CMS we may see a node graph which looks like this + // So, with CMS we may see a node graph for a volatile object store + // which looks like this // // MemBarRelease // MemBarCPUOrder_(leading)__________________ @@ -1524,6 +1640,55 @@ // from the StoreCM into the trailing membar (n.b. the latter // proceeds via a Phi associated with the If region). // + // The graph for a CAS varies slightly, the obvious difference being + // that the StoreN/P node is replaced by a CompareAndSwapP/N node + // and the trailing MemBarVolatile by a MemBarCPUOrder + + // MemBarAcquire pair. The other important difference is that the + // CompareAndSwap node's SCMemProj is not merged into the card mark + // membar - it still feeds the trailing MergeMem. This also means + // that the card mark membar receives its Mem feed directly from the + // leading membar rather than via a MergeMem. + // + // MemBarRelease + // MemBarCPUOrder__(leading)_________________________ + // || \\ C \ + // MemBarVolatile (card mark) CompareAndSwapN/P CastP2X + // C | || M | | + // | LoadB | ______/| + // | | | / | + // | Cmp | / SCMemProj + // | / | / | + // If | / / + // | \ | / / + // IfFalse IfTrue | / / + // \ / \ |/ prec / + // \ / StoreCM / + // \ / | / + // Region . . . / + // | \ / + // | . . . \ / Bot + // | MergeMem + // | | + // MemBarCPUOrder + // MemBarAcquire (trailing) + // + // This has a slightly different memory subgraph to the one seen + // previously but the core of it is the same as for the CAS normal + // sungraph + // + // MemBarRelease + // MemBarCPUOrder____ + // || \ . . . + // MemBarVolatile CompareAndSwapX . . . + // | \ | + // . . . SCMemProj + // | / . . . + // MergeMem + // | + // MemBarCPUOrder + // MemBarAcquire + // + // // G1 is quite a lot more complicated. The nodes inserted on behalf // of G1 may comprise: a pre-write graph which adds the old value to // the SATB queue; the releasing store itself; and, finally, a @@ -1575,12 +1740,16 @@ // n.b. the LoadB in this subgraph is not the card read -- it's a // read of the SATB queue active flag. // + // Once again the CAS graph is a minor variant on the above with the + // expected substitutions of CompareAndSawpX for StoreN/P and + // MemBarCPUOrder + MemBarAcquire for trailing MemBarVolatile. + // // The G1 post-write subtree is also optional, this time when the // new value being written is either null or can be identified as a // newly allocated (young gen) object with no intervening control // flow. The latter cannot happen but the former may, in which case - // the card mark membar is omitted and the memory feeds from the - // leading membar and the StoreN/P are merged direct into the + // the card mark membar is omitted and the memory feeds form the + // leading membar and the SToreN/P are merged direct into the // trailing membar as per the normal subgraph. So, the only special // case which arises is when the post-write subgraph is generated. // @@ -1668,47 +1837,84 @@ // value check has been elided the total number of Phis is 2 // otherwise it is 3. // + // The CAS graph when using G1GC also includes a pre-write subgraph + // and an optional post-write subgraph. Teh sam evarioations are + // introduced as for CMS with conditional card marking i.e. the + // StoreP/N is swapped for a CompareAndSwapP/N, the tariling + // MemBarVolatile for a MemBarCPUOrder + MemBarAcquire pair and the + // Mem feed from the CompareAndSwapP/N includes a precedence + // dependency feed to the StoreCM and a feed via an SCMemProj to the + // trailing membar. So, as before the configuration includes the + // normal CAS graph as a subgraph of the memory flow. + // // So, the upshot is that in all cases the volatile put graph will // include a *normal* memory subgraph betwen the leading membar and - // its child membar. When that child is not a card mark membar then - // it marks the end of a volatile put subgraph. If the child is a - // card mark membar then the normal subgraph will form part of a - // volatile put subgraph if and only if the child feeds an - // AliasIdxBot Mem feed to a trailing barrier via a MergeMem. That - // feed is either direct (for CMS) or via 2 or 3 Phi nodes merging - // the leading barrier memory flow (for G1). + // its child membar, either a volatile put graph (including a + // releasing StoreX) or a CAS graph (including a CompareAndSwapX). + // When that child is not a card mark membar then it marks the end + // of the volatile put or CAS subgraph. If the child is a card mark + // membar then the normal subgraph will form part of a volatile put + // subgraph if and only if the child feeds an AliasIdxBot Mem feed + // to a trailing barrier via a MergeMem. That feed is either direct + // (for CMS) or via 2 or 3 Phi nodes merging the leading barrier + // memory flow (for G1). // // The predicates controlling generation of instructions for store // and barrier nodes employ a few simple helper functions (described - // below) which identify the presence or absence of these subgraph - // configurations and provide a means of traversing from one node in - // the subgraph to another. + // below) which identify the presence or absence of all these + // subgraph configurations and provide a means of traversing from + // one node in the subgraph to another. + + // is_CAS(int opcode) + // + // return true if opcode is one of the possible CompareAndSwapX + // values otherwise false. + + bool is_CAS(int opcode) + { + return (opcode == Op_CompareAndSwapI || + opcode == Op_CompareAndSwapL || + opcode == Op_CompareAndSwapN || + opcode == Op_CompareAndSwapP); + } // leading_to_normal // - //graph traversal helper which detects the normal case Mem feed - // from a release membar (or, optionally, its cpuorder child) to a - // dependent volatile membar i.e. it ensures that the following Mem - // flow subgraph is present. + //graph traversal helper which detects the normal case Mem feed from + // a release membar (or, optionally, its cpuorder child) to a + // dependent volatile membar i.e. it ensures that one or other of + // the following Mem flow subgraph is present. // // MemBarRelease - // MemBarCPUOrder + // MemBarCPUOrder {leading} // | \ . . . // | StoreN/P[mo_release] . . . // | / // MergeMem // | - // MemBarVolatile - // - // if the correct configuration is present returns the volatile + // MemBarVolatile {trailing or card mark} + // + // MemBarRelease + // MemBarCPUOrder {leading} + // | \ . . . + // | CompareAndSwapX . . . + // | + // . . . SCMemProj + // \ | + // | MergeMem + // | / + // MemBarCPUOrder + // MemBarAcquire {trailing} + // + // if the correct configuration is present returns the trailing // membar otherwise NULL. // // the input membar is expected to be either a cpuorder membar or a // release membar. in the latter case it should not have a cpu membar // child. // - // the returned membar may be a card mark membar rather than a - // trailing membar. + // the returned value may be a card mark or trailing membar + // MemBarNode *leading_to_normal(MemBarNode *leading) { @@ -1719,54 +1925,103 @@ // check the mem flow ProjNode *mem = leading->proj_out(TypeFunc::Memory); - if (!mem) + if (!mem) { return NULL; + } Node *x = NULL; StoreNode * st = NULL; + LoadStoreNode *cas = NULL; MergeMemNode *mm = NULL; for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); if (x->is_MergeMem()) { - if (mm != NULL) + if (mm != NULL) { return NULL; + } // two merge mems is one too many mm = x->as_MergeMem(); } else if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) { - // two releasing stores is one too many - if (st != NULL) + // two releasing stores/CAS nodes is one too many + if (st != NULL || cas != NULL) { + return NULL; + } + st = x->as_Store(); + } else if (is_CAS(x->Opcode())) { + if (st != NULL || cas != NULL) { return NULL; - st = x->as_Store(); + } + cas = x->as_LoadStore(); + } + } + + // must have a store or a cas + if (!st && !cas) { + return NULL; + } + + // must have a merge if we also have st + if (st && !mm) { + return NULL; + } + + Node *y = NULL; + if (cas) { + // look for an SCMemProj + for (DUIterator_Fast imax, i = cas->fast_outs(imax); i < imax; i++) { + x = cas->fast_out(i); + if (x->is_Proj()) { + y = x; + break; + } + } + if (y == NULL) { + return NULL; } - } - - if (!mm || !st) - return NULL; - - bool found = false; - // ensure the store feeds the merge - for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { - if (st->fast_out(i) == mm) { - found = true; + // the proj must feed a MergeMem + for (DUIterator_Fast imax, i = y->fast_outs(imax); i < imax; i++) { + x = y->fast_out(i); + if (x->is_MergeMem()) { + mm = x->as_MergeMem(); + break; + } + } + if (mm == NULL) + return NULL; + } else { + // ensure the store feeds the existing mergemem; + for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { + if (st->fast_out(i) == mm) { + y = st; + break; + } + } + if (y == NULL) { + return NULL; + } + } + + MemBarNode *mbar = NULL; + // ensure the merge feeds to the expected type of membar + for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { + x = mm->fast_out(i); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarVolatile && st) { + mbar = x->as_MemBar(); + } else if (cas && opcode == Op_MemBarCPUOrder) { + MemBarNode *y = x->as_MemBar(); + y = child_membar(y); + if (y != NULL && y->Opcode() == Op_MemBarAcquire) { + mbar = y; + } + } break; } } - if (!found) - return NULL; - - MemBarNode *mbvol = NULL; - // ensure the merge feeds a volatile membar - for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { - x = mm->fast_out(i); - if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) { - mbvol = x->as_MemBar(); - break; - } - } - - return mbvol; + return mbar; } // normal_to_leading @@ -1774,7 +2029,7 @@ // graph traversal helper which detects the normal case Mem feed // from either a card mark or a trailing membar to a preceding // release membar (optionally its cpuorder child) i.e. it ensures - // that the following Mem flow subgraph is present. + // that one or other of the following Mem flow subgraphs is present. // // MemBarRelease // MemBarCPUOrder {leading} @@ -1783,7 +2038,19 @@ // | / // MergeMem // | - // MemBarVolatile + // MemBarVolatile {card mark or trailing} + // + // MemBarRelease + // MemBarCPUOrder {leading} + // | \ . . . + // | CompareAndSwapX . . . + // | + // . . . SCMemProj + // \ | + // | MergeMem + // | / + // MemBarCPUOrder + // MemBarAcquire {trailing} // // this predicate checks for the same flow as the previous predicate // but starting from the bottom rather than the top. @@ -1797,51 +2064,116 @@ MemBarNode *normal_to_leading(const MemBarNode *barrier) { // input must be a volatile membar - assert(barrier->Opcode() == Op_MemBarVolatile, "expecting a volatile membar"); + assert((barrier->Opcode() == Op_MemBarVolatile || + barrier->Opcode() == Op_MemBarAcquire), + "expecting a volatile or an acquire membar"); Node *x; + bool is_cas = barrier->Opcode() == Op_MemBarAcquire; + + // if we have an acquire membar then it must be fed via a CPUOrder + // membar + + if (is_cas) { + // skip to parent barrier which must be a cpuorder + x = parent_membar(barrier); + if (x->Opcode() != Op_MemBarCPUOrder) + return NULL; + } else { + // start from the supplied barrier + x = (Node *)barrier; + } // the Mem feed to the membar should be a merge - x = barrier->in(TypeFunc::Memory); + x = x ->in(TypeFunc::Memory); if (!x->is_MergeMem()) return NULL; MergeMemNode *mm = x->as_MergeMem(); - // the AliasIdxBot slice should be another MemBar projection - x = mm->in(Compile::AliasIdxBot); + if (is_cas) { + // the merge should be fed from the CAS via an SCMemProj node + x = NULL; + for (uint idx = 1; idx < mm->req(); idx++) { + if (mm->in(idx)->Opcode() == Op_SCMemProj) { + x = mm->in(idx); + break; + } + } + if (x == NULL) { + return NULL; + } + // check for a CAS feeding this proj + x = x->in(0); + int opcode = x->Opcode(); + if (!is_CAS(opcode)) { + return NULL; + } + // the CAS should get its mem feed from the leading membar + x = x->in(MemNode::Memory); + } else { + // the merge should get its Bottom mem feed from the leading membar + x = mm->in(Compile::AliasIdxBot); + } + // ensure this is a non control projection - if (!x->is_Proj() || x->is_CFG()) + if (!x->is_Proj() || x->is_CFG()) { return NULL; + } // if it is fed by a membar that's the one we want x = x->in(0); - if (!x->is_MemBar()) + if (!x->is_MemBar()) { return NULL; + } MemBarNode *leading = x->as_MemBar(); // reject invalid candidates - if (!leading_membar(leading)) + if (!leading_membar(leading)) { return NULL; - - // ok, we have a leading ReleaseMembar, now for the sanity clauses - - // the leading membar must feed Mem to a releasing store + } + + // ok, we have a leading membar, now for the sanity clauses + + // the leading membar must feed Mem to a releasing store or CAS ProjNode *mem = leading->proj_out(TypeFunc::Memory); StoreNode *st = NULL; + LoadStoreNode *cas = NULL; for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) { + // two stores or CASes is one too many + if (st != NULL || cas != NULL) { + return NULL; + } st = x->as_Store(); - break; + } else if (is_CAS(x->Opcode())) { + if (st != NULL || cas != NULL) { + return NULL; + } + cas = x->as_LoadStore(); } } - if (st == NULL) + + // we should not have both a store and a cas + if (st == NULL & cas == NULL) { return NULL; - - // the releasing store has to feed the same merge - for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { - if (st->fast_out(i) == mm) - return leading; + } + + if (st == NULL) { + // nothing more to check + return leading; + } else { + // we should not have a store if we started from an acquire + if (is_cas) { + return NULL; + } + + // the store should feed the merge we used to get here + for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { + if (st->fast_out(i) == mm) { + return leading; + } + } } return NULL; @@ -1865,8 +2197,8 @@ // Bot | / // MergeMem // | - // MemBarVolatile (trailing) - // + // | + // MemBarVolatile {trailing} // // 2) // MemBarRelease/CPUOrder (leading) @@ -1884,7 +2216,8 @@ // Bot | / // MergeMem // | - // MemBarVolatile (trailing) + // MemBarVolatile {trailing} + // // // 3) // MemBarRelease/CPUOrder (leading) @@ -1905,7 +2238,8 @@ // Bot | / // MergeMem // | - // MemBarVolatile (trailing) + // | + // MemBarVolatile {trailing} // // configuration 1 is only valid if UseConcMarkSweepGC && // UseCondCardMark @@ -1955,8 +2289,9 @@ break; } } - if (!phi) + if (!phi) { return NULL; + } // look for another merge below this phi feed = phi; } else { @@ -1969,7 +2304,7 @@ assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge"); MemBarNode *trailing = NULL; - // be sure we have a volatile membar below the merge + // be sure we have a trailing membar the merge for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { x = mm->fast_out(i); if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) { @@ -1984,24 +2319,32 @@ // trailing_to_card_mark // // graph traversal helper which detects extra, non-normal Mem feed - // from a trailing membar to a preceding card mark volatile membar - // i.e. it identifies whether one of the three possible extra GC - // post-write Mem flow subgraphs is present + // from a trailing volatile membar to a preceding card mark volatile + // membar i.e. it identifies whether one of the three possible extra + // GC post-write Mem flow subgraphs is present // // this predicate checks for the same flow as the previous predicate // but starting from the bottom rather than the top. // - // if the configurationis present returns the card mark membar + // if the configuration is present returns the card mark membar // otherwise NULL + // + // n.b. the supplied membar is expected to be a trailing + // MemBarVolatile i.e. the caller must ensure the input node has the + // correct opcode MemBarNode *trailing_to_card_mark(const MemBarNode *trailing) { - assert(!is_card_mark_membar(trailing), "not expecting a card mark membar"); - + assert(trailing->Opcode() == Op_MemBarVolatile, + "expecting a volatile membar"); + assert(!is_card_mark_membar(trailing), + "not expecting a card mark membar"); + + // the Mem feed to the membar should be a merge Node *x = trailing->in(TypeFunc::Memory); - // the Mem feed to the membar should be a merge - if (!x->is_MergeMem()) + if (!x->is_MergeMem()) { return NULL; + } MergeMemNode *mm = x->as_MergeMem(); @@ -2054,13 +2397,15 @@ } // the proj has to come from the card mark membar x = x->in(0); - if (!x->is_MemBar()) + if (!x->is_MemBar()) { return NULL; + } MemBarNode *card_mark_membar = x->as_MemBar(); - if (!is_card_mark_membar(card_mark_membar)) + if (!is_card_mark_membar(card_mark_membar)) { return NULL; + } return card_mark_membar; } @@ -2068,7 +2413,7 @@ // trailing_to_leading // // graph traversal helper which checks the Mem flow up the graph - // from a (non-card mark) volatile membar attempting to locate and + // from a (non-card mark) trailing membar attempting to locate and // return an associated leading membar. it first looks for a // subgraph in the normal configuration (relying on helper // normal_to_leading). failing that it then looks for one of the @@ -2081,22 +2426,35 @@ // if the configuration is valid returns the cpuorder member for // preference or when absent the release membar otherwise NULL. // - // n.b. the input membar is expected to be a volatile membar but - // must *not* be a card mark membar. + // n.b. the input membar is expected to be either a volatile or + // acquire membar but in the former case must *not* be a card mark + // membar. MemBarNode *trailing_to_leading(const MemBarNode *trailing) { - assert(!is_card_mark_membar(trailing), "not expecting a card mark membar"); + assert((trailing->Opcode() == Op_MemBarAcquire || + trailing->Opcode() == Op_MemBarVolatile), + "expecting an acquire or volatile membar"); + assert((trailing->Opcode() != Op_MemBarVolatile || + !is_card_mark_membar(trailing)), + "not expecting a card mark membar"); MemBarNode *leading = normal_to_leading(trailing); - if (leading) + if (leading) { return leading; + } + + // nothing more to do if this is an acquire + if (trailing->Opcode() == Op_MemBarAcquire) { + return NULL; + } MemBarNode *card_mark_membar = trailing_to_card_mark(trailing); - if (!card_mark_membar) + if (!card_mark_membar) { return NULL; + } return normal_to_leading(card_mark_membar); } @@ -2105,10 +2463,12 @@ bool unnecessary_acquire(const Node *barrier) { - // assert barrier->is_MemBar(); - if (UseBarriersForVolatile) + assert(barrier->is_MemBar(), "expecting a membar"); + + if (UseBarriersForVolatile) { // we need to plant a dmb return false; + } // a volatile read derived from bytecode (or also from an inlined // SHA field read via LibraryCallKit::load_field_from_object) @@ -2140,8 +2500,9 @@ // // where * tags node we were passed // and |k means input k - if (x->is_DecodeNarrowPtr()) + if (x->is_DecodeNarrowPtr()) { x = x->in(1); + } return (x->is_Load() && x->as_Load()->is_acquire()); } @@ -2167,8 +2528,9 @@ return false; ctl = parent->proj_out(TypeFunc::Control); mem = parent->proj_out(TypeFunc::Memory); - if (!ctl || !mem) + if (!ctl || !mem) { return false; + } // ensure the proj nodes both feed a LoadX[mo_acquire] LoadNode *ld = NULL; for (DUIterator_Fast imax, i = ctl->fast_outs(imax); i < imax; i++) { @@ -2180,38 +2542,46 @@ } } // it must be an acquiring load - if (! ld || ! ld->is_acquire()) - return false; - for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { - x = mem->fast_out(i); - // if we see the same load we drop it and stop searching - if (x == ld) { - ld = NULL; - break; - } - } - // we must have dropped the load - if (ld) - return false; - // check for a child cpuorder membar - MemBarNode *child = child_membar(barrier->as_MemBar()); - if (!child || child->Opcode() != Op_MemBarCPUOrder) - return false; - - return true; + if (ld && ld->is_acquire()) { + + for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { + x = mem->fast_out(i); + // if we see the same load we drop it and stop searching + if (x == ld) { + ld = NULL; + break; + } + } + // we must have dropped the load + if (ld == NULL) { + // check for a child cpuorder membar + MemBarNode *child = child_membar(barrier->as_MemBar()); + if (child && child->Opcode() == Op_MemBarCPUOrder) + return true; + } + } + + // final option for unnecessary mebar is that it is a trailing node + // belonging to a CAS + + MemBarNode *leading = trailing_to_leading(barrier->as_MemBar()); + + return leading != NULL; } bool needs_acquiring_load(const Node *n) { - // assert n->is_Load(); - if (UseBarriersForVolatile) + assert(n->is_Load(), "expecting a load"); + if (UseBarriersForVolatile) { // we use a normal load and a dmb return false; + } LoadNode *ld = n->as_Load(); - if (!ld->is_acquire()) + if (!ld->is_acquire()) { return false; + } // check if this load is feeding an acquire membar // @@ -2261,20 +2631,23 @@ membar = parent_membar(ld); - if (!membar || !membar->Opcode() == Op_MemBarCPUOrder) + if (!membar || !membar->Opcode() == Op_MemBarCPUOrder) { return false; + } // ensure that there is a CPUOrder->Acquire->CPUOrder membar chain membar = child_membar(membar); - if (!membar || !membar->Opcode() == Op_MemBarAcquire) + if (!membar || !membar->Opcode() == Op_MemBarAcquire) { return false; + } membar = child_membar(membar); - if (!membar || !membar->Opcode() == Op_MemBarCPUOrder) + if (!membar || !membar->Opcode() == Op_MemBarCPUOrder) { return false; + } return true; } @@ -2285,9 +2658,10 @@ n->Opcode() == Op_MemBarRelease), "expecting a release membar"); - if (UseBarriersForVolatile) + if (UseBarriersForVolatile) { // we need to plant a dmb return false; + } // if there is a dependent CPUOrder barrier then use that as the // leading @@ -2303,12 +2677,14 @@ // must start with a normal feed MemBarNode *child_barrier = leading_to_normal(barrier); - if (!child_barrier) + if (!child_barrier) { return false; - - if (!is_card_mark_membar(child_barrier)) + } + + if (!is_card_mark_membar(child_barrier)) { // this is the trailing membar and we are done return true; + } // must be sure this card mark feeds a trailing membar MemBarNode *trailing = card_mark_to_trailing(child_barrier); @@ -2318,17 +2694,19 @@ bool unnecessary_volatile(const Node *n) { // assert n->is_MemBar(); - if (UseBarriersForVolatile) + if (UseBarriersForVolatile) { // we need to plant a dmb return false; + } MemBarNode *mbvol = n->as_MemBar(); // first we check if this is part of a card mark. if so then we have // to generate a StoreLoad barrier - if (is_card_mark_membar(mbvol)) + if (is_card_mark_membar(mbvol)) { return false; + } // ok, if it's not a card mark then we still need to check if it is // a trailing membar of a volatile put hgraph. @@ -2341,29 +2719,33 @@ bool needs_releasing_store(const Node *n) { // assert n->is_Store(); - if (UseBarriersForVolatile) + if (UseBarriersForVolatile) { // we use a normal store and dmb combination return false; + } StoreNode *st = n->as_Store(); // the store must be marked as releasing - if (!st->is_release()) + if (!st->is_release()) { return false; + } // the store must be fed by a membar Node *x = st->lookup(StoreNode::Memory); - if (! x || !x->is_Proj()) + if (! x || !x->is_Proj()) { return false; + } ProjNode *proj = x->as_Proj(); x = proj->lookup(0); - if (!x || !x->is_MemBar()) + if (!x || !x->is_MemBar()) { return false; + } MemBarNode *barrier = x->as_MemBar(); @@ -2372,24 +2754,76 @@ // volatile put graph. // reject invalid candidates - if (!leading_membar(barrier)) + if (!leading_membar(barrier)) { return false; + } // does this lead a normal subgraph? MemBarNode *mbvol = leading_to_normal(barrier); - if (!mbvol) + if (!mbvol) { return false; + } // all done unless this is a card mark - if (!is_card_mark_membar(mbvol)) + if (!is_card_mark_membar(mbvol)) { return true; + } // we found a card mark -- just make sure we have a trailing barrier return (card_mark_to_trailing(mbvol) != NULL); } +// predicate controlling translation of CAS +// +// returns true if CAS needs to use an acquiring load otherwise false + +bool needs_acquiring_load_exclusive(const Node *n) +{ + assert(is_CAS(n->Opcode()), "expecting a compare and swap"); + if (UseBarriersForVolatile) { + return false; + } + + // CAS nodes only ought to turn up in inlined unsafe CAS operations +#ifdef ASSERT + LoadStoreNode *st = n->as_LoadStore(); + + // the store must be fed by a membar + + Node *x = st->lookup(StoreNode::Memory); + + assert (x && x->is_Proj(), "CAS not fed by memory proj!"); + + ProjNode *proj = x->as_Proj(); + + x = proj->lookup(0); + + assert (x && x->is_MemBar(), "CAS not fed by membar!"); + + MemBarNode *barrier = x->as_MemBar(); + + // the barrier must be a cpuorder mmebar fed by a release membar + + assert(barrier->Opcode() == Op_MemBarCPUOrder, + "CAS not fed by cpuorder membar!"); + + MemBarNode *b = parent_membar(barrier); + assert ((b != NULL && b->Opcode() == Op_MemBarRelease), + "CAS not fed by cpuorder+release membar pair!"); + + // does this lead a normal subgraph? + MemBarNode *mbar = leading_to_normal(barrier); + + assert(mbar != NULL, "CAS not embedded in normal graph!"); + + assert(mbar->Opcode() == Op_MemBarAcquire, "trailing membar should be an acquire"); +#endif // ASSERT + // so we can just return true here + return true; +} + // predicate controlling translation of StoreCM // // returns true if a StoreStore must precede the card write otherwise @@ -2403,14 +2837,16 @@ // and the associated card mark when we are using CMS without // conditional card marking - if (!UseConcMarkSweepGC || UseCondCardMark) + if (!UseConcMarkSweepGC || UseCondCardMark) { return true; + } // if we are implementing volatile puts using barriers then the // object put as an str so we must insert the dmb ishst - if (UseBarriersForVolatile) + if (UseBarriersForVolatile) { return false; + } // we can omit the dmb ishst if this StoreCM is part of a volatile // put because in thta case the put will be implemented by stlr @@ -2422,19 +2858,22 @@ Node *x = storecm->in(StoreNode::Memory); - if (!x->is_Proj()) + if (!x->is_Proj()) { return false; + } x = x->in(0); - if (!x->is_MemBar()) + if (!x->is_MemBar()) { return false; + } MemBarNode *leading = x->as_MemBar(); // reject invalid candidates - if (!leading_membar(leading)) + if (!leading_membar(leading)) { return false; + } // we can omit the StoreStore if it is the head of a normal subgraph return (leading_to_normal(leading) != NULL); @@ -3024,6 +3463,10 @@ return true; // Per default match rules are supported. } +const int Matcher::float_pressure(int default_pressure_threshold) { + return default_pressure_threshold; +} + int Matcher::regnum_to_fpu_offset(int regnum) { Unimplemented(); @@ -8365,9 +8808,13 @@ // XXX No flag versions for CompareAndSwap{I,L,P,N} because matcher // can't match them +// standard CompareAndSwapX when we are using barriers +// these have higher priority than the rules selected by a predicate + instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapI mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8385,6 +8832,7 @@ instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapL mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8402,6 +8850,7 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapP mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8419,6 +8868,7 @@ instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapN mem (Binary oldval newval))); + ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8433,6 +8883,84 @@ ins_pipe(pipe_slow); %} +// alternative CompareAndSwapX when we are eliding barriers + +instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) %{ + + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapI mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchgw_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) %{ + + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapL mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchg_acq(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ + + predicate(needs_acquiring_load_exclusive(n)); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + ins_cost(VOLATILE_REF_COST); + + effect(KILL cr); + + format %{ + "cmpxchgw_acq $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval" + "cset $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode(aarch64_enc_cmpxchgw_acq(mem, oldval, newval), + aarch64_enc_cset_eq(res)); + + ins_pipe(pipe_slow); +%} + instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{ match(Set prev (GetAndSetI mem newv)); @@ -13286,6 +13814,25 @@ ins_pipe(pipe_cmp_branch); %} +instruct cmpP_narrowOop_imm0_branch(cmpOp cmp, iRegN oop, immP0 zero, label labl, rFlagsReg cr) %{ + match(If cmp (CmpP (DecodeN oop) zero)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cb$cmp $oop, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + if (cond == Assembler::EQ) + __ cbzw($oop$$Register, *L); + else + __ cbnzw($oop$$Register, *L); + %} + ins_pipe(pipe_cmp_branch); +%} + // Conditional Far Branch // Conditional Far Branch Unsigned // TODO: fixme @@ -14662,6 +15209,102 @@ ins_pipe(pipe_class_default); %} +// --------------------------------- SQRT ------------------------------------- + +instruct vsqrt2D(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (SqrtVD src)); + format %{ "fsqrt $dst, $src\t# vector (2D)" %} + ins_encode %{ + __ fsqrt(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +// --------------------------------- ABS -------------------------------------- + +instruct vabs2F(vecD dst, vecD src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AbsVF src)); + ins_cost(INSN_COST * 3); + format %{ "fabs $dst,$src\t# vector (2S)" %} + ins_encode %{ + __ fabs(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vabs4F(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (AbsVF src)); + ins_cost(INSN_COST * 3); + format %{ "fabs $dst,$src\t# vector (4S)" %} + ins_encode %{ + __ fabs(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vabs2D(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AbsVD src)); + ins_cost(INSN_COST * 3); + format %{ "fabs $dst,$src\t# vector (2D)" %} + ins_encode %{ + __ fabs(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +// --------------------------------- NEG -------------------------------------- + +instruct vneg2F(vecD dst, vecD src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (NegVF src)); + ins_cost(INSN_COST * 3); + format %{ "fneg $dst,$src\t# vector (2S)" %} + ins_encode %{ + __ fneg(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vneg4F(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (NegVF src)); + ins_cost(INSN_COST * 3); + format %{ "fneg $dst,$src\t# vector (4S)" %} + ins_encode %{ + __ fneg(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vneg2D(vecX dst, vecX src) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (NegVD src)); + ins_cost(INSN_COST * 3); + format %{ "fneg $dst,$src\t# vector (2D)" %} + ins_encode %{ + __ fneg(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg)); + %} + ins_pipe(pipe_class_default); +%} + // --------------------------------- AND -------------------------------------- instruct vand8B(vecD dst, vecD src1, vecD src2) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -2311,6 +2311,12 @@ #define MSG "invalid arrangement" +#define ASSERTION (T == T2S || T == T4S || T == T2D) + INSN(fsqrt, 1, 0b11111); + INSN(fabs, 0, 0b01111); + INSN(fneg, 1, 0b01111); +#undef ASSERTION + #define ASSERTION (T == T8B || T == T16B || T == T4H || T == T8H || T == T2S || T == T4S) INSN(rev64, 0, 0b00000); #undef ASSERTION diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/c2_globals_aarch64.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -68,10 +68,11 @@ // Peephole and CISC spilling both break the graph, and so makes the // scheduler sick. -define_pd_global(bool, OptoPeephole, true); +define_pd_global(bool, OptoPeephole, false); define_pd_global(bool, UseCISCSpill, true); define_pd_global(bool, OptoScheduling, false); define_pd_global(bool, OptoBundling, false); +define_pd_global(bool, OptoRegScheduling, false); define_pd_global(intx, ReservedCodeCacheSize, 48*M); define_pd_global(intx, NonProfiledCodeHeapSize, 21*M); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/compiledIC_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -51,13 +51,15 @@ // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from // calling compiled code to calling interpreted code. // mov rmethod, 0 // jmp -4 # to self - address mark = cbuf.insts_mark(); // Get mark within main instrs section. + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } // 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. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/cppInterpreterGenerator_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/cppInterpreterGenerator_aarch64.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/cppInterpreterGenerator_aarch64.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,5 +30,6 @@ void generate_more_monitors(); void generate_deopt_handling(); + void lock_method(void); #endif // CPU_AARCH64_VM_CPPINTERPRETERGENERATOR_AARCH64_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -42,6 +42,11 @@ // Implementation of InterpreterMacroAssembler +void InterpreterMacroAssembler::jump_to_entry(address entry) { + assert(entry, "Entry must have been generated by now"); + b(entry); +} + #ifndef CC_INTERP void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { @@ -1542,14 +1547,14 @@ if (MethodData::profile_arguments()) { Label done; int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); - add(mdp, mdp, off_to_args); for (int i = 0; i < TypeProfileArgsLimit; i++) { if (i > 0 || MethodData::profile_return()) { // If return value type is profiled we may have no argument to profile - ldr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); + ldr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset()))); sub(tmp, tmp, i*TypeStackSlotEntries::per_arg_count()); cmp(tmp, TypeStackSlotEntries::per_arg_count()); + add(rscratch1, mdp, off_to_args); br(Assembler::LT, done); } ldr(tmp, Address(callee, Method::const_offset())); @@ -1557,26 +1562,27 @@ // stack offset o (zero based) from the start of the argument // list, for n arguments translates into offset n - o - 1 from // the end of the argument list - ldr(rscratch1, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args)); + ldr(rscratch1, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i)))); sub(tmp, tmp, rscratch1); sub(tmp, tmp, 1); Address arg_addr = argument_address(tmp); ldr(tmp, arg_addr); - Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); + Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))); profile_obj_type(tmp, mdo_arg_addr); int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); - add(mdp, mdp, to_add); off_to_args += to_add; } if (MethodData::profile_return()) { - ldr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); + ldr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset()))); sub(tmp, tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count()); } + add(rscratch1, mdp, off_to_args); bind(done); + mov(mdp, rscratch1); if (MethodData::profile_return()) { // We're right after the type profile for the last diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -66,6 +66,8 @@ void load_earlyret_value(TosState state); + void jump_to_entry(address entry); + #ifdef CC_INTERP void save_bcp() { /* not needed in c++ interpreter and harmless */ } void restore_bcp() { /* not needed in c++ interpreter and harmless */ } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/interpreterGenerator_aarch64.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,14 +41,13 @@ address generate_native_entry(bool synchronized); address generate_abstract_entry(void); address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_jump_to_normal_entry(void); - address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } - address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } + address generate_accessor_entry(void) { return NULL; } + address generate_empty_entry(void) { return NULL; } void generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs); address generate_Reference_get_entry(); address generate_CRC32_update_entry(); address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); - void lock_method(void); + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } void generate_stack_overflow_check(void); void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -236,17 +236,6 @@ __ blrt(rscratch1, gpargs, fpargs, rtype); } -// Jump into normal path for accessor and empty entry to jump to normal entry -// The "fast" optimization don't update compilation count therefore can disable inlining -// for these functions that should be inlined. -address InterpreterGenerator::generate_jump_to_normal_entry(void) { - address entry_point = __ pc(); - - assert(Interpreter::entry_for_kind(Interpreter::zerolocals) != NULL, "should already be generated"); - __ b(Interpreter::entry_for_kind(Interpreter::zerolocals)); - return entry_point; -} - // Abstract method entry // Attempt to execute abstract method. Throw exception address InterpreterGenerator::generate_abstract_entry(void) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_aarch64.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + Unimplemented(); + return 0; +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + Unimplemented(); +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + Unimplemented(); +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + return NULL; +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return false; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1709,6 +1709,20 @@ return idivq_offset; } +void MacroAssembler::membar(Membar_mask_bits order_constraint) { + address prev = pc() - NativeMembar::instruction_size; + if (prev == code()->last_membar()) { + NativeMembar *bar = NativeMembar_at(prev); + // We are merging two memory barrier instructions. On AArch64 we + // can do this simply by ORing them together. + bar->set_kind(bar->get_kind() | order_constraint); + BLOCK_COMMENT("merged membar"); + } else { + code()->set_last_membar(pc()); + dmb(Assembler::barrier(order_constraint)); + } +} + // MacroAssembler routines found actually to be needed void MacroAssembler::push(Register src) @@ -2238,7 +2252,7 @@ ttyLocker ttyl; ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); - assert(false, err_msg("DEBUG MESSAGE: %s", msg)); + assert(false, "DEBUG MESSAGE: %s", msg); } } @@ -2286,18 +2300,30 @@ } #endif -void MacroAssembler::push_CPU_state() { - push(0x3fffffff, sp); // integer registers except lr & sp - +void MacroAssembler::push_CPU_state(bool save_vectors) { + push(0x3fffffff, sp); // integer registers except lr & sp + + if (!save_vectors) { for (int i = 30; i >= 0; i -= 2) stpd(as_FloatRegister(i), as_FloatRegister(i+1), Address(pre(sp, -2 * wordSize))); + } else { + for (int i = 30; i >= 0; i -= 2) + stpq(as_FloatRegister(i), as_FloatRegister(i+1), + Address(pre(sp, -4 * wordSize))); + } } -void MacroAssembler::pop_CPU_state() { - for (int i = 0; i < 32; i += 2) - ldpd(as_FloatRegister(i), as_FloatRegister(i+1), - Address(post(sp, 2 * wordSize))); +void MacroAssembler::pop_CPU_state(bool restore_vectors) { + if (!restore_vectors) { + for (int i = 0; i < 32; i += 2) + ldpd(as_FloatRegister(i), as_FloatRegister(i+1), + Address(post(sp, 2 * wordSize))); + } else { + for (int i = 0; i < 32; i += 2) + ldpq(as_FloatRegister(i), as_FloatRegister(i+1), + Address(post(sp, 4 * wordSize))); + } pop(0x3fffffff, sp); // integer registers except lr & sp } @@ -3027,6 +3053,24 @@ _masm->bind(_label); } +void MacroAssembler::addptr(const Address &dst, int32_t src) { + Address adr; + switch(dst.getMode()) { + case Address::base_plus_offset: + // This is the expected mode, although we allow all the other + // forms below. + adr = form_address(rscratch2, dst.base(), dst.offset(), LogBytesPerWord); + break; + default: + lea(rscratch2, dst); + adr = Address(rscratch2); + break; + } + ldr(rscratch1, adr); + add(rscratch1, rscratch1, src); + str(rscratch1, adr); +} + void MacroAssembler::cmpptr(Register src1, Address src2) { unsigned long offset; adrp(rscratch1, src2, offset); @@ -3063,11 +3107,15 @@ if (UseCondCardMark) { Label L_already_dirty; + membar(StoreLoad); ldrb(rscratch2, Address(obj, rscratch1)); cbz(rscratch2, L_already_dirty); strb(zr, Address(obj, rscratch1)); bind(L_already_dirty); } else { + if (UseConcMarkSweepGC && CMSPrecleaningEnabled) { + membar(StoreStore); + } strb(zr, Address(obj, rscratch1)); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -152,6 +152,13 @@ strw(scratch, a); } + void bind(Label& L) { + Assembler::bind(L); + code()->clear_last_membar(); + } + + void membar(Membar_mask_bits order_constraint); + // Frame creation and destruction shared between JITs. void build_frame(int framesize); void remove_frame(int framesize); @@ -777,8 +784,8 @@ DEBUG_ONLY(void verify_heapbase(const char* msg);) - void push_CPU_state(); - void pop_CPU_state() ; + void push_CPU_state(bool save_vectors = false); + void pop_CPU_state(bool restore_vectors = false) ; // Round up to a power of two void round_to(Register reg, int modulus); @@ -908,13 +915,7 @@ // Arithmetics - void addptr(Address dst, int32_t src) { - lea(rscratch2, dst); - ldr(rscratch1, Address(rscratch2)); - add(rscratch1, rscratch1, src); - str(rscratch1, Address(rscratch2)); - } - + void addptr(const Address &dst, int32_t src); void cmpptr(Register src1, Address src2); // Various forms of CAS diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/methodHandles_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -50,7 +50,7 @@ #ifdef ASSERT static int check_nonzero(const char* xname, int x) { - assert(x != 0, err_msg("%s should be nonzero", xname)); + assert(x != 0, "%s should be nonzero", xname); return x; } #define NONZERO(x) check_nonzero(#x, x) @@ -407,7 +407,7 @@ } default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp --- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -101,6 +101,12 @@ static bool maybe_cpool_ref(address instr) { return is_adrp_at(instr) || is_ldr_literal_at(instr); } + + bool is_Membar() { + unsigned int insn = uint_at(0); + return Instruction_aarch64::extract(insn, 31, 12) == 0b11010101000000110011 && + Instruction_aarch64::extract(insn, 7, 0) == 0b10111111; + } }; inline NativeInstruction* nativeInstruction_at(address address) { @@ -487,4 +493,15 @@ return (NativeCallTrampolineStub*)addr; } +class NativeMembar : public NativeInstruction { +public: + unsigned int get_kind() { return Instruction_aarch64::extract(uint_at(0), 11, 8); } + void set_kind(int order_kind) { Instruction_aarch64::patch(addr_at(0), 11, 8, order_kind); } +}; + +inline NativeMembar *NativeMembar_at(address addr) { + assert(nativeInstruction_at(addr)->is_Membar(), "no membar found"); + return (NativeMembar*)addr; +} + #endif // CPU_AARCH64_VM_NATIVEINST_AARCH64_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -102,12 +102,5 @@ } } -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { - if (NativeInstruction::maybe_cpool_ref(addr())) { - address old_addr = old_addr_for(addr(), src, dest); - MacroAssembler::pd_patch_instruction(addr(), MacroAssembler::target_addr_for_insn(old_addr)); - } -} - void metadata_Relocation::pd_fix_value(address x) { } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -75,8 +75,8 @@ // FIXME -- this is used by C1 class RegisterSaver { public: - static OopMap* save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words); - static void restore_live_registers(MacroAssembler* masm); + static OopMap* save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors = false); + static void restore_live_registers(MacroAssembler* masm, bool restore_vectors = false); // Offsets into the register save area // Used by deoptimization when it is managing result register @@ -108,7 +108,17 @@ }; -OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words) { +OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) { +#ifdef COMPILER2 + if (save_vectors) { + // Save upper half of vector registers + int vect_words = 32 * 8 / wordSize; + additional_frame_words += vect_words; + } +#else + assert(!save_vectors, "vectors are generated only by C2"); +#endif + int frame_size_in_bytes = round_to(additional_frame_words*wordSize + reg_save_size*BytesPerInt, 16); // OopMap frame size is in compiler stack slots (jint's) not bytes or words @@ -122,7 +132,7 @@ // Save registers, fpu state, and flags. __ enter(); - __ push_CPU_state(); + __ push_CPU_state(save_vectors); // Set an oopmap for the call site. This oopmap will map all // oop-registers and debug-info registers as callee-saved. This @@ -139,14 +149,14 @@ // register slots are 8 bytes // wide, 32 floating-point // registers - oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset + additional_frame_slots), r->as_VMReg()); } } for (int i = 0; i < FloatRegisterImpl::number_of_registers; i++) { FloatRegister r = as_FloatRegister(i); - int sp_offset = 2 * i; + int sp_offset = save_vectors ? (4 * i) : (2 * i); oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), r->as_VMReg()); } @@ -154,8 +164,11 @@ return oop_map; } -void RegisterSaver::restore_live_registers(MacroAssembler* masm) { - __ pop_CPU_state(); +void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_vectors) { +#ifndef COMPILER2 + assert(!restore_vectors, "vectors are generated only by C2"); +#endif + __ pop_CPU_state(restore_vectors); __ leave(); } @@ -177,9 +190,9 @@ } // Is vector's size (in bytes) bigger than a size saved by default? -// 16 bytes XMM registers are saved by default using fxsave/fxrstor instructions. +// 8 bytes vector registers are saved by default on AArch64. bool SharedRuntime::is_wide_vector(int size) { - return size > 16; + return size > 8; } // The java_calling_convention describes stack locations as ideal slots on // a frame with no abi restrictions. Since we must observe abi restrictions @@ -460,11 +473,11 @@ } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Note: r13 contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled @@ -1146,7 +1159,7 @@ assert((unsigned)gpargs < 256, "eek!"); assert((unsigned)fpargs < 32, "eek!"); __ lea(rscratch1, RuntimeAddress(dest)); - __ mov(rscratch2, (gpargs << 6) | (fpargs << 2) | type); + if (UseBuiltinSim) __ mov(rscratch2, (gpargs << 6) | (fpargs << 2) | type); __ blrt(rscratch1, rscratch2); __ maybe_isb(); } @@ -1194,7 +1207,7 @@ } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { @@ -1521,14 +1534,13 @@ int vep_offset = ((intptr_t)__ pc()) - start; - // Generate stack overflow check - // If we have to make this method not-entrant we'll overwrite its // first instruction with a jump. For this action to be legal we // must ensure that this first instruction is a B, BL, NOP, BKPT, // SVC, HVC, or SMC. Make it a NOP. __ nop(); + // Generate stack overflow check if (UseStackBanging) { __ bang_stack_with_offset(StackShadowPages*os::vm_page_size()); } else { @@ -1709,23 +1721,20 @@ // need to spill before we call out int c_arg = total_c_args - total_in_args; - // Pre-load a static method's oop into r20. Used both by locking code and - // the normal JNI call code. + // Pre-load a static method's oop into c_rarg1. if (method->is_static() && !is_critical_native) { // load oop into a register - __ movoop(oop_handle_reg, + __ movoop(c_rarg1, JNIHandles::make_local(method->method_holder()->java_mirror()), /*immediate*/true); // Now handlize the static class mirror it's known not-null. - __ str(oop_handle_reg, Address(sp, klass_offset)); + __ str(c_rarg1, Address(sp, klass_offset)); map->set_oop(VMRegImpl::stack2reg(klass_slot_offset)); // Now get the handle - __ lea(oop_handle_reg, Address(sp, klass_offset)); - // store the klass handle as second argument - __ mov(c_rarg1, oop_handle_reg); + __ lea(c_rarg1, Address(sp, klass_offset)); // and protect the arg if we must spill c_arg--; } @@ -1740,19 +1749,13 @@ __ set_last_Java_frame(sp, noreg, (address)the_pc, rscratch1); - - // We have all of the arguments setup at this point. We must not touch any register - // argument registers at this point (what if we save/restore them there are no oop? - + Label dtrace_method_entry, dtrace_method_entry_done; { - SkipIfEqual skip(masm, &DTraceMethodProbes, false); - // protect the args we've loaded - save_args(masm, total_c_args, c_arg, out_regs); - __ mov_metadata(c_rarg1, method()); - __ call_VM_leaf( - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), - rthread, c_rarg1); - restore_args(masm, total_c_args, c_arg, out_regs); + unsigned long offset; + __ adrp(rscratch1, ExternalAddress((address)&DTraceMethodProbes), offset); + __ ldrb(rscratch1, Address(rscratch1, offset)); + __ cbnzw(rscratch1, dtrace_method_entry); + __ bind(dtrace_method_entry_done); } // RedefineClasses() tracing support for obsolete method entry @@ -1782,7 +1785,6 @@ if (method->is_synchronized()) { assert(!is_critical_native, "unhandled"); - const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); // Get the handle (the 2nd argument) @@ -1838,7 +1840,6 @@ // Finally just about ready to make the JNI call - // get JNIEnv* which is first argument to native if (!is_critical_native) { __ lea(c_rarg0, Address(rthread, in_bytes(JavaThread::jni_environment_offset()))); @@ -1879,9 +1880,9 @@ // Unpack native results. switch (ret_type) { - case T_BOOLEAN: __ ubfx(r0, r0, 0, 8); break; + case T_BOOLEAN: __ ubfx(r0, r0, 0, 8); break; case T_CHAR : __ ubfx(r0, r0, 0, 16); break; - case T_BYTE : __ sbfx(r0, r0, 0, 8); break; + case T_BYTE : __ sbfx(r0, r0, 0, 8); break; case T_SHORT : __ sbfx(r0, r0, 0, 16); break; case T_INT : __ sbfx(r0, r0, 0, 32); break; case T_DOUBLE : @@ -1904,14 +1905,17 @@ // Thread A is resumed to finish this native method, but doesn't block here since it // didn't see any synchronization is progress, and escapes. __ mov(rscratch1, _thread_in_native_trans); - __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); - __ stlrw(rscratch1, rscratch2); if(os::is_MP()) { if (UseMembar) { + __ strw(rscratch1, Address(rthread, JavaThread::thread_state_offset())); + // Force this write out before the read below __ dmb(Assembler::SY); } else { + __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); + __ stlrw(rscratch1, rscratch2); + // Write serialization page so VM thread can do a pseudo remote membar. // We use the current thread pointer to calculate a thread specific // offset to write to within the page. This minimizes bus traffic @@ -1920,54 +1924,23 @@ } } - Label after_transition; - // check for safepoint operation in progress and/or pending suspend requests + Label safepoint_in_progress, safepoint_in_progress_done; { - Label Continue; - - { unsigned long offset; - __ adrp(rscratch1, - ExternalAddress((address)SafepointSynchronize::address_of_state()), - offset); - __ ldrw(rscratch1, Address(rscratch1, offset)); - } - __ cmpw(rscratch1, SafepointSynchronize::_not_synchronized); - - Label L; - __ br(Assembler::NE, L); + assert(SafepointSynchronize::_not_synchronized == 0, "fix this code"); + unsigned long offset; + __ adrp(rscratch1, + ExternalAddress((address)SafepointSynchronize::address_of_state()), + offset); + __ ldrw(rscratch1, Address(rscratch1, offset)); + __ cbnzw(rscratch1, safepoint_in_progress); __ ldrw(rscratch1, Address(rthread, JavaThread::suspend_flags_offset())); - __ cbz(rscratch1, Continue); - __ bind(L); - - // Don't use call_VM as it will see a possible pending exception and forward it - // and never return here preventing us from clearing _last_native_pc down below. - // - save_native_result(masm, ret_type, stack_slots); - __ mov(c_rarg0, rthread); -#ifndef PRODUCT - assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); -#endif - if (!is_critical_native) { - __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); - } else { - __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans_and_transition))); - } - __ blrt(rscratch1, 1, 0, 1); - __ maybe_isb(); - // Restore any method result value - restore_native_result(masm, ret_type, stack_slots); - - if (is_critical_native) { - // The call above performed the transition to thread_in_Java so - // skip the transition logic below. - __ b(after_transition); - } - - __ bind(Continue); + __ cbnzw(rscratch1, safepoint_in_progress); + __ bind(safepoint_in_progress_done); } // change thread state + Label after_transition; __ mov(rscratch1, _thread_in_Java); __ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset())); __ stlrw(rscratch1, rscratch2); @@ -2024,16 +1997,15 @@ } __ bind(done); - } + + Label dtrace_method_exit, dtrace_method_exit_done; { - SkipIfEqual skip(masm, &DTraceMethodProbes, false); - save_native_result(masm, ret_type, stack_slots); - __ mov_metadata(c_rarg1, method()); - __ call_VM_leaf( - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), - rthread, c_rarg1); - restore_native_result(masm, ret_type, stack_slots); + unsigned long offset; + __ adrp(rscratch1, ExternalAddress((address)&DTraceMethodProbes), offset); + __ ldrb(rscratch1, Address(rscratch1, offset)); + __ cbnzw(rscratch1, dtrace_method_exit); + __ bind(dtrace_method_exit_done); } __ reset_last_Java_frame(false, true); @@ -2082,7 +2054,7 @@ // Slow path locking & unlocking if (method->is_synchronized()) { - // BEGIN Slow path lock + __ block_comment("Slow path lock {"); __ bind(slow_path_lock); // has last_Java_frame setup. No exceptions so do vanilla call not call_VM @@ -2109,9 +2081,9 @@ #endif __ b(lock_done); - // END Slow path lock - - // BEGIN Slow path unlock + __ block_comment("} Slow path lock"); + + __ block_comment("Slow path unlock {"); __ bind(slow_path_unlock); // If we haven't already saved the native result we must save it now as xmm registers @@ -2149,7 +2121,7 @@ } __ b(unlock_done); - // END Slow path unlock + __ block_comment("} Slow path unlock"); } // synchronized @@ -2162,6 +2134,69 @@ // and continue __ b(reguard_done); + // SLOW PATH safepoint + { + __ block_comment("safepoint {"); + __ bind(safepoint_in_progress); + + // Don't use call_VM as it will see a possible pending exception and forward it + // and never return here preventing us from clearing _last_native_pc down below. + // + save_native_result(masm, ret_type, stack_slots); + __ mov(c_rarg0, rthread); +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + if (!is_critical_native) { + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); + } else { + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans_and_transition))); + } + __ blrt(rscratch1, 1, 0, 1); + __ maybe_isb(); + // Restore any method result value + restore_native_result(masm, ret_type, stack_slots); + + if (is_critical_native) { + // The call above performed the transition to thread_in_Java so + // skip the transition logic above. + __ b(after_transition); + } + + __ b(safepoint_in_progress_done); + __ block_comment("} safepoint"); + } + + // SLOW PATH dtrace support + { + __ block_comment("dtrace entry {"); + __ bind(dtrace_method_entry); + + // We have all of the arguments setup at this point. We must not touch any register + // argument registers at this point (what if we save/restore them there are no oop? + + save_args(masm, total_c_args, c_arg, out_regs); + __ mov_metadata(c_rarg1, method()); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), + rthread, c_rarg1); + restore_args(masm, total_c_args, c_arg, out_regs); + __ b(dtrace_method_entry_done); + __ block_comment("} dtrace entry"); + } + + { + __ block_comment("dtrace exit {"); + __ bind(dtrace_method_exit); + save_native_result(masm, ret_type, stack_slots); + __ mov_metadata(c_rarg1, method()); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), + rthread, c_rarg1); + restore_native_result(masm, ret_type, stack_slots); + __ b(dtrace_method_exit_done); + __ block_comment("} dtrace exit"); + } __ flush(); @@ -2742,7 +2777,7 @@ bool save_vectors = (poll_type == POLL_AT_VECTOR_LOOP); // Save registers, fpu state, and flags - map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); + map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words, save_vectors); // The following is basically a call_VM. However, we need the precise // address of the call in order to generate an oopmap. Hence, we do all the @@ -2793,7 +2828,7 @@ __ bind(noException); // Normal exit, restore registers and exit. - RegisterSaver::restore_live_registers(masm); + RegisterSaver::restore_live_registers(masm, save_vectors); __ ret(lr); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -746,6 +746,9 @@ const Register count = end; // 'end' register contains bytes count now __ mov(scratch, (address)ct->byte_map_base); __ add(start, start, scratch); + if (UseConcMarkSweepGC) { + __ membar(__ StoreStore); + } __ BIND(L_loop); __ strb(zr, Address(start, count)); __ subs(count, count, 1); @@ -2395,6 +2398,274 @@ return start; } + /*** + * Arguments: + * + * Inputs: + * c_rarg0 - int adler + * c_rarg1 - byte* buff + * c_rarg2 - int len + * + * Output: + * c_rarg0 - int adler result + */ + address generate_updateBytesAdler32() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "updateBytesAdler32"); + address start = __ pc(); + + Label L_simple_by1_loop, L_nmax, L_nmax_loop, L_by16, L_by16_loop, L_by1_loop, L_do_mod, L_combine, L_by1; + + // Aliases + Register adler = c_rarg0; + Register s1 = c_rarg0; + Register s2 = c_rarg3; + Register buff = c_rarg1; + Register len = c_rarg2; + Register nmax = r4; + Register base = r5; + Register count = r6; + Register temp0 = rscratch1; + Register temp1 = rscratch2; + Register temp2 = r7; + + // Max number of bytes we can process before having to take the mod + // 0x15B0 is 5552 in decimal, the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 + unsigned long BASE = 0xfff1; + unsigned long NMAX = 0x15B0; + + __ mov(base, BASE); + __ mov(nmax, NMAX); + + // s1 is initialized to the lower 16 bits of adler + // s2 is initialized to the upper 16 bits of adler + __ ubfx(s2, adler, 16, 16); // s2 = ((adler >> 16) & 0xffff) + __ uxth(s1, adler); // s1 = (adler & 0xffff) + + // The pipelined loop needs at least 16 elements for 1 iteration + // It does check this, but it is more effective to skip to the cleanup loop + __ cmp(len, 16); + __ br(Assembler::HS, L_nmax); + __ cbz(len, L_combine); + + __ bind(L_simple_by1_loop); + __ ldrb(temp0, Address(__ post(buff, 1))); + __ add(s1, s1, temp0); + __ add(s2, s2, s1); + __ subs(len, len, 1); + __ br(Assembler::HI, L_simple_by1_loop); + + // s1 = s1 % BASE + __ subs(temp0, s1, base); + __ csel(s1, temp0, s1, Assembler::HS); + + // s2 = s2 % BASE + __ lsr(temp0, s2, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(s2, temp1, s2, ext::uxth); + + __ subs(temp0, s2, base); + __ csel(s2, temp0, s2, Assembler::HS); + + __ b(L_combine); + + __ bind(L_nmax); + __ subs(len, len, nmax); + __ sub(count, nmax, 16); + __ br(Assembler::LO, L_by16); + + __ bind(L_nmax_loop); + + __ ldp(temp0, temp1, Address(__ post(buff, 16))); + + __ add(s1, s1, temp0, ext::uxtb); + __ ubfx(temp2, temp0, 8, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 16, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 24, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 32, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 40, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 48, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ add(s2, s2, s1); + __ add(s1, s1, temp0, Assembler::LSR, 56); + __ add(s2, s2, s1); + + __ add(s1, s1, temp1, ext::uxtb); + __ ubfx(temp2, temp1, 8, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 16, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 24, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 32, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 40, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 48, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ add(s2, s2, s1); + __ add(s1, s1, temp1, Assembler::LSR, 56); + __ add(s2, s2, s1); + + __ subs(count, count, 16); + __ br(Assembler::HS, L_nmax_loop); + + // s1 = s1 % BASE + __ lsr(temp0, s1, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(temp1, temp1, s1, ext::uxth); + + __ lsr(temp0, temp1, 16); + __ lsl(s1, temp0, 4); + __ sub(s1, s1, temp0); + __ add(s1, s1, temp1, ext:: uxth); + + __ subs(temp0, s1, base); + __ csel(s1, temp0, s1, Assembler::HS); + + // s2 = s2 % BASE + __ lsr(temp0, s2, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(temp1, temp1, s2, ext::uxth); + + __ lsr(temp0, temp1, 16); + __ lsl(s2, temp0, 4); + __ sub(s2, s2, temp0); + __ add(s2, s2, temp1, ext:: uxth); + + __ subs(temp0, s2, base); + __ csel(s2, temp0, s2, Assembler::HS); + + __ subs(len, len, nmax); + __ sub(count, nmax, 16); + __ br(Assembler::HS, L_nmax_loop); + + __ bind(L_by16); + __ adds(len, len, count); + __ br(Assembler::LO, L_by1); + + __ bind(L_by16_loop); + + __ ldp(temp0, temp1, Address(__ post(buff, 16))); + + __ add(s1, s1, temp0, ext::uxtb); + __ ubfx(temp2, temp0, 8, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 16, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 24, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 32, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 40, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp0, 48, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ add(s2, s2, s1); + __ add(s1, s1, temp0, Assembler::LSR, 56); + __ add(s2, s2, s1); + + __ add(s1, s1, temp1, ext::uxtb); + __ ubfx(temp2, temp1, 8, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 16, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 24, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 32, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 40, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ ubfx(temp2, temp1, 48, 8); + __ add(s2, s2, s1); + __ add(s1, s1, temp2); + __ add(s2, s2, s1); + __ add(s1, s1, temp1, Assembler::LSR, 56); + __ add(s2, s2, s1); + + __ subs(len, len, 16); + __ br(Assembler::HS, L_by16_loop); + + __ bind(L_by1); + __ adds(len, len, 15); + __ br(Assembler::LO, L_do_mod); + + __ bind(L_by1_loop); + __ ldrb(temp0, Address(__ post(buff, 1))); + __ add(s1, temp0, s1); + __ add(s2, s2, s1); + __ subs(len, len, 1); + __ br(Assembler::HS, L_by1_loop); + + __ bind(L_do_mod); + // s1 = s1 % BASE + __ lsr(temp0, s1, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(temp1, temp1, s1, ext::uxth); + + __ lsr(temp0, temp1, 16); + __ lsl(s1, temp0, 4); + __ sub(s1, s1, temp0); + __ add(s1, s1, temp1, ext:: uxth); + + __ subs(temp0, s1, base); + __ csel(s1, temp0, s1, Assembler::HS); + + // s2 = s2 % BASE + __ lsr(temp0, s2, 16); + __ lsl(temp1, temp0, 4); + __ sub(temp1, temp1, temp0); + __ add(temp1, temp1, s2, ext::uxth); + + __ lsr(temp0, temp1, 16); + __ lsl(s2, temp0, 4); + __ sub(s2, s2, temp0); + __ add(s2, s2, temp1, ext:: uxth); + + __ subs(temp0, s2, base); + __ csel(s2, temp0, s2, Assembler::HS); + + // Combine lower bits and higher bits + __ bind(L_combine); + __ orr(s1, s1, s2, Assembler::LSL, 16); // adler = s1 | (s2 << 16) + + __ ret(lr); + + return start; + } + /** * Arguments: * @@ -3613,6 +3884,11 @@ StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(); } + // generate Adler32 intrinsics code + if (UseAdler32Intrinsics) { + StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32(); + } + // Safefetch stubs. generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, &StubRoutines::_safefetch32_fault_pc, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -535,7 +535,7 @@ // r0 // c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs) // rscratch1, rscratch2 (scratch regs) -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags(rmethod, Method::access_flags_offset()); const Address monitor_block_top( @@ -721,8 +721,7 @@ // generate a vanilla interpreter entry as the slow path __ bind(slow_path); - (void) generate_normal_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); return entry; } #endif // INCLUDE_ALL_GCS @@ -779,12 +778,10 @@ // generate a vanilla native entry as the slow path __ bind(slow_path); - - (void) generate_native_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); return entry; } - return generate_native_entry(false); + return NULL; } /** @@ -841,12 +838,10 @@ // generate a vanilla native entry as the slow path __ bind(slow_path); - - (void) generate_native_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); return entry; } - return generate_native_entry(false); + return NULL; } void InterpreterGenerator::bang_stack_shadow_pages(bool native_call) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -178,9 +178,8 @@ warning("UseCRC32 specified, but not supported on this CPU"); } - if (UseAdler32Intrinsics) { - warning("Adler32Intrinsics not available on this CPU."); - FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); + if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { + FLAG_SET_DEFAULT(UseAdler32Intrinsics, true); } if (auxv & HWCAP_AES) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -60,6 +60,7 @@ define_pd_global(bool, OptoPeephole, false); define_pd_global(bool, UseCISCSpill, false); define_pd_global(bool, OptoBundling, false); +define_pd_global(bool, OptoRegScheduling, false); // GL: // Detected a problem with unscaled compressed oops and // narrow_oop_use_complex_address() == false. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -94,10 +94,12 @@ const int IC_pos_in_java_to_interp_stub = 8; #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* = NULL*/) { #ifdef COMPILER2 - // Get the mark within main instrs section which is set to the address of the call. - address call_addr = cbuf.insts_mark(); + if (mark == NULL) { + // Get the mark within main instrs section which is set to the address of the call. + mark = cbuf.insts_mark(); + } // 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. @@ -117,7 +119,7 @@ // Create a static stub relocation which relates this stub // with the call instruction at insts_call_instruction_offset in the // instructions code-section. - __ relocate(static_stub_Relocation::spec(call_addr)); + __ relocate(static_stub_Relocation::spec(mark)); const int stub_start_offset = __ offset(); // Now, create the stub's code: diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -46,7 +46,7 @@ MacroAssembler::null_check_throw(a, offset, temp_reg, exception_entry); } -void InterpreterMacroAssembler::branch_to_entry(address entry, Register Rscratch) { +void InterpreterMacroAssembler::jump_to_entry(address entry, Register Rscratch) { assert(entry, "Entry must have been generated by now"); if (is_within_range_of_b(entry, pc())) { b(entry); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -39,7 +39,7 @@ void null_check_throw(Register a, int offset, Register temp_reg); - void branch_to_entry(address entry, Register Rscratch); + void jump_to_entry(address entry, Register Rscratch); // Handy address generation macros. #define thread_(field_name) in_bytes(JavaThread::field_name ## _offset()), R16_thread diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp --- a/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/interpreterGenerator_ppc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,12 +31,12 @@ private: address generate_abstract_entry(void); - address generate_jump_to_normal_entry(void); - address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } - address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } + address generate_accessor_entry(void) { return NULL; } + address generate_empty_entry(void) { return NULL; } address generate_Reference_get_entry(void); address generate_CRC32_update_entry(); address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } #endif // CPU_PPC_VM_INTERPRETERGENERATOR_PPC_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/interpreter_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -427,18 +427,6 @@ return entry; } -// Call an accessor method (assuming it is resolved, otherwise drop into -// vanilla (slow path) entry. -address InterpreterGenerator::generate_jump_to_normal_entry(void) { - address entry = __ pc(); - address normal_entry = Interpreter::entry_for_kind(Interpreter::zerolocals); - assert(normal_entry != NULL, "should already be generated."); - __ branch_to_entry(normal_entry, R11_scratch1); - __ flush(); - - return entry; -} - // Abstract method entry. // address InterpreterGenerator::generate_abstract_entry(void) { @@ -529,13 +517,13 @@ // regular method entry code to generate the NPE. // - address entry = __ pc(); + if (UseG1GC) { + address entry = __ pc(); - const int referent_offset = java_lang_ref_Reference::referent_offset; - guarantee(referent_offset > 0, "referent offset not initialized"); + const int referent_offset = java_lang_ref_Reference::referent_offset; + guarantee(referent_offset > 0, "referent offset not initialized"); - if (UseG1GC) { - Label slow_path; + Label slow_path; // Debugging not possible, so can't use __ skip_if_jvmti_mode(slow_path, GR31_SCRATCH); @@ -577,13 +565,11 @@ // Generate regular method entry. __ bind(slow_path); - __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1); - __ flush(); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1); return entry; - } else { - return generate_jump_to_normal_entry(); } + + return NULL; } void Deoptimization::unwind_callee_save_values(frame* f, vframeArray* vframe_array) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/ppc/vm/jvmciCodeInstaller_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_ppc.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + Unimplemented(); + return 0; +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + Unimplemented(); +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { + Unimplemented(); +} + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + Unimplemented(); +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + return NULL; +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return false; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -594,13 +594,6 @@ "can't identify emitted call"); } else { // variant 1: -#if defined(ABI_ELFv2) - nop(); - calculate_address_from_global_toc(R12, dest, true, true, false); - mtctr(R12); - nop(); - nop(); -#else mr(R0, R11); // spill R11 -> R0. // Load the destination address into CTR, @@ -610,7 +603,6 @@ mtctr(R11); mr(R11, R0); // spill R11 <- R0. nop(); -#endif // do the call/jump if (link) { @@ -4292,7 +4284,7 @@ static void stop_on_request(int tp, const char* msg) { tty->print("PPC assembly code requires stop: (%s) %s\n", stop_types[tp%/*stop_end*/4], msg); - guarantee(false, err_msg("PPC assembly code requires stop: %s", msg)); + guarantee(false, "PPC assembly code requires stop: %s", msg); } // Call a C-function that prints output. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -60,7 +60,7 @@ #ifdef ASSERT static int check_nonzero(const char* xname, int x) { - assert(x != 0, err_msg("%s should be nonzero", xname)); + assert(x != 0, "%s should be nonzero", xname); return x; } #define NONZERO(x) check_nonzero(#x, x) @@ -434,7 +434,7 @@ } default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -149,7 +149,7 @@ if (!NativeCall::is_call_at(addr)) { tty->print_cr("not a NativeCall at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr - 20, addr + 20, tty); - fatal(err_msg("not a NativeCall at " PTR_FORMAT, p2i(addr))); + fatal("not a NativeCall at " PTR_FORMAT, p2i(addr)); } } #endif // ASSERT @@ -162,7 +162,7 @@ if (!NativeFarCall::is_far_call_at(addr)) { tty->print_cr("not a NativeFarCall at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr, 20, 20, tty); - fatal(err_msg("not a NativeFarCall at " PTR_FORMAT, p2i(addr))); + fatal("not a NativeFarCall at " PTR_FORMAT, p2i(addr)); } } #endif // ASSERT @@ -308,7 +308,7 @@ ! MacroAssembler::is_bl(*((int*) addr))) { tty->print_cr("not a NativeMovConstReg at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr, 20, 20, tty); - fatal(err_msg("not a NativeMovConstReg at " PTR_FORMAT, p2i(addr))); + fatal("not a NativeMovConstReg at " PTR_FORMAT, p2i(addr)); } } } @@ -346,7 +346,7 @@ if (!NativeJump::is_jump_at(addr)) { tty->print_cr("not a NativeJump at " PTR_FORMAT, p2i(addr)); // TODO: PPC port: Disassembler::decode(addr, 20, 20, tty); - fatal(err_msg("not a NativeJump at " PTR_FORMAT, p2i(addr))); + fatal("not a NativeJump at " PTR_FORMAT, p2i(addr)); } } #endif // ASSERT diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/ppc.ad --- a/hotspot/src/cpu/ppc/vm/ppc.ad Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/ppc.ad Thu Oct 22 11:13:08 2015 -0700 @@ -2064,6 +2064,10 @@ return true; // Per default match rules are supported. } +const int Matcher::float_pressure(int default_pressure_threshold) { + return default_pressure_threshold; +} + int Matcher::regnum_to_fpu_offset(int regnum) { // No user for this method? Unimplemented(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -125,8 +125,5 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -} - void metadata_Relocation::pd_fix_value(address x) { } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -475,9 +475,8 @@ // Is vector's size (in bytes) bigger than a size saved by default? bool SharedRuntime::is_wide_vector(int size) { - ResourceMark rm; // Note, MaxVectorSize == 8 on PPC64. - assert(size <= 8, err_msg_res("%d bytes vectors are not supported", size)); + assert(size <= 8, "%d bytes vectors are not supported", size); return size > 8; } #ifdef COMPILER2 @@ -957,11 +956,11 @@ return c2i_entrypoint; } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Load method's entry-point from method. __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); @@ -1631,7 +1630,7 @@ } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -841,7 +841,7 @@ // Only called by MacroAssembler::verify_oop static void verify_oop_helper(const char* message, oop o) { if (!o->is_oop_or_null()) { - fatal(message); + fatal("%s", message); } ++ StubRoutines::_verify_oop_count; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -620,7 +620,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { if (!math_entry_available(kind)) { NOT_PRODUCT(__ should_not_reach_here();) - return Interpreter::entry_for_kind(Interpreter::zerolocals); + return NULL; } address entry = __ pc(); @@ -1126,14 +1126,6 @@ generate_fixed_frame(false, Rsize_of_parameters, Rsize_of_locals); -#ifdef FAST_DISPATCH - __ unimplemented("Fast dispatch in generate_normal_entry"); -#if 0 - __ set((intptr_t)Interpreter::dispatch_table(), IdispatchTables); - // Set bytecode dispatch table base. -#endif -#endif - // -------------------------------------------------------------------------- // Zero out non-parameter locals. // Note: *Always* zero out non-parameter locals as Sparc does. It's not @@ -1266,9 +1258,8 @@ * int java.util.zip.CRC32.update(int crc, int b) */ address InterpreterGenerator::generate_CRC32_update_entry() { - address start = __ pc(); // Remember stub start address (is rtn value). - if (UseCRC32Intrinsics) { + address start = __ pc(); // Remember stub start address (is rtn value). Label slow_path; // Safepoint check @@ -1313,11 +1304,11 @@ // Generate a vanilla native entry as the slow path. BLOCK_COMMENT("} CRC32_update"); BIND(slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native), R11_scratch1); + return start; } - (void) generate_native_entry(false); - - return start; + return NULL; } // CRC32 Intrinsics. @@ -1327,9 +1318,8 @@ * int java.util.zip.CRC32.updateByteBuffer(int crc, long* buf, int off, int len) */ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { - address start = __ pc(); // Remember stub start address (is rtn value). - if (UseCRC32Intrinsics) { + address start = __ pc(); // Remember stub start address (is rtn value). Label slow_path; // Safepoint check @@ -1406,11 +1396,11 @@ // Generate a vanilla native entry as the slow path. BLOCK_COMMENT("} CRC32_updateBytes(Buffer)"); BIND(slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native), R11_scratch1); + return start; } - (void) generate_native_entry(false); - - return start; + return NULL; } // These should never be compiled since the interpreter will prefer diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/assembler_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -389,7 +389,7 @@ static void assert_signed_range(intptr_t x, int nbits) { assert(nbits == 32 || (-(1 << nbits-1) <= x && x < ( 1 << nbits-1)), - err_msg("value out of range: x=" INTPTR_FORMAT ", nbits=%d", x, nbits)); + "value out of range: x=" INTPTR_FORMAT ", nbits=%d", x, nbits); } static void assert_signed_word_disp_range(intptr_t x, int nbits) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -64,6 +64,7 @@ define_pd_global(bool, UseCISCSpill, false); define_pd_global(bool, OptoBundling, false); define_pd_global(bool, OptoScheduling, true); +define_pd_global(bool, OptoRegScheduling, false); #ifdef _LP64 // We need to make sure that all generated code is within diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/compiledIC_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -53,14 +53,15 @@ // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { -#ifdef COMPILER2 +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from calling // compiled code to calling interpreted code. // set (empty), G5 // jmp -1 - address mark = cbuf.insts_mark(); // Get mark within main instrs section. + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } MacroAssembler _masm(&cbuf); @@ -80,12 +81,11 @@ __ delayed()->nop(); + assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size"); + // Update current stubs pointer and restore code_end. __ end_a_stub(); return base; -#else - ShouldNotReachHere(); -#endif } #undef __ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/cppInterpreterGenerator_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,6 +31,7 @@ void generate_more_monitors(); void generate_deopt_handling(); + void lock_method(void); void adjust_callers_stack(Register args); void generate_compute_interpreter_state(const Register state, const Register prev_state, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -468,7 +468,7 @@ // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } // @@ -1164,7 +1164,7 @@ } // Find preallocated monitor and lock method (C++ interpreter) // -void InterpreterGenerator::lock_method(void) { +void CppInterpreterGenerator::lock_method() { // Lock the current method. // Destroys registers L2_scratch, L3_scratch, O0 // diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/globals_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -82,6 +82,7 @@ \ product(intx, UseVIS, 99, \ "Highest supported VIS instructions set on Sparc") \ + range(0, 99) \ \ product(bool, UseCBCond, false, \ "Use compare and branch instruction on SPARC") \ @@ -91,12 +92,14 @@ \ product(intx, BlockZeroingLowLimit, 2048, \ "Minimum size in bytes when block zeroing will be used") \ + range(1, max_jint) \ \ product(bool, UseBlockCopy, false, \ "Use special cpu instructions for block copy") \ \ product(intx, BlockCopyLowLimit, 2048, \ "Minimum size in bytes when block copy will be used") \ + range(1, max_jint) \ \ develop(bool, UseV8InstrsOnly, false, \ "Use SPARC-V8 Compliant instruction subset") \ @@ -108,9 +111,11 @@ "Do not use swap instructions, but only CAS (in a loop) on SPARC")\ \ product(uintx, ArraycopySrcPrefetchDistance, 0, \ - "Distance to prefetch source array in arracopy") \ + "Distance to prefetch source array in arraycopy") \ + constraint(ArraycopySrcPrefetchDistanceConstraintFunc, AfterErgo) \ \ product(uintx, ArraycopyDstPrefetchDistance, 0, \ - "Distance to prefetch destination array in arracopy") \ + "Distance to prefetch destination array in arraycopy") \ + constraint(ArraycopyDstPrefetchDistanceConstraintFunc, AfterErgo) \ #endif // CPU_SPARC_VM_GLOBALS_SPARC_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -59,6 +59,13 @@ #endif // CC_INTERP +void InterpreterMacroAssembler::jump_to_entry(address entry) { + assert(entry, "Entry must have been generated by now"); + AddressLiteral al(entry); + jump_to(al, G3_scratch); + delayed()->nop(); +} + void InterpreterMacroAssembler::compute_extra_locals_size_in_bytes(Register args_size, Register locals_size, Register delta) { // Note: this algorithm is also used by C1's OSR entry sequence. // Any changes should also be applied to CodeEmitter::emit_osr_entry(). @@ -1643,26 +1650,73 @@ bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. +#if INCLUDE_JVMCI + if (MethodProfileWidth == 0) { + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + } +#else update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); - bind (profile_continue); +#endif + bind(profile_continue); } } -void InterpreterMacroAssembler::record_klass_in_profile_helper( - Register receiver, Register scratch, - int start_row, Label& done, bool is_virtual_call) { +#if INCLUDE_JVMCI +void InterpreterMacroAssembler::profile_called_method(Register method, Register scratch) { + assert_different_registers(method, scratch); + if (ProfileInterpreter && MethodProfileWidth > 0) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(profile_continue); + + Label done; + record_item_in_profile_helper(method, scratch, 0, done, MethodProfileWidth, + &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset())); + bind(done); + + update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); + bind(profile_continue); + } +} +#endif // INCLUDE_JVMCI + +void InterpreterMacroAssembler::record_klass_in_profile_helper(Register receiver, Register scratch, + Label& done, bool is_virtual_call) { if (TypeProfileWidth == 0) { if (is_virtual_call) { increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); } - return; +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + increment_mdp_data_at(in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()), scratch); + } +#endif + } else { + int non_profiled_offset = -1; + if (is_virtual_call) { + non_profiled_offset = in_bytes(CounterData::count_offset()); + } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()); + } +#endif + + record_item_in_profile_helper(receiver, scratch, 0, done, TypeProfileWidth, + &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); } - - int last_row = VirtualCallData::row_limit() - 1; +} + +void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, + Register scratch, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset) { + int last_row = total_rows - 1; assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. + // Test this row for both the item and for null. // Take any of three different outcomes: - // 1. found receiver => increment count and goto done + // 1. found item => increment count and goto done // 2. found null => keep looking for case 1, maybe allocate this cell // 3. found something else => keep looking for cases 1 and 2 // Case 3 is handled by a recursive call. @@ -1670,28 +1724,28 @@ Label next_test; bool test_for_null_also = (row == start_row); - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(recvr_offset, receiver, next_test, scratch); + // See if the item is item[n]. + int item_offset = in_bytes(item_offset_fn(row)); + test_mdp_data_at(item_offset, item, next_test, scratch); // delayed()->tst(scratch); - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + // The receiver is item[n]. Increment count[n]. + int count_offset = in_bytes(item_count_offset_fn(row)); increment_mdp_data_at(count_offset, scratch); ba_short(done); bind(next_test); if (test_for_null_also) { Label found_null; - // Failed the equality check on receiver[n]... Test for null. + // Failed the equality check on item[n]... Test for null. if (start_row == last_row) { // The only thing left to do is handle the null case. - if (is_virtual_call) { + if (non_profiled_offset >= 0) { brx(Assembler::zero, false, Assembler::pn, found_null); delayed()->nop(); - // Receiver did not match any saved receiver and there is no empty row for it. + // Item did not match any saved item and there is no empty row for it. // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); + increment_mdp_data_at(non_profiled_offset, scratch); ba_short(done); bind(found_null); } else { @@ -1705,21 +1759,22 @@ delayed()->nop(); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, scratch, start_row + 1, done, is_virtual_call); - - // Found a null. Keep searching for a matching receiver, + record_item_in_profile_helper(item, scratch, start_row + 1, done, total_rows, + item_offset_fn, item_count_offset_fn, non_profiled_offset); + + // Found a null. Keep searching for a matching item, // but remember that this is an empty (unused) slot. bind(found_null); } } - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is NULL. - - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + // In the fall-through case, we found no matching item, but we + // observed the item[start_row] is NULL. + + // Fill in the item field and increment the count. + int item_offset = in_bytes(item_offset_fn(start_row)); + set_mdp_data_at(item_offset, item); + int count_offset = in_bytes(item_count_offset_fn(start_row)); mov(DataLayout::counter_increment, scratch); set_mdp_data_at(count_offset, scratch); if (start_row > 0) { @@ -1732,7 +1787,7 @@ assert(ProfileInterpreter, "must be profiling"); Label done; - record_klass_in_profile_helper(receiver, scratch, 0, done, is_virtual_call); + record_klass_in_profile_helper(receiver, scratch, done, is_virtual_call); bind (done); } @@ -1788,7 +1843,7 @@ // The method data pointer needs to be updated. int mdp_delta = in_bytes(BitData::bit_data_size()); if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size()); } update_mdp_by_constant(mdp_delta); @@ -1806,7 +1861,7 @@ int mdp_delta = in_bytes(BitData::bit_data_size()); if (TypeProfileCasts) { - mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size()); // Record the object type. record_klass_in_profile(klass, scratch, false); @@ -1828,7 +1883,7 @@ int count_offset = in_bytes(CounterData::count_offset()); // Back up the address, since we have already bumped the mdp. - count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); + count_offset -= in_bytes(ReceiverTypeData::receiver_type_data_size()); // *Decrement* the counter. We expect to see zero or small negatives. increment_mdp_data_at(count_offset, scratch, true); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,6 +30,8 @@ // This file specializes the assember with interpreter-specific macros +typedef ByteSize (*OffsetFunction)(uint); + REGISTER_DECLARATION( Register, Otos_i , O0); // tos for ints, etc REGISTER_DECLARATION( Register, Otos_l , O0); // for longs REGISTER_DECLARATION( Register, Otos_l1, O0); // for 1st part of longs @@ -80,6 +82,8 @@ InterpreterMacroAssembler(CodeBuffer* c) : MacroAssembler(c) {} + void jump_to_entry(address entry); + #ifndef CC_INTERP virtual void load_earlyret_value(TosState state); @@ -299,7 +303,11 @@ void record_klass_in_profile(Register receiver, Register scratch, bool is_virtual_call); void record_klass_in_profile_helper(Register receiver, Register scratch, - int start_row, Label& done, bool is_virtual_call); + Label& done, bool is_virtual_call); + void record_item_in_profile_helper(Register item, + Register scratch, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset); void update_mdp_by_offset(int offset_of_disp, Register scratch); void update_mdp_by_offset(Register reg, int offset_of_disp, @@ -312,6 +320,7 @@ void profile_call(Register scratch); void profile_final_call(Register scratch); void profile_virtual_call(Register receiver, Register scratch, bool receiver_can_be_null = false); + void profile_called_method(Register method, Register scratch) NOT_JVMCI_RETURN; void profile_ret(TosState state, Register return_bci, Register scratch); void profile_null_seen(Register scratch); void profile_typecheck(Register klass, Register scratch); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -34,11 +34,9 @@ address generate_abstract_entry(void); // there are no math intrinsics on sparc address generate_math_entry(AbstractInterpreter::MethodKind kind) { return NULL; } - address generate_jump_to_normal_entry(void); - address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } - address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } + address generate_accessor_entry(void) { return NULL; } + address generate_empty_entry(void) { return NULL; } address generate_Reference_get_entry(void); - void lock_method(void); void save_native_result(void); void restore_native_result(void); @@ -48,4 +46,5 @@ // Not supported address generate_CRC32_update_entry() { return NULL; } address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } #endif // CPU_SPARC_VM_INTERPRETERGENERATOR_SPARC_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -241,15 +241,6 @@ // Various method entries -address InterpreterGenerator::generate_jump_to_normal_entry(void) { - address entry = __ pc(); - assert(Interpreter::entry_for_kind(Interpreter::zerolocals) != NULL, "should already be generated"); - AddressLiteral al(Interpreter::entry_for_kind(Interpreter::zerolocals)); - __ jump_to(al, G3_scratch); - __ delayed()->nop(); - return entry; -} - // Abstract method entry // Attempt to execute abstract method. Throw exception // diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_sparc.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + if (inst->is_call() || inst->is_jump()) { + return pc_offset + NativeCall::instruction_size; + } else if (inst->is_call_reg()) { + return pc_offset + NativeCallReg::instruction_size; + } else if (inst->is_sethi()) { + return pc_offset + NativeFarCall::instruction_size; + } else { + fatal("unsupported type of instruction for call site"); + return 0; + } +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + address pc = _instructions->start() + pc_offset; + Handle obj = HotSpotObjectConstantImpl::object(constant); + jobject value = JNIHandles::make_local(obj()); + if (HotSpotObjectConstantImpl::compressed(constant)) { +#ifdef _LP64 + int oop_index = _oop_recorder->find_index(value); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + _instructions->relocate(pc, rspec, 1); +#else + fatal("compressed oop on 32bit"); +#endif + } else { + NativeMovConstReg* move = nativeMovConstReg_at(pc); + move->set_data((intptr_t) value); + + // We need two relocations: one on the sethi and one on the add. + int oop_index = _oop_recorder->find_index(value); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + _instructions->relocate(pc + NativeMovConstReg::sethi_offset, rspec); + _instructions->relocate(pc + NativeMovConstReg::add_offset, rspec); + } +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + address pc = _instructions->start() + pc_offset; + NativeInstruction* inst = nativeInstruction_at(pc); + NativeInstruction* inst1 = nativeInstruction_at(pc + 4); + if(inst->is_sethi() && inst1->is_nop()) { + address const_start = _constants->start(); + address dest = _constants->start() + data_offset; + if(_constants_size > 0) { + _instructions->relocate(pc + NativeMovConstReg::sethi_offset, internal_word_Relocation::spec((address) dest)); + _instructions->relocate(pc + NativeMovConstReg::add_offset, internal_word_Relocation::spec((address) dest)); + } + TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset); + }else { + int const_size = align_size_up(_constants->end()-_constants->start(), CodeEntryAlignment); + NativeMovRegMem* load = nativeMovRegMem_at(pc); + // This offset must match with SPARCLoadConstantTableBaseOp.emitCode + load->set_offset(- (const_size - data_offset + Assembler::min_simm13())); + TRACE_jvmci_3("relocating ld at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset); + } +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + fatal("CodeInstaller::pd_relocate_CodeBlob - sparc unimp"); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + address pc = (address) inst; + if (inst->is_call()) { + NativeCall* call = nativeCall_at(pc); + call->set_destination((address) foreign_call_destination); + _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec()); + } else if (inst->is_sethi()) { + NativeJump* jump = nativeJump_at(pc); + jump->set_jump_destination((address) foreign_call_destination); + _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec()); + } else { + fatal(err_msg("unknown call or jump instruction at " PTR_FORMAT, p2i(pc))); + } + TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +#ifdef ASSERT + Method* method = NULL; + // we need to check, this might also be an unresolved method + if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { + method = getMethodFromHotSpotMethod(hotspot_method); + } +#endif + switch (_next_call_type) { + case INLINE_INVOKE: + break; + case INVOKEVIRTUAL: + case INVOKEINTERFACE: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc)); + break; + } + case INVOKESTATIC: { + assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_static_call_stub()); + _instructions->relocate(call->instruction_address(), relocInfo::static_call_type); + break; + } + case INVOKESPECIAL: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type); + break; + } + default: + fatal("invalid _next_call_type value"); + break; + } +} + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + switch (mark) { + case POLL_NEAR: + fatal("unimplemented"); + break; + case POLL_FAR: + _instructions->relocate(pc, relocInfo::poll_type); + break; + case POLL_RETURN_NEAR: + fatal("unimplemented"); + break; + case POLL_RETURN_FAR: + _instructions->relocate(pc, relocInfo::poll_return_type); + break; + default: + fatal("invalid mark value"); + break; + } +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + if (jvmci_reg < RegisterImpl::number_of_registers) { + return as_Register(jvmci_reg)->as_VMReg(); + } else { + jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers; + floatRegisterNumber += MAX2(0, floatRegisterNumber-32); // Beginning with f32, only every second register is going to be addressed + if (floatRegisterNumber < FloatRegisterImpl::number_of_registers) { + return as_FloatRegister(floatRegisterNumber)->as_VMReg(); + } + ShouldNotReachHere(); + return NULL; + } +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return !hotspotRegister->is_FloatRegister(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1596,7 +1596,7 @@ else { ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); } - assert(false, err_msg("DEBUG MESSAGE: %s", msg)); + assert(false, "DEBUG MESSAGE: %s", msg); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/memset_with_concurrent_readers_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -61,8 +61,8 @@ " sub %[offset], %[end], %[offset]\n\t" // offset := start - end " sllx %[offset], 2, %[offset]\n\t" // scale offset for instruction size of 4 " add %[offset], 40, %[offset]\n\t" // offset += 10 * instruction size - " rd %pc, %[pc]\n\t" // dispatch on scaled offset - " jmpl %[pc]+%[offset], %g0\n\t" + " rd %%pc, %[pc]\n\t" // dispatch on scaled offset + " jmpl %[pc]+%[offset], %%g0\n\t" " nop\n\t" // DISPATCH: no direct reference, but without it the store block may be elided. "1:\n\t" @@ -108,7 +108,7 @@ // Unroll loop x8. " sub %[aend], %[ato], %[temp]\n\t" " cmp %[temp], 56\n\t" // cc := (aligned_end - aligned_to) > 7 words - " ba %xcc, 2f\n\t" // goto TEST always + " ba %%xcc, 2f\n\t" // goto TEST always " sub %[aend], 56, %[temp]\n\t" // limit := aligned_end - 7 words // LOOP: "1:\n\t" // unrolled x8 store loop top @@ -123,7 +123,7 @@ " stx %[xvalue], [%[ato]-8]\n\t" // TEST: "2:\n\t" - " bgu,a %xcc, 1b\n\t" // goto LOOP if more than 7 words remaining + " bgu,a %%xcc, 1b\n\t" // goto LOOP if more than 7 words remaining " add %[ato], 64, %[ato]\n\t" // aligned_to += 8, for next iteration // Fill remaining < 8 full words. // Dispatch on (aligned_end - aligned_to). @@ -132,8 +132,8 @@ " sub %[ato], %[aend], %[ato]\n\t" // offset := aligned_to - aligned_end " srax %[ato], 1, %[ato]\n\t" // scale offset for instruction size of 4 " add %[ato], 40, %[ato]\n\t" // offset += 10 * instruction size - " rd %pc, %[temp]\n\t" // dispatch on scaled offset - " jmpl %[temp]+%[ato], %g0\n\t" + " rd %%pc, %[temp]\n\t" // dispatch on scaled offset + " jmpl %[temp]+%[ato], %%g0\n\t" " nop\n\t" // DISPATCH: no direct reference, but without it the store block may be elided. "3:\n\t" diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -56,7 +56,7 @@ #ifdef ASSERT static int check_nonzero(const char* xname, int x) { - assert(x != 0, err_msg("%s should be nonzero", xname)); + assert(x != 0, "%s should be nonzero", xname); return x; } #define NONZERO(x) check_nonzero(#x, x) @@ -453,7 +453,7 @@ } default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -53,6 +53,7 @@ bool is_nop() { return long_at(0) == nop_instruction(); } bool is_call() { return is_op(long_at(0), Assembler::call_op); } + bool is_call_reg() { return is_op(long_at(0), Assembler::arith_op); } bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2) && inv_rd(long_at(0)) != G0); } @@ -415,6 +416,19 @@ return call; } +class NativeCallReg: public NativeInstruction { + public: + enum Sparc_specific_constants { + instruction_size = 8, + return_address_offset = 8, + instruction_offset = 0 + }; + + address next_instruction_address() const { + return addr_at(instruction_size); + } +}; + // The NativeFarCall is an abstraction for accessing/manipulating native call-anywhere // instructions in the sparcv9 vm. Used to call native methods which may be loaded // anywhere in the address space, possibly out of reach of a call instruction. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -197,8 +197,5 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { } -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -} - void metadata_Relocation::pd_fix_value(address x) { } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -43,6 +43,9 @@ #include "compiler/compileBroker.hpp" #include "shark/sharkCompiler.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif #define __ masm-> @@ -316,7 +319,7 @@ // 8 bytes FP registers are saved by default on SPARC. bool SharedRuntime::is_wide_vector(int size) { // Note, MaxVectorSize == 8 on SPARC. - assert(size <= 8, err_msg_res("%d bytes vectors are not supported", size)); + assert(size <= 8, "%d bytes vectors are not supported", size); return size > 8; } @@ -464,7 +467,7 @@ break; default: - fatal(err_msg_res("unknown basic type %d", sig_bt[i])); + fatal("unknown basic type %d", sig_bt[i]); break; } } @@ -513,10 +516,10 @@ const VMRegPair *regs, Label& skip_fixup); void gen_i2c_adapter(int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs); + // VMReg max_arg, + int comp_args_on_stack, // VMRegStackSlots + const BasicType *sig_bt, + const VMRegPair *regs); AdapterGenerator(MacroAssembler *_masm) : masm(_masm) {} }; @@ -760,13 +763,11 @@ __ bind(L_fail); } -void AdapterGenerator::gen_i2c_adapter( - int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs) { - +void AdapterGenerator::gen_i2c_adapter(int total_args_passed, + // VMReg max_arg, + int comp_args_on_stack, // VMRegStackSlots + const BasicType *sig_bt, + const VMRegPair *regs) { // Generate an I2C adapter: adjust the I-frame to make space for the C-frame // layout. Lesp was saved by the calling I-frame and will be restored on // return. Meanwhile, outgoing arg space is all owned by the callee @@ -990,6 +991,21 @@ // Jump to the compiled code just as if compiled code was doing it. __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // check if this call should be routed towards a specific entry point + __ ld(Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), G1); + __ cmp(G0, G1); + Label no_alternative_target; + __ br(Assembler::equal, false, Assembler::pn, no_alternative_target); + __ delayed()->nop(); + + __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()), G3); + __ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); + + __ bind(no_alternative_target); + } +#endif // INCLUDE_JVMCI // 6243940 We might end up in handle_wrong_method if // the callee is deoptimized as we race thru here. If that @@ -1006,6 +1022,15 @@ __ delayed()->nop(); } +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { + AdapterGenerator agen(masm); + agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); +} + // --------------------------------------------------------------- AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, int total_args_passed, @@ -1016,9 +1041,7 @@ AdapterFingerPrint* fingerprint) { address i2c_entry = __ pc(); - AdapterGenerator agen(masm); - - agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); + gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); // ------------------------------------------------------------------------- @@ -1063,7 +1086,7 @@ } address c2i_entry = __ pc(); - + AdapterGenerator agen(masm); agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, L_skip_fixup); __ flush(); @@ -1859,7 +1882,7 @@ } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { @@ -2916,6 +2939,11 @@ pad += StackShadowPages*16 + 32; } #endif +#if INCLUDE_JVMCI + if (EnableJVMCI) { + pad += 1000; // Increase the buffer size when compiling for JVMCI + } +#endif #ifdef _LP64 CodeBuffer buffer("deopt_blob", 2100+pad, 512); #else @@ -2982,6 +3010,45 @@ __ ba(cont); __ delayed()->mov(Deoptimization::Unpack_deopt, L0deopt_mode); + +#if INCLUDE_JVMCI + Label after_fetch_unroll_info_call; + int implicit_exception_uncommon_trap_offset = 0; + int uncommon_trap_offset = 0; + + if (EnableJVMCI) { + masm->block_comment("BEGIN implicit_exception_uncommon_trap"); + implicit_exception_uncommon_trap_offset = __ offset() - start; + + __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()), O7); + __ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); + __ add(O7, -8, O7); + + uncommon_trap_offset = __ offset() - start; + + // Save everything in sight. + (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); + __ set_last_Java_frame(SP, NULL); + + __ ld(G2_thread, in_bytes(JavaThread::pending_deoptimization_offset()), O1); + __ sub(G0, 1, L1); + __ st(L1, G2_thread, in_bytes(JavaThread::pending_deoptimization_offset())); + + __ mov((int32_t)Deoptimization::Unpack_reexecute, L0deopt_mode); + __ mov(G2_thread, O0); + __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); + __ delayed()->nop(); + oop_maps->add_gc_map( __ offset()-start, map->deep_copy()); + __ get_thread(); + __ add(O7, 8, O7); + __ reset_last_Java_frame(); + + __ ba(after_fetch_unroll_info_call); + __ delayed()->nop(); // Delay slot + masm->block_comment("END implicit_exception_uncommon_trap"); + } // EnableJVMCI +#endif // INCLUDE_JVMCI + int exception_offset = __ offset() - start; // restore G2, the trampoline destroyed it @@ -3004,6 +3071,7 @@ int exception_in_tls_offset = __ offset() - start; // No need to update oop_map as each call to save_live_registers will produce identical oopmap + // Opens a new stack frame (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); // Restore G2_thread @@ -3035,7 +3103,12 @@ // Reexecute entry, similar to c2 uncommon trap // int reexecute_offset = __ offset() - start; - +#if INCLUDE_JVMCI && !defined(COMPILER1) + if (EnableJVMCI && UseJVMCICompiler) { + // JVMCI does not use this kind of deoptimization + __ should_not_reach_here(); + } +#endif // No need to update oop_map as each call to save_live_registers will produce identical oopmap (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); @@ -3059,6 +3132,11 @@ __ reset_last_Java_frame(); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + __ bind(after_fetch_unroll_info_call); + } +#endif // NOTE: we know that only O0/O1 will be reloaded by restore_result_registers // so this move will survive @@ -3124,6 +3202,12 @@ masm->flush(); _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); + _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); + } +#endif } #ifdef COMPILER2 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/sparc.ad --- a/hotspot/src/cpu/sparc/vm/sparc.ad Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/sparc.ad Thu Oct 22 11:13:08 2015 -0700 @@ -1098,7 +1098,7 @@ Register r = as_Register(ra_->get_encode(this)); CodeSection* consts_section = __ code()->consts(); int consts_size = consts_section->align_at_start(consts_section->size()); - assert(constant_table.size() == consts_size, err_msg("must be: %d == %d", constant_table.size(), consts_size)); + assert(constant_table.size() == consts_size, "must be: %d == %d", constant_table.size(), consts_size); if (UseRDPCForConstantTableBase) { // For the following RDPC logic to work correctly the consts @@ -1860,6 +1860,10 @@ return true; // Per default match rules are supported. } +const int Matcher::float_pressure(int default_pressure_threshold) { + return default_pressure_threshold; +} + int Matcher::regnum_to_fpu_offset(int regnum) { return regnum - 32; // The FP registers are in the second chunk } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -204,6 +204,20 @@ address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { address entry = __ pc(); __ get_constant_pool_cache(LcpoolCache); // load LcpoolCache +#if INCLUDE_JVMCI + // Check if we need to take lock at entry of synchronized method. + if (UseJVMCICompiler) { + Label L; + Address pending_monitor_enter_addr(G2_thread, JavaThread::pending_monitorenter_offset()); + __ ldbool(pending_monitor_enter_addr, Gtemp); // Load if pending monitor enter + __ cmp_and_br_short(Gtemp, G0, Assembler::equal, Assembler::pn, L); + // Clear flag. + __ stbool(G0, pending_monitor_enter_addr); + // Take lock. + lock_method(); + __ bind(L); + } +#endif { Label L; Address exception_addr(G2_thread, Thread::pending_exception_offset()); __ ld_ptr(exception_addr, Gtemp); // Load pending exception. @@ -349,7 +363,7 @@ // Allocate monitor and lock method (asm interpreter) // ebx - Method* // -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { __ ld(Lmethod, in_bytes(Method::access_flags_offset()), O0); // Load access flags. #ifdef ASSERT @@ -779,14 +793,14 @@ // Generate regular method entry __ bind(slow_path); - (void) generate_normal_entry(false); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); return entry; } #endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } // diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -37,9 +37,9 @@ #ifdef _LP64 // The sethi() instruction generates lots more instructions when shell // stack limit is unlimited, so that's why this is much bigger. - const static int InterpreterCodeSize = 210 * K; + const static int InterpreterCodeSize = 260 * K; #else - const static int InterpreterCodeSize = 180 * K; + const static int InterpreterCodeSize = 230 * K; #endif #endif // CPU_SPARC_VM_TEMPLATEINTERPRETER_SPARC_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -2949,12 +2949,14 @@ void TemplateTable::generate_vtable_call(Register Rrecv, Register Rindex, Register Rret) { + Register Rtemp = G4_scratch; Register Rcall = Rindex; assert_different_registers(Rcall, G5_method, Gargs, Rret); // get target Method* & entry point __ lookup_virtual_method(Rrecv, Rindex, G5_method); __ profile_arguments_type(G5_method, Rcall, Gargs, true); + __ profile_called_method(G5_method, Rtemp); __ call_from_interpreter(Rcall, Gargs, Rret); } @@ -3211,6 +3213,7 @@ assert_different_registers(Rcall, G5_method, Gargs, Rret); __ profile_arguments_type(G5_method, Rcall, Gargs, true); + __ profile_called_method(G5_method, Rscratch); __ call_from_interpreter(Rcall, Gargs, Rret); } @@ -3486,7 +3489,8 @@ Register RspecifiedKlass = O4; // Check for casting a NULL - __ br_null_short(Otos_i, Assembler::pn, is_null); + __ br_null(Otos_i, false, Assembler::pn, is_null); + __ delayed()->nop(); // Get value klass in RobjKlass __ load_klass(Otos_i, RobjKlass); // get value klass @@ -3542,7 +3546,8 @@ Register RspecifiedKlass = O4; // Check for casting a NULL - __ br_null_short(Otos_i, Assembler::pt, is_null); + __ br_null(Otos_i, false, Assembler::pt, is_null); + __ delayed()->nop(); // Get value klass in RobjKlass __ load_klass(Otos_i, RobjKlass); // get value klass diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/vmStructs_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -37,10 +37,11 @@ /******************************/ \ /* JavaFrameAnchor */ \ /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _flags, int) + volatile_nonstatic_field(JavaFrameAnchor, _flags, int) \ + static_field(VM_Version, _features, int) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) - +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_toplevel_type(VM_Version) #define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ /******************************/ \ @@ -78,7 +79,11 @@ declare_c2_constant(R_G4_num) \ declare_c2_constant(R_G5_num) \ declare_c2_constant(R_G6_num) \ - declare_c2_constant(R_G7_num) + declare_c2_constant(R_G7_num) \ + declare_constant(VM_Version::vis1_instructions_m) \ + declare_constant(VM_Version::vis2_instructions_m) \ + declare_constant(VM_Version::vis3_instructions_m) \ + declare_constant(VM_Version::cbcond_instructions_m) #define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -40,10 +40,6 @@ PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes(); PrefetchFieldsAhead = prefetch_fields_ahead(); - assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 1, "invalid value"); - if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0; - if( AllocatePrefetchInstr > 1 ) AllocatePrefetchInstr = 0; - // Allocation prefetch settings intx cache_line_size = prefetch_data_size(); if( cache_line_size > AllocatePrefetchStepSize ) @@ -59,13 +55,6 @@ AllocatePrefetchDistance = allocate_prefetch_distance(); AllocatePrefetchStyle = allocate_prefetch_style(); - assert((AllocatePrefetchDistance % AllocatePrefetchStepSize) == 0 && - (AllocatePrefetchDistance > 0), "invalid value"); - if ((AllocatePrefetchDistance % AllocatePrefetchStepSize) != 0 || - (AllocatePrefetchDistance <= 0)) { - AllocatePrefetchDistance = AllocatePrefetchStepSize; - } - if (AllocatePrefetchStyle == 3 && !has_blk_init()) { warning("BIS instructions are not available on this CPU"); FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1); @@ -73,13 +62,6 @@ guarantee(VM_Version::has_v9(), "only SPARC v9 is supported"); - assert(ArraycopySrcPrefetchDistance < 4096, "invalid value"); - if (ArraycopySrcPrefetchDistance >= 4096) - ArraycopySrcPrefetchDistance = 4064; - assert(ArraycopyDstPrefetchDistance < 4096, "invalid value"); - if (ArraycopyDstPrefetchDistance >= 4096) - ArraycopyDstPrefetchDistance = 4064; - UseSSE = 0; // Only on x86 and x64 _supports_cx8 = has_v9(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,6 +29,7 @@ #include "runtime/vm_version.hpp" class VM_Version: public Abstract_VM_Version { + friend class VMStructs; protected: enum Feature_Flag { v8_instructions = 0, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/assembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -733,11 +733,11 @@ // these asserts are somewhat nonsensical #ifndef _LP64 assert(which == imm_operand || which == disp32_operand, - err_msg("which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip))); + "which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip)); #else assert((which == call32_operand || which == imm_operand) && is_64bit || which == narrow_oop_operand && !is_64bit, - err_msg("which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip))); + "which %d is_64_bit %d ip " INTPTR_FORMAT, which, is_64bit, p2i(ip)); #endif // _LP64 return ip; @@ -770,6 +770,7 @@ case 0x55: // andnps case 0x56: // orps case 0x57: // xorps + case 0x59: //mulpd case 0x6E: // movd case 0x7E: // movd case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush @@ -877,21 +878,35 @@ // Check second byte NOT_LP64(assert((0xC0 & *ip) == 0xC0, "shouldn't have LDS and LES instructions")); + int vex_opcode; // First byte if ((0xFF & *inst) == VEX_3bytes) { + vex_opcode = VEX_OPCODE_MASK & *ip; ip++; // third byte is_64bit = ((VEX_W & *ip) == VEX_W); + } else { + vex_opcode = VEX_OPCODE_0F; } ip++; // opcode // To find the end of instruction (which == end_pc_operand). - switch (0xFF & *ip) { - case 0x61: // pcmpestri r, r/a, #8 - case 0x70: // pshufd r, r/a, #8 - case 0x73: // psrldq r, #8 - tail_size = 1; // the imm8 - break; - default: - break; + switch (vex_opcode) { + case VEX_OPCODE_0F: + switch (0xFF & *ip) { + case 0x70: // pshufd r, r/a, #8 + case 0x71: // ps[rl|ra|ll]w r, #8 + case 0x72: // ps[rl|ra|ll]d r, #8 + case 0x73: // ps[rl|ra|ll]q r, #8 + case 0xC2: // cmp[ps|pd|ss|sd] r, r, r/a, #8 + case 0xC4: // pinsrw r, r, r/a, #8 + case 0xC5: // pextrw r/a, r, #8 + case 0xC6: // shufp[s|d] r, r, r/a, #8 + tail_size = 1; // the imm8 + break; + } + break; + case VEX_OPCODE_0F_3A: + tail_size = 1; + break; } ip++; // skip opcode debug_only(has_disp32 = true); // has both kinds of operands! @@ -1604,6 +1619,85 @@ emit_int8((unsigned char)0xA2); } +// Opcode / Instruction Op / En 64 - Bit Mode Compat / Leg Mode Description Implemented +// F2 0F 38 F0 / r CRC32 r32, r / m8 RM Valid Valid Accumulate CRC32 on r / m8. v +// F2 REX 0F 38 F0 / r CRC32 r32, r / m8* RM Valid N.E. Accumulate CRC32 on r / m8. - +// F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E. Accumulate CRC32 on r / m8. - +// +// F2 0F 38 F1 / r CRC32 r32, r / m16 RM Valid Valid Accumulate CRC32 on r / m16. v +// +// F2 0F 38 F1 / r CRC32 r32, r / m32 RM Valid Valid Accumulate CRC32 on r / m32. v +// +// F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E. Accumulate CRC32 on r / m64. v +void Assembler::crc32(Register crc, Register v, int8_t sizeInBytes) { + assert(VM_Version::supports_sse4_2(), ""); + int8_t w = 0x01; + Prefix p = Prefix_EMPTY; + + emit_int8((int8_t)0xF2); + switch (sizeInBytes) { + case 1: + w = 0; + break; + case 2: + case 4: + break; + LP64_ONLY(case 8:) + // This instruction is not valid in 32 bits + // Note: + // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + // + // Page B - 72 Vol. 2C says + // qwreg2 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : 11 qwreg1 qwreg2 + // mem64 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : mod qwreg r / m + // F0!!! + // while 3 - 208 Vol. 2A + // F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E.Accumulate CRC32 on r / m64. + // + // the 0 on a last bit is reserved for a different flavor of this instruction : + // F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E.Accumulate CRC32 on r / m8. + p = REX_W; + break; + default: + assert(0, "Unsupported value for a sizeInBytes argument"); + break; + } + LP64_ONLY(prefix(crc, v, p);) + emit_int8((int8_t)0x0F); + emit_int8(0x38); + emit_int8((int8_t)(0xF0 | w)); + emit_int8(0xC0 | ((crc->encoding() & 0x7) << 3) | (v->encoding() & 7)); +} + +void Assembler::crc32(Register crc, Address adr, int8_t sizeInBytes) { + assert(VM_Version::supports_sse4_2(), ""); + InstructionMark im(this); + int8_t w = 0x01; + Prefix p = Prefix_EMPTY; + + emit_int8((int8_t)0xF2); + switch (sizeInBytes) { + case 1: + w = 0; + break; + case 2: + case 4: + break; + LP64_ONLY(case 8:) + // This instruction is not valid in 32 bits + p = REX_W; + break; + default: + assert(0, "Unsupported value for a sizeInBytes argument"); + break; + } + LP64_ONLY(prefix(crc, adr, p);) + emit_int8((int8_t)0x0F); + emit_int8(0x38); + emit_int8((int8_t)(0xF0 | w)); + emit_operand(crc, adr); +} + void Assembler::cvtdq2pd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); emit_simd_arith_nonds(0xE6, dst, src, VEX_SIMD_F3, /* no_mask_reg */ false, /* legacy_mode */ true); @@ -2399,7 +2493,7 @@ void Assembler::movsbl(Register dst, Register src) { // movsxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), src->encoding(), true); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); emit_int8(0x0F); emit_int8((unsigned char)0xBE); emit_int8((unsigned char)(0xC0 | encode)); @@ -2516,7 +2610,7 @@ void Assembler::movzbl(Register dst, Register src) { // movzxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), src->encoding(), true); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); emit_int8(0x0F); emit_int8((unsigned char)0xB6); emit_int8(0xC0 | encode); @@ -2951,6 +3045,15 @@ emit_int8(imm8); } +void Assembler::pextrw(Register dst, XMMRegister src, int imm8) { + assert(VM_Version::supports_sse2(), ""); + int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_66, /* no_mask_reg */ true, + VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + emit_int8((unsigned char)0xC5); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8(imm8); +} + void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, /* no_mask_reg */ true, @@ -2969,6 +3072,15 @@ emit_int8(imm8); } +void Assembler::pinsrw(XMMRegister dst, Register src, int imm8) { + assert(VM_Version::supports_sse2(), ""); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, /* no_mask_reg */ true, + VEX_OPCODE_0F, /* rex_w */ false, AVX_128bit, /* legacy_mode */ _legacy_mode_bw); + emit_int8((unsigned char)0xC4); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8(imm8); +} + void Assembler::pmovzxbw(XMMRegister dst, Address src) { assert(VM_Version::supports_sse4_1(), ""); if (VM_Version::supports_evex()) { @@ -3984,6 +4096,16 @@ } } +void Assembler::mulpd(XMMRegister dst, Address src) { + _instruction_uses_vl = true; + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + if (VM_Version::supports_evex()) { + emit_simd_arith_q(0x59, dst, src, VEX_SIMD_66); + } else { + emit_simd_arith(0x59, dst, src, VEX_SIMD_66); + } +} + void Assembler::mulps(XMMRegister dst, XMMRegister src) { _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); @@ -4172,6 +4294,26 @@ emit_vex_arith(0x54, dst, nds, src, VEX_SIMD_NONE, vector_len, /* no_mask_reg */ false, /* legacy_mode */ _legacy_mode_dq); } +void Assembler::unpckhpd(XMMRegister dst, XMMRegister src) { + _instruction_uses_vl = true; + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + if (VM_Version::supports_evex()) { + emit_simd_arith_q(0x15, dst, src, VEX_SIMD_66); + } else { + emit_simd_arith(0x15, dst, src, VEX_SIMD_66); + } +} + +void Assembler::unpcklpd(XMMRegister dst, XMMRegister src) { + _instruction_uses_vl = true; + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + if (VM_Version::supports_evex()) { + emit_simd_arith_q(0x14, dst, src, VEX_SIMD_66); + } else { + emit_simd_arith(0x14, dst, src, VEX_SIMD_66); + } +} + void Assembler::xorpd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); if (VM_Version::supports_avx512dq()) { @@ -4792,8 +4934,9 @@ } -// AND packed integers +// logical operations packed integers void Assembler::pand(XMMRegister dst, XMMRegister src) { + _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); emit_simd_arith(0xDB, dst, src, VEX_SIMD_66); } @@ -4814,6 +4957,17 @@ emit_vex_arith(0xDB, dst, nds, src, VEX_SIMD_66, vector_len); } +void Assembler::pandn(XMMRegister dst, XMMRegister src) { + _instruction_uses_vl = true; + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + if (VM_Version::supports_evex()) { + emit_simd_arith_q(0xDF, dst, src, VEX_SIMD_66); + } + else { + emit_simd_arith(0xDF, dst, src, VEX_SIMD_66); + } +} + void Assembler::por(XMMRegister dst, XMMRegister src) { _instruction_uses_vl = true; NOT_LP64(assert(VM_Version::supports_sse2(), "")); @@ -6223,6 +6377,14 @@ emit_int8((unsigned char)(0xC0 | src->encoding() << 3 | dst->encoding())); } +// 0F A4 / r ib +void Assembler::shldl(Register dst, Register src, int8_t imm8) { + emit_int8(0x0F); + emit_int8((unsigned char)0xA4); + emit_int8((unsigned char)(0xC0 | src->encoding() << 3 | dst->encoding())); + emit_int8(imm8); +} + void Assembler::shrdl(Register dst, Register src) { emit_int8(0x0F); emit_int8((unsigned char)0xAD); @@ -6362,12 +6524,12 @@ return reg_enc; } -int Assembler::prefix_and_encode(int dst_enc, int src_enc, bool byteinst) { +int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { if (dst_enc < 8) { if (src_enc >= 8) { prefix(REX_B); src_enc -= 8; - } else if (byteinst && src_enc >= 4) { + } else if ((src_is_byte && src_enc >= 4) || (dst_is_byte && dst_enc >= 4)) { prefix(REX); } } else { @@ -6408,6 +6570,40 @@ } } +void Assembler::prefix(Register dst, Register src, Prefix p) { + if (src->encoding() >= 8) { + p = (Prefix)(p | REX_B); + } + if (dst->encoding() >= 8) { + p = (Prefix)( p | REX_R); + } + if (p != Prefix_EMPTY) { + // do not generate an empty prefix + prefix(p); + } +} + +void Assembler::prefix(Register dst, Address adr, Prefix p) { + if (adr.base_needs_rex()) { + if (adr.index_needs_rex()) { + assert(false, "prefix(Register dst, Address adr, Prefix p) does not support handling of an X"); + } else { + prefix(REX_B); + } + } else { + if (adr.index_needs_rex()) { + assert(false, "prefix(Register dst, Address adr, Prefix p) does not support handling of an X"); + } + } + if (dst->encoding() >= 8) { + p = (Prefix)(p | REX_R); + } + if (p != Prefix_EMPTY) { + // do not generate an empty prefix + prefix(p); + } +} + void Assembler::prefix(Address adr) { if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/assembler_x86.hpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -506,7 +506,8 @@ VEX_3bytes = 0xC4, VEX_2bytes = 0xC5, - EVEX_4bytes = 0x62 + EVEX_4bytes = 0x62, + Prefix_EMPTY = 0x0 }; enum VexPrefix { @@ -535,7 +536,8 @@ VEX_OPCODE_NONE = 0x0, VEX_OPCODE_0F = 0x1, VEX_OPCODE_0F_38 = 0x2, - VEX_OPCODE_0F_3A = 0x3 + VEX_OPCODE_0F_3A = 0x3, + VEX_OPCODE_MASK = 0x1F }; enum AvxVectorLen { @@ -611,10 +613,15 @@ int prefix_and_encode(int reg_enc, bool byteinst = false); int prefixq_and_encode(int reg_enc); - int prefix_and_encode(int dst_enc, int src_enc, bool byteinst = false); + int prefix_and_encode(int dst_enc, int src_enc) { + return prefix_and_encode(dst_enc, false, src_enc, false); + } + int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte); int prefixq_and_encode(int dst_enc, int src_enc); void prefix(Register reg); + void prefix(Register dst, Register src, Prefix p); + void prefix(Register dst, Address adr, Prefix p); void prefix(Address adr); void prefixq(Address adr); @@ -1177,6 +1184,10 @@ // Identify processor type and features void cpuid(); + // CRC32C + void crc32(Register crc, Register v, int8_t sizeInBytes); + void crc32(Register crc, Address adr, int8_t sizeInBytes); + // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value void cvtsd2ss(XMMRegister dst, XMMRegister src); void cvtsd2ss(XMMRegister dst, Address src); @@ -1672,10 +1683,14 @@ // SSE 4.1 extract void pextrd(Register dst, XMMRegister src, int imm8); void pextrq(Register dst, XMMRegister src, int imm8); + // SSE 2 extract + void pextrw(Register dst, XMMRegister src, int imm8); // SSE 4.1 insert void pinsrd(XMMRegister dst, Register src, int imm8); void pinsrq(XMMRegister dst, Register src, int imm8); + // SSE 2 insert + void pinsrw(XMMRegister dst, Register src, int imm8); // SSE4.1 packed move void pmovzxbw(XMMRegister dst, XMMRegister src); @@ -1783,6 +1798,7 @@ void setb(Condition cc, Register dst); void shldl(Register dst, Register src); + void shldl(Register dst, Register src, int8_t imm8); void shll(Register dst, int imm8); void shll(Register dst); @@ -1925,6 +1941,7 @@ // Multiply Packed Floating-Point Values void mulpd(XMMRegister dst, XMMRegister src); + void mulpd(XMMRegister dst, Address src); void mulps(XMMRegister dst, XMMRegister src); void vmulpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vmulps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); @@ -1951,6 +1968,9 @@ void vandpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void vandps(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + void unpckhpd(XMMRegister dst, XMMRegister src); + void unpcklpd(XMMRegister dst, XMMRegister src); + // Bitwise Logical XOR of Packed Floating-Point Values void xorpd(XMMRegister dst, XMMRegister src); void xorps(XMMRegister dst, XMMRegister src); @@ -2046,6 +2066,9 @@ void vpand(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vpand(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + // Andn packed integers + void pandn(XMMRegister dst, XMMRegister src); + // Or packed integers void por(XMMRegister dst, XMMRegister src); void vpor(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/assembler_x86.inline.hpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -33,10 +33,12 @@ inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst) { return reg_enc; } inline int Assembler::prefixq_and_encode(int reg_enc) { return reg_enc; } -inline int Assembler::prefix_and_encode(int dst_enc, int src_enc, bool byteinst) { return dst_enc << 3 | src_enc; } +inline int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { return dst_enc << 3 | src_enc; } inline int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { return dst_enc << 3 | src_enc; } inline void Assembler::prefix(Register reg) {} +inline void Assembler::prefix(Register dst, Register src, Prefix p) {} +inline void Assembler::prefix(Register dst, Address adr, Prefix p) {} inline void Assembler::prefix(Address adr) {} inline void Assembler::prefixq(Address adr) {} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -2457,9 +2457,6 @@ // Should consider not saving rbx, if not necessary __ trigfunc('t', op->as_Op2()->fpu_stack_size()); break; - case lir_exp : - __ exp_with_fallback(op->as_Op2()->fpu_stack_size()); - break; case lir_pow : __ pow_with_fallback(op->as_Op2()->fpu_stack_size()); break; @@ -2684,7 +2681,7 @@ #endif // _LP64 } } else { - fatal(err_msg("unexpected type: %s", basictype_to_str(c->type()))); + fatal("unexpected type: %s", basictype_to_str(c->type())); } // cpu register - address } else if (opr2->is_address()) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -808,6 +808,12 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { assert(x->number_of_arguments() == 1 || (x->number_of_arguments() == 2 && x->id() == vmIntrinsics::_dpow), "wrong type"); + + if (x->id() == vmIntrinsics::_dexp) { + do_ExpIntrinsic(x); + return; + } + LIRItem value(x->argument_at(0), this); bool use_fpu = false; @@ -818,7 +824,6 @@ case vmIntrinsics::_dtan: case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: - case vmIntrinsics::_dexp: case vmIntrinsics::_dpow: use_fpu = true; } @@ -870,7 +875,6 @@ case vmIntrinsics::_dtan: __ tan (calc_input, calc_result, tmp1, tmp2); break; case vmIntrinsics::_dlog: __ log (calc_input, calc_result, tmp1); break; case vmIntrinsics::_dlog10: __ log10(calc_input, calc_result, tmp1); break; - case vmIntrinsics::_dexp: __ exp (calc_input, calc_result, tmp1, tmp2, FrameMap::rax_opr, FrameMap::rcx_opr, FrameMap::rdx_opr); break; case vmIntrinsics::_dpow: __ pow (calc_input, calc_input2, calc_result, tmp1, tmp2, FrameMap::rax_opr, FrameMap::rcx_opr, FrameMap::rdx_opr); break; default: ShouldNotReachHere(); } @@ -880,6 +884,32 @@ } } +void LIRGenerator::do_ExpIntrinsic(Intrinsic* x) { + LIRItem value(x->argument_at(0), this); + value.set_destroys_register(); + + LIR_Opr calc_result = rlock_result(x); + LIR_Opr result_reg = result_register_for(x->type()); + + BasicTypeList signature(1); + signature.append(T_DOUBLE); + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + + value.load_item_force(cc->at(0)); + +#ifndef _LP64 + LIR_Opr tmp = FrameMap::fpu0_double_opr; + result_reg = tmp; + if (VM_Version::supports_sse2()) { + __ call_runtime_leaf(StubRoutines::dexp(), getThreadTemp(), result_reg, cc->args()); + } else { + __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dexp), getThreadTemp(), result_reg, cc->args()); + } +#else + __ call_runtime_leaf(StubRoutines::dexp(), getThreadTemp(), result_reg, cc->args()); +#endif + __ move(result_reg, calc_result); +} void LIRGenerator::do_ArrayCopy(Intrinsic* x) { assert(x->number_of_arguments() == 5, "wrong type"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp --- a/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/c1_LinearScan_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -814,8 +814,7 @@ case lir_tan: case lir_sin: - case lir_cos: - case lir_exp: { + case lir_cos: { // sin, cos and exp need two temporary fpu stack slots, so there are two temporary // registers (stored in right and temp of the operation). // the stack allocator must guarantee that the stack slots are really free, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/c2_globals_x86.hpp --- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -48,11 +48,11 @@ define_pd_global(intx, OnStackReplacePercentage, 140); define_pd_global(intx, ConditionalMoveLimit, 3); -define_pd_global(intx, FLOATPRESSURE, 6); define_pd_global(intx, FreqInlineSize, 325); define_pd_global(intx, MinJumpTableSize, 10); #ifdef AMD64 define_pd_global(intx, INTPRESSURE, 13); +define_pd_global(intx, FLOATPRESSURE, 14); define_pd_global(intx, InteriorEntryAlignment, 16); define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, LoopUnrollLimit, 60); @@ -64,6 +64,7 @@ define_pd_global(uint64_t, MaxRAM, 128ULL*G); #else define_pd_global(intx, INTPRESSURE, 6); +define_pd_global(intx, FLOATPRESSURE, 6); define_pd_global(intx, InteriorEntryAlignment, 4); define_pd_global(size_t, NewSizeThreadIncrease, 4*K); define_pd_global(intx, LoopUnrollLimit, 50); // Design center runs on 1.3.1 @@ -82,6 +83,7 @@ define_pd_global(bool, UseCISCSpill, true); define_pd_global(bool, OptoScheduling, false); define_pd_global(bool, OptoBundling, false); +define_pd_global(bool, OptoRegScheduling, true); define_pd_global(intx, ReservedCodeCacheSize, 48*M); define_pd_global(intx, NonProfiledCodeHeapSize, 21*M); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/compiledIC_x86.cpp --- a/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/compiledIC_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -50,13 +50,15 @@ // ---------------------------------------------------------------------------- #define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf) { +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { // Stub is fixed up when the corresponding call is converted from // calling compiled code to calling interpreted code. // movq rbx, 0 // jmp -5 # to self - address mark = cbuf.insts_mark(); // Get mark within main instrs section. + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } // 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. @@ -73,6 +75,8 @@ // This is recognized as unresolved by relocs/nativeinst/ic code. __ jump(RuntimeAddress(__ pc())); + assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size"); + // Update current stubs pointer and restore insts_end. __ end_a_stub(); return base; @@ -104,10 +108,15 @@ NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); - assert(method_holder->data() == 0 || method_holder->data() == (intptr_t)callee(), +#ifdef ASSERT + // read the value once + intptr_t data = method_holder->data(); + address destination = jump->jump_destination(); + assert(data == 0 || data == (intptr_t)callee(), "a) MT-unsafe modification of inline cache"); - assert(jump->jump_destination() == (address)-1 || jump->jump_destination() == entry, + assert(destination == (address)-1 || destination == entry, "b) MT-unsafe modification of inline cache"); +#endif // Update stub. method_holder->set_data((intptr_t)callee()); @@ -124,11 +133,12 @@ assert(stub != NULL, "stub not found"); // Creation also verifies the object. NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); method_holder->set_data(0); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); jump->set_jump_destination((address)-1); } + //----------------------------------------------------------------------------- // Non-product mode code #ifndef PRODUCT @@ -150,5 +160,4 @@ // Verify state. assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); } - #endif // !PRODUCT diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp --- a/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/cppInterpreterGenerator_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,6 +29,7 @@ void generate_more_monitors(); void generate_deopt_handling(); + void lock_method(void); address generate_interpreter_frame_manager(bool synchronized); // C++ interpreter only void generate_compute_interpreter_state(const Register state, const Register prev_state, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp --- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -741,7 +741,7 @@ // Find preallocated monitor and lock method (C++ interpreter) // rbx - Method* // -void InterpreterGenerator::lock_method(void) { +void CppInterpreterGenerator::lock_method() { // assumes state == rsi/r13 == pointer to current interpreterState // minimally destroys rax, rdx|c_rarg1, rdi // @@ -807,7 +807,7 @@ // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } // diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/crc32c.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/x86/vm/crc32c.h Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +* or visit www.oracle.com if you need additional information or have any +* questions. +* +*/ + +enum { + // S. Gueron / Information Processing Letters 112 (2012) 184 + // shows than anything above 6K and below 32K is a good choice + // 32K does not deliver any further performance gains + // 6K=8*256 (*3 as we compute 3 blocks together) + // + // Thus selecting the smallest value so it could apply to the largest number + // of buffer sizes. + CRC32C_HIGH = 8 * 256, + + // empirical + // based on ubench study using methodology described in + // V. Gopal et al. / Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction April 2011 8 + // + // arbitrary value between 27 and 256 + CRC32C_MIDDLE = 8 * 86, + + // V. Gopal et al. / Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction April 2011 9 + // shows that 240 and 1024 are equally good choices as the 216==8*27 + // + // Selecting the smallest value which resulted in a significant performance improvement over + // sequential version + CRC32C_LOW = 8 * 27, + + CRC32C_NUM_ChunkSizeInBytes = 3, + + // We need to compute powers of 64N and 128N for each "chunk" size + CRC32C_NUM_PRECOMPUTED_CONSTANTS = ( 2 * CRC32C_NUM_ChunkSizeInBytes ) +}; +// Notes: +// 1. Why we need to choose a "chunk" approach? +// Overhead of computing a powers and powers of for an arbitrary buffer of size N is significant +// (implementation approaches a library perf.) +// 2. Why only 3 "chunks"? +// Performance experiments results showed that a HIGH+LOW was not delivering a stable speedup +// curve. +// +// Disclaimer: +// If you ever decide to increase/decrease number of "chunks" be sure to modify +// a) constants table generation (hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp) +// b) constant fetch from that table (macroAssembler_x86.cpp) +// c) unrolled for loop (macroAssembler_x86.cpp) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/frame_x86.cpp --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -48,8 +48,6 @@ } #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Profiling/safepoint support bool frame::safe_for_sender(JavaThread *thread) { @@ -280,7 +278,7 @@ address* pc_addr = &(((address*) sp())[-1]); if (TracePcPatching) { tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]", - pc_addr, *pc_addr, pc); + p2i(pc_addr), p2i(*pc_addr), p2i(pc)); } // Either the return address is the original one or we are going to // patch in the same address that's already there. @@ -458,11 +456,11 @@ // This is the sp before any possible extension (adapter/locals). intptr_t* unextended_sp = interpreter_frame_sender_sp(); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (map->update_map()) { update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset)); } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI return frame(sender_sp, unextended_sp, link(), sender_pc()); } @@ -683,10 +681,19 @@ DESCRIBE_FP_OFFSET(interpreter_frame_locals); DESCRIBE_FP_OFFSET(interpreter_frame_bcp); DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp); -#endif +#ifdef AMD64 + } else if (is_entry_frame()) { + // This could be more descriptive if we use the enum in + // stubGenerator to map to real names but it's most important to + // claim these frame slots so the error checking works. + for (int i = 0; i < entry_frame_after_call_words; i++) { + values.describe(frame_no, fp() - i, err_msg("call_stub word fp - %d", i)); + } +#endif // AMD64 } +#endif } -#endif +#endif // !PRODUCT intptr_t *frame::initial_deoptimization_info() { // used to reset the saved FP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/frame_x86.inline.hpp --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -78,7 +78,11 @@ assert(((nmethod*)_cb)->insts_contains(_pc), "original PC must be in nmethod"); _deopt_state = is_deoptimized; } else { - _deopt_state = not_deoptimized; + if (_cb->is_deoptimization_stub()) { + _deopt_state = is_deoptimized; + } else { + _deopt_state = not_deoptimized; + } } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/globals_x86.hpp --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -46,7 +46,7 @@ // the the vep is aligned at CodeEntryAlignment whereas c2 only aligns // the uep and the vep doesn't get real alignment but just slops on by // only assured that the entry instruction meets the 5 byte size requirement. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI define_pd_global(intx, CodeEntryAlignment, 32); #else define_pd_global(intx, CodeEntryAlignment, 16); @@ -91,6 +91,7 @@ \ product(intx, UseAVX, 99, \ "Highest supported AVX instructions set on x86/x64") \ + range(0, 99) \ \ product(bool, UseCLMUL, false, \ "Control whether CLMUL instructions can be used on x86/x64") \ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/interp_masm_x86.cpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -40,6 +40,11 @@ // Implementation of InterpreterMacroAssembler +void InterpreterMacroAssembler::jump_to_entry(address entry) { + assert(entry, "Entry must have been generated by now"); + jump(RuntimeAddress(entry)); +} + #ifndef CC_INTERP void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { Label update, next, none; @@ -1497,13 +1502,39 @@ bind(skip_receiver_profile); // The method data pointer needs to be updated to reflect the new target. +#if INCLUDE_JVMCI + if (MethodProfileWidth == 0) { + update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); + } +#else // INCLUDE_JVMCI update_mdp_by_constant(mdp, in_bytes(VirtualCallData:: virtual_call_data_size())); +#endif // INCLUDE_JVMCI bind(profile_continue); } } +#if INCLUDE_JVMCI +void InterpreterMacroAssembler::profile_called_method(Register method, Register mdp, Register reg2) { + assert_different_registers(method, mdp, reg2); + if (ProfileInterpreter && MethodProfileWidth > 0) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + Label done; + record_item_in_profile_helper(method, mdp, reg2, 0, done, MethodProfileWidth, + &VirtualCallData::method_offset, &VirtualCallData::method_count_offset, in_bytes(VirtualCallData::nonprofiled_receiver_count_offset())); + bind(done); + + update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); + bind(profile_continue); + } +} +#endif // INCLUDE_JVMCI + // This routine creates a state machine for updating the multi-row // type profile at a virtual call site (or other type-sensitive bytecode). // The machine visits each row (of receiver/count) until the receiver type @@ -1523,14 +1554,36 @@ if (is_virtual_call) { increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); } - return; - } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + increment_mdp_data_at(mdp, in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset())); + } +#endif // INCLUDE_JVMCI + } else { + int non_profiled_offset = -1; + if (is_virtual_call) { + non_profiled_offset = in_bytes(CounterData::count_offset()); + } +#if INCLUDE_JVMCI + else if (EnableJVMCI) { + non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()); + } +#endif // INCLUDE_JVMCI - int last_row = VirtualCallData::row_limit() - 1; + record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth, + &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); + } +} + +void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, Register mdp, + Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset) { + int last_row = total_rows - 1; assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the receiver and for null. + // Test this row for both the item and for null. // Take any of three different outcomes: - // 1. found receiver => increment count and goto done + // 1. found item => increment count and goto done // 2. found null => keep looking for case 1, maybe allocate this cell // 3. found something else => keep looking for cases 1 and 2 // Case 3 is handled by a recursive call. @@ -1538,30 +1591,30 @@ Label next_test; bool test_for_null_also = (row == start_row); - // See if the receiver is receiver[n]. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); - test_mdp_data_at(mdp, recvr_offset, receiver, + // See if the item is item[n]. + int item_offset = in_bytes(item_offset_fn(row)); + test_mdp_data_at(mdp, item_offset, item, (test_for_null_also ? reg2 : noreg), next_test); - // (Reg2 now contains the receiver from the CallData.) + // (Reg2 now contains the item from the CallData.) - // The receiver is receiver[n]. Increment count[n]. - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); + // The item is item[n]. Increment count[n]. + int count_offset = in_bytes(item_count_offset_fn(row)); increment_mdp_data_at(mdp, count_offset); jmp(done); bind(next_test); if (test_for_null_also) { Label found_null; - // Failed the equality check on receiver[n]... Test for null. + // Failed the equality check on item[n]... Test for null. testptr(reg2, reg2); if (start_row == last_row) { // The only thing left to do is handle the null case. - if (is_virtual_call) { + if (non_profiled_offset >= 0) { jccb(Assembler::zero, found_null); - // Receiver did not match any saved receiver and there is no empty row for it. + // Item did not match any saved item and there is no empty row for it. // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + increment_mdp_data_at(mdp, non_profiled_offset); jmp(done); bind(found_null); } else { @@ -1573,21 +1626,22 @@ jcc(Assembler::zero, found_null); // Put all the "Case 3" tests here. - record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); + record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows, + item_offset_fn, item_count_offset_fn, non_profiled_offset); - // Found a null. Keep searching for a matching receiver, + // Found a null. Keep searching for a matching item, // but remember that this is an empty (unused) slot. bind(found_null); } } - // In the fall-through case, we found no matching receiver, but we - // observed the receiver[start_row] is NULL. + // In the fall-through case, we found no matching item, but we + // observed the item[start_row] is NULL. - // Fill in the receiver field and increment the count. - int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); - set_mdp_data_at(mdp, recvr_offset, receiver); - int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); + // Fill in the item field and increment the count. + int item_offset = in_bytes(item_offset_fn(start_row)); + set_mdp_data_at(mdp, item_offset, item); + int count_offset = in_bytes(item_count_offset_fn(start_row)); movl(reg2, DataLayout::counter_increment); set_mdp_data_at(mdp, count_offset, reg2); if (start_row > 0) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/interp_masm_x86.hpp --- a/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/interp_masm_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -32,6 +32,7 @@ // This file specializes the assember with interpreter-specific macros +typedef ByteSize (*OffsetFunction)(uint); class InterpreterMacroAssembler: public MacroAssembler { @@ -60,6 +61,8 @@ _locals_register(LP64_ONLY(r14) NOT_LP64(rdi)), _bcp_register(LP64_ONLY(r13) NOT_LP64(rsi)) {} + void jump_to_entry(address entry); + void load_earlyret_value(TosState state); #ifdef CC_INTERP @@ -249,6 +252,10 @@ void record_klass_in_profile_helper(Register receiver, Register mdp, Register reg2, int start_row, Label& done, bool is_virtual_call); + void record_item_in_profile_helper(Register item, Register mdp, + Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset); void update_mdp_by_offset(Register mdp_in, int offset_of_offset); void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); @@ -262,6 +269,7 @@ void profile_virtual_call(Register receiver, Register mdp, Register scratch2, bool receiver_can_be_null = false); + void profile_called_method(Register method, Register mdp, Register reg2) NOT_JVMCI_RETURN; void profile_ret(Register return_bci, Register mdp); void profile_null_seen(Register mdp); void profile_typecheck(Register mdp, Register klass, Register scratch); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp --- a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,17 +31,6 @@ #define __ _masm-> -// Jump into normal path for accessor and empty entry to jump to normal entry -// The "fast" optimization don't update compilation count therefore can disable inlining -// for these functions that should be inlined. -address InterpreterGenerator::generate_jump_to_normal_entry(void) { - address entry_point = __ pc(); - - assert(Interpreter::entry_for_kind(Interpreter::zerolocals) != NULL, "should already be generated"); - __ jump(RuntimeAddress(Interpreter::entry_for_kind(Interpreter::zerolocals))); - return entry_point; -} - // Abstract method entry // Attempt to execute abstract method. Throw exception address InterpreterGenerator::generate_abstract_entry(void) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp --- a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,19 +36,18 @@ address generate_native_entry(bool synchronized); address generate_abstract_entry(void); address generate_math_entry(AbstractInterpreter::MethodKind kind); - address generate_jump_to_normal_entry(void); - address generate_accessor_entry(void) { return generate_jump_to_normal_entry(); } - address generate_empty_entry(void) { return generate_jump_to_normal_entry(); } + address generate_accessor_entry(void) { return NULL; } + address generate_empty_entry(void) { return NULL; } address generate_Reference_get_entry(); address generate_CRC32_update_entry(); address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind); + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind); #ifndef _LP64 address generate_Float_intBitsToFloat_entry(); address generate_Float_floatToRawIntBits_entry(); address generate_Double_longBitsToDouble_entry(); address generate_Double_doubleToRawLongBits_entry(); #endif - void lock_method(void); void generate_stack_overflow_check(void); void generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -151,11 +151,15 @@ __ pop_fTOS(); break; case Interpreter::java_lang_math_exp: - __ exp_with_fallback(0); - // Store to stack to convert 80bit precision back to 64bits - __ push_fTOS(); - __ pop_fTOS(); - break; + __ subptr(rsp, 2*wordSize); + __ fstp_d(Address(rsp, 0)); + if (VM_Version::supports_sse2()) { + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dexp()))); + } else { + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::dexp))); + } + __ addptr(rsp, 2*wordSize); + break; default : ShouldNotReachHere(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -52,8 +52,6 @@ #define __ _masm-> -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef _WIN64 address AbstractInterpreterGenerator::generate_slow_signature_handler() { address entry = __ pc(); @@ -252,6 +250,9 @@ if (kind == Interpreter::java_lang_math_sqrt) { __ sqrtsd(xmm0, Address(rsp, wordSize)); + } else if (kind == Interpreter::java_lang_math_exp) { + __ movdbl(xmm0, Address(rsp, wordSize)); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dexp()))); } else { __ fld_d(Address(rsp, wordSize)); switch (kind) { @@ -278,9 +279,6 @@ // empty stack slot) __ pow_with_fallback(0); break; - case Interpreter::java_lang_math_exp: - __ exp_with_fallback(0); - break; default : ShouldNotReachHere(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/x86/vm/jvmciCodeInstaller_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "compiler/disassembler.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/sharedRuntime.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "asm/register.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/vmreg.hpp" +#include "vmreg_x86.inline.hpp" + +jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) { + if (inst->is_call() || inst->is_jump()) { + assert(NativeCall::instruction_size == (int)NativeJump::instruction_size, "unexpected size"); + return (pc_offset + NativeCall::instruction_size); + } else if (inst->is_mov_literal64()) { + // mov+call instruction pair + jint offset = pc_offset + NativeMovConstReg::instruction_size; + u_char* call = (u_char*) (_instructions->start() + offset); + if (call[0] == Assembler::REX_B) { + offset += 1; /* prefix byte for extended register R8-R15 */ + call++; + } + assert(call[0] == 0xFF, "expected call"); + offset += 2; /* opcode byte + modrm byte */ + return (offset); + } else if (inst->is_call_reg()) { + // the inlined vtable stub contains a "call register" instruction + assert(method != NULL, "only valid for virtual calls"); + return (pc_offset + ((NativeCallReg *) inst)->next_instruction_offset()); + } else if (inst->is_cond_jump()) { + address pc = (address) (inst); + return pc_offset + (jint) (Assembler::locate_next_instruction(pc) - pc); + } else { + fatal("unsupported type of instruction for call site"); + return 0; + } +} + +void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle& constant) { + address pc = _instructions->start() + pc_offset; + Handle obj = HotSpotObjectConstantImpl::object(constant); + jobject value = JNIHandles::make_local(obj()); + if (HotSpotObjectConstantImpl::compressed(constant)) { +#ifdef _LP64 + address operand = Assembler::locate_operand(pc, Assembler::narrow_oop_operand); + int oop_index = _oop_recorder->find_index(value); + _instructions->relocate(pc, oop_Relocation::spec(oop_index), Assembler::narrow_oop_operand); + TRACE_jvmci_3("relocating (narrow oop constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); +#else + fatal("compressed oop on 32bit"); +#endif + } else { + address operand = Assembler::locate_operand(pc, Assembler::imm_operand); + *((jobject*) operand) = value; + _instructions->relocate(pc, oop_Relocation::spec_for_immediate(), Assembler::imm_operand); + TRACE_jvmci_3("relocating (oop constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(operand)); + } +} + +void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) { + address pc = _instructions->start() + pc_offset; + + address operand = Assembler::locate_operand(pc, Assembler::disp32_operand); + address next_instruction = Assembler::locate_next_instruction(pc); + address dest = _constants->start() + data_offset; + + long disp = dest - next_instruction; + assert(disp == (jint) disp, "disp doesn't fit in 32 bits"); + *((jint*) operand) = (jint) disp; + + _instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS), Assembler::disp32_operand); + TRACE_jvmci_3("relocating at " PTR_FORMAT "/" PTR_FORMAT " with destination at " PTR_FORMAT " (%d)", p2i(pc), p2i(operand), p2i(dest), data_offset); +} + +void CodeInstaller::pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst) { + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + nativeJump_at((address)inst)->set_jump_destination(nm->verified_entry_point()); + } else { + nativeJump_at((address)inst)->set_jump_destination(cb->code_begin()); + } + _instructions->relocate((address)inst, runtime_call_Relocation::spec(), Assembler::call32_operand); +} + +void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) { + address pc = (address) inst; + if (inst->is_call()) { + // NOTE: for call without a mov, the offset must fit a 32-bit immediate + // see also CompilerToVM.getMaxCallTargetOffset() + NativeCall* call = nativeCall_at(pc); + call->set_destination((address) foreign_call_destination); + _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + } else if (inst->is_mov_literal64()) { + NativeMovConstReg* mov = nativeMovConstReg_at(pc); + mov->set_data((intptr_t) foreign_call_destination); + _instructions->relocate(mov->instruction_address(), runtime_call_Relocation::spec(), Assembler::imm_operand); + } else if (inst->is_jump()) { + NativeJump* jump = nativeJump_at(pc); + jump->set_jump_destination((address) foreign_call_destination); + _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec(), Assembler::call32_operand); + } else if (inst->is_cond_jump()) { + address old_dest = nativeGeneralJump_at(pc)->jump_destination(); + address disp = Assembler::locate_operand(pc, Assembler::call32_operand); + *(jint*) disp += ((address) foreign_call_destination) - old_dest; + _instructions->relocate(pc, runtime_call_Relocation::spec(), Assembler::call32_operand); + } else { + fatal("unsupported relocation for foreign call"); + } + + TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); +} + +void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) { +#ifdef ASSERT + Method* method = NULL; + // we need to check, this might also be an unresolved method + if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) { + method = getMethodFromHotSpotMethod(hotspot_method); + } +#endif + switch (_next_call_type) { + case INLINE_INVOKE: + break; + case INVOKEVIRTUAL: + case INVOKEINTERFACE: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface"); + + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), + virtual_call_Relocation::spec(_invoke_mark_pc), + Assembler::call32_operand); + break; + } + case INVOKESTATIC: { + assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic"); + + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_static_call_stub()); + _instructions->relocate(call->instruction_address(), + relocInfo::static_call_type, Assembler::call32_operand); + break; + } + case INVOKESPECIAL: { + assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial"); + NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); + call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); + _instructions->relocate(call->instruction_address(), + relocInfo::opt_virtual_call_type, Assembler::call32_operand); + break; + } + default: + break; + } +} + +static void relocate_poll_near(address pc) { + NativeInstruction* ni = nativeInstruction_at(pc); + int32_t* disp = (int32_t*) Assembler::locate_operand(pc, Assembler::disp32_operand); + int32_t offset = *disp; // The Java code installed the polling page offset into the disp32 operand + intptr_t new_disp = (intptr_t) (os::get_polling_page() + offset) - (intptr_t) ni; + *disp = (int32_t)new_disp; +} + + +void CodeInstaller::pd_relocate_poll(address pc, jint mark) { + switch (mark) { + case POLL_NEAR: { + relocate_poll_near(pc); + _instructions->relocate(pc, relocInfo::poll_type, Assembler::disp32_operand); + break; + } + case POLL_FAR: + // This is a load from a register so there is no relocatable operand. + // We just have to ensure that the format is not disp32_operand + // so that poll_Relocation::fix_relocation_after_move does the right + // thing (i.e. ignores this relocation record) + _instructions->relocate(pc, relocInfo::poll_type, Assembler::imm_operand); + break; + case POLL_RETURN_NEAR: { + relocate_poll_near(pc); + _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::disp32_operand); + break; + } + case POLL_RETURN_FAR: + // see comment above for POLL_FAR + _instructions->relocate(pc, relocInfo::poll_return_type, Assembler::imm_operand); + break; + default: + fatal("invalid mark value"); + break; + } +} + +// convert JVMCI register indices (as used in oop maps) to HotSpot registers +VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg) { + if (jvmci_reg < RegisterImpl::number_of_registers) { + return as_Register(jvmci_reg)->as_VMReg(); + } else { + jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers; + if (floatRegisterNumber < XMMRegisterImpl::number_of_registers) { + return as_XMMRegister(floatRegisterNumber)->as_VMReg(); + } + ShouldNotReachHere(); + return NULL; + } +} + +bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { + return !(hotspotRegister->is_FloatRegister() || hotspotRegister->is_XMMRegister()); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -45,6 +45,7 @@ #include "gc/g1/g1SATBCardTableModRefBS.hpp" #include "gc/g1/heapRegion.hpp" #endif // INCLUDE_ALL_GCS +#include "crc32c.h" #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -56,8 +57,6 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef ASSERT bool AbstractAssembler::pd_check_instruction_mark() { return true; } #endif @@ -417,7 +416,7 @@ ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); } // Don't assert holding the ttyLock - assert(false, err_msg("DEBUG MESSAGE: %s", msg)); + assert(false, "DEBUG MESSAGE: %s", msg); ThreadStateTransition::transition(thread, _thread_in_vm, saved_state); } @@ -883,7 +882,7 @@ ttyLocker ttyl; ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); - assert(false, err_msg("DEBUG MESSAGE: %s", msg)); + assert(false, "DEBUG MESSAGE: %s", msg); } } @@ -2888,7 +2887,7 @@ } // !defined(COMPILER2) is because of stupid core builds -#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) +#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) || INCLUDE_JVMCI void MacroAssembler::empty_FPU_stack() { if (VM_Version::supports_mmx()) { emms(); @@ -2896,7 +2895,7 @@ for (int i = 8; i-- > 0; ) ffree(i); } } -#endif // !LP64 || C1 || !C2 +#endif // !LP64 || C1 || !C2 || INCLUDE_JVMCI // Defines obj, preserves var_size_in_bytes @@ -3032,6 +3031,15 @@ Assembler::fldcw(as_Address(src)); } +void MacroAssembler::mulpd(XMMRegister dst, AddressLiteral src) { + if (reachable(src)) { + Assembler::mulpd(dst, as_Address(src)); + } else { + lea(rscratch1, src); + Assembler::mulpd(dst, Address(rscratch1, 0)); + } +} + void MacroAssembler::pow_exp_core_encoding() { // kills rax, rcx, rdx subptr(rsp,sizeof(jdouble)); @@ -3104,19 +3112,7 @@ BLOCK_COMMENT("} fast_pow"); } -void MacroAssembler::fast_exp() { - // computes exp(X) = 2^(X * log2(e)) - // if fast computation is not possible, result is NaN. Requires - // fallback from user of this macro. - // increase precision for intermediate steps of the computation - increase_precision(); - fldl2e(); // Stack: log2(e) X ... - fmulp(1); // Stack: (X*log2(e)) ... - pow_exp_core_encoding(); // Stack: exp(X) ... - restore_precision(); -} - -void MacroAssembler::pow_or_exp(bool is_exp, int num_fpu_regs_in_use) { +void MacroAssembler::pow_or_exp(int num_fpu_regs_in_use) { // kills rax, rcx, rdx // pow and exp needs 2 extra registers on the fpu stack. Label slow_case, done; @@ -3128,182 +3124,164 @@ Register tmp2 = rax; Register tmp3 = rcx; - if (is_exp) { - // Stack: X - fld_s(0); // duplicate argument for runtime call. Stack: X X - fast_exp(); // Stack: exp(X) X - fcmp(tmp, 0, false, false); // Stack: exp(X) X - // exp(X) not equal to itself: exp(X) is NaN go to slow case. - jcc(Assembler::parity, slow_case); - // get rid of duplicate argument. Stack: exp(X) - if (num_fpu_regs_in_use > 0) { - fxch(); - fpop(); - } else { - ffree(1); - } - jmp(done); - } else { - // Stack: X Y - Label x_negative, y_not_2; - - static double two = 2.0; - ExternalAddress two_addr((address)&two); - - // constant maybe too far on 64 bit - lea(tmp2, two_addr); - fld_d(Address(tmp2, 0)); // Stack: 2 X Y - fcmp(tmp, 2, true, false); // Stack: X Y - jcc(Assembler::parity, y_not_2); - jcc(Assembler::notEqual, y_not_2); - - fxch(); fpop(); // Stack: X - fmul(0); // Stack: X*X - - jmp(done); - - bind(y_not_2); - - fldz(); // Stack: 0 X Y - fcmp(tmp, 1, true, false); // Stack: X Y - jcc(Assembler::above, x_negative); - - // X >= 0 - - fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y - fld_s(1); // Stack: X Y X Y - fast_pow(); // Stack: X^Y X Y - fcmp(tmp, 0, false, false); // Stack: X^Y X Y - // X^Y not equal to itself: X^Y is NaN go to slow case. - jcc(Assembler::parity, slow_case); - // get rid of duplicate arguments. Stack: X^Y - if (num_fpu_regs_in_use > 0) { - fxch(); fpop(); - fxch(); fpop(); - } else { - ffree(2); - ffree(1); - } - jmp(done); - - // X <= 0 - bind(x_negative); - - fld_s(1); // Stack: Y X Y - frndint(); // Stack: int(Y) X Y - fcmp(tmp, 2, false, false); // Stack: int(Y) X Y - jcc(Assembler::notEqual, slow_case); - - subptr(rsp, 8); - - // For X^Y, when X < 0, Y has to be an integer and the final - // result depends on whether it's odd or even. We just checked - // that int(Y) == Y. We move int(Y) to gp registers as a 64 bit - // integer to test its parity. If int(Y) is huge and doesn't fit - // in the 64 bit integer range, the integer indefinite value will - // end up in the gp registers. Huge numbers are all even, the - // integer indefinite number is even so it's fine. + // Stack: X Y + Label x_negative, y_not_2; + + static double two = 2.0; + ExternalAddress two_addr((address)&two); + + // constant maybe too far on 64 bit + lea(tmp2, two_addr); + fld_d(Address(tmp2, 0)); // Stack: 2 X Y + fcmp(tmp, 2, true, false); // Stack: X Y + jcc(Assembler::parity, y_not_2); + jcc(Assembler::notEqual, y_not_2); + + fxch(); fpop(); // Stack: X + fmul(0); // Stack: X*X + + jmp(done); + + bind(y_not_2); + + fldz(); // Stack: 0 X Y + fcmp(tmp, 1, true, false); // Stack: X Y + jcc(Assembler::above, x_negative); + + // X >= 0 + + fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y + fld_s(1); // Stack: X Y X Y + fast_pow(); // Stack: X^Y X Y + fcmp(tmp, 0, false, false); // Stack: X^Y X Y + // X^Y not equal to itself: X^Y is NaN go to slow case. + jcc(Assembler::parity, slow_case); + // get rid of duplicate arguments. Stack: X^Y + if (num_fpu_regs_in_use > 0) { + fxch(); fpop(); + fxch(); fpop(); + } else { + ffree(2); + ffree(1); + } + jmp(done); + + // X <= 0 + bind(x_negative); + + fld_s(1); // Stack: Y X Y + frndint(); // Stack: int(Y) X Y + fcmp(tmp, 2, false, false); // Stack: int(Y) X Y + jcc(Assembler::notEqual, slow_case); + + subptr(rsp, 8); + + // For X^Y, when X < 0, Y has to be an integer and the final + // result depends on whether it's odd or even. We just checked + // that int(Y) == Y. We move int(Y) to gp registers as a 64 bit + // integer to test its parity. If int(Y) is huge and doesn't fit + // in the 64 bit integer range, the integer indefinite value will + // end up in the gp registers. Huge numbers are all even, the + // integer indefinite number is even so it's fine. #ifdef ASSERT - // Let's check we don't end up with an integer indefinite number - // when not expected. First test for huge numbers: check whether - // int(Y)+1 == int(Y) which is true for very large numbers and - // those are all even. A 64 bit integer is guaranteed to not - // overflow for numbers where y+1 != y (when precision is set to - // double precision). - Label y_not_huge; - - fld1(); // Stack: 1 int(Y) X Y - fadd(1); // Stack: 1+int(Y) int(Y) X Y + // Let's check we don't end up with an integer indefinite number + // when not expected. First test for huge numbers: check whether + // int(Y)+1 == int(Y) which is true for very large numbers and + // those are all even. A 64 bit integer is guaranteed to not + // overflow for numbers where y+1 != y (when precision is set to + // double precision). + Label y_not_huge; + + fld1(); // Stack: 1 int(Y) X Y + fadd(1); // Stack: 1+int(Y) int(Y) X Y #ifdef _LP64 - // trip to memory to force the precision down from double extended - // precision - fstp_d(Address(rsp, 0)); - fld_d(Address(rsp, 0)); + // trip to memory to force the precision down from double extended + // precision + fstp_d(Address(rsp, 0)); + fld_d(Address(rsp, 0)); #endif - fcmp(tmp, 1, true, false); // Stack: int(Y) X Y + fcmp(tmp, 1, true, false); // Stack: int(Y) X Y #endif - // move int(Y) as 64 bit integer to thread's stack - fistp_d(Address(rsp,0)); // Stack: X Y + // move int(Y) as 64 bit integer to thread's stack + fistp_d(Address(rsp,0)); // Stack: X Y #ifdef ASSERT - jcc(Assembler::notEqual, y_not_huge); - - // Y is huge so we know it's even. It may not fit in a 64 bit - // integer and we don't want the debug code below to see the - // integer indefinite value so overwrite int(Y) on the thread's - // stack with 0. - movl(Address(rsp, 0), 0); - movl(Address(rsp, 4), 0); - - bind(y_not_huge); + jcc(Assembler::notEqual, y_not_huge); + + // Y is huge so we know it's even. It may not fit in a 64 bit + // integer and we don't want the debug code below to see the + // integer indefinite value so overwrite int(Y) on the thread's + // stack with 0. + movl(Address(rsp, 0), 0); + movl(Address(rsp, 4), 0); + + bind(y_not_huge); #endif - fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y - fld_s(1); // Stack: X Y X Y - fabs(); // Stack: abs(X) Y X Y - fast_pow(); // Stack: abs(X)^Y X Y - fcmp(tmp, 0, false, false); // Stack: abs(X)^Y X Y - // abs(X)^Y not equal to itself: abs(X)^Y is NaN go to slow case. - - pop(tmp2); - NOT_LP64(pop(tmp3)); - jcc(Assembler::parity, slow_case); + fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y + fld_s(1); // Stack: X Y X Y + fabs(); // Stack: abs(X) Y X Y + fast_pow(); // Stack: abs(X)^Y X Y + fcmp(tmp, 0, false, false); // Stack: abs(X)^Y X Y + // abs(X)^Y not equal to itself: abs(X)^Y is NaN go to slow case. + + pop(tmp2); + NOT_LP64(pop(tmp3)); + jcc(Assembler::parity, slow_case); #ifdef ASSERT - // Check that int(Y) is not integer indefinite value (int - // overflow). Shouldn't happen because for values that would - // overflow, 1+int(Y)==Y which was tested earlier. + // Check that int(Y) is not integer indefinite value (int + // overflow). Shouldn't happen because for values that would + // overflow, 1+int(Y)==Y which was tested earlier. #ifndef _LP64 - { - Label integer; - testl(tmp2, tmp2); - jcc(Assembler::notZero, integer); - cmpl(tmp3, 0x80000000); - jcc(Assembler::notZero, integer); - STOP("integer indefinite value shouldn't be seen here"); - bind(integer); - } + { + Label integer; + testl(tmp2, tmp2); + jcc(Assembler::notZero, integer); + cmpl(tmp3, 0x80000000); + jcc(Assembler::notZero, integer); + STOP("integer indefinite value shouldn't be seen here"); + bind(integer); + } #else - { - Label integer; - mov(tmp3, tmp2); // preserve tmp2 for parity check below - shlq(tmp3, 1); - jcc(Assembler::carryClear, integer); - jcc(Assembler::notZero, integer); - STOP("integer indefinite value shouldn't be seen here"); - bind(integer); - } + { + Label integer; + mov(tmp3, tmp2); // preserve tmp2 for parity check below + shlq(tmp3, 1); + jcc(Assembler::carryClear, integer); + jcc(Assembler::notZero, integer); + STOP("integer indefinite value shouldn't be seen here"); + bind(integer); + } #endif #endif - // get rid of duplicate arguments. Stack: X^Y - if (num_fpu_regs_in_use > 0) { - fxch(); fpop(); - fxch(); fpop(); - } else { - ffree(2); - ffree(1); - } - - testl(tmp2, 1); - jcc(Assembler::zero, done); // X <= 0, Y even: X^Y = abs(X)^Y - // X <= 0, Y even: X^Y = -abs(X)^Y - - fchs(); // Stack: -abs(X)^Y Y - jmp(done); - } + // get rid of duplicate arguments. Stack: X^Y + if (num_fpu_regs_in_use > 0) { + fxch(); fpop(); + fxch(); fpop(); + } else { + ffree(2); + ffree(1); + } + + testl(tmp2, 1); + jcc(Assembler::zero, done); // X <= 0, Y even: X^Y = abs(X)^Y + // X <= 0, Y even: X^Y = -abs(X)^Y + + fchs(); // Stack: -abs(X)^Y Y + jmp(done); // slow case: runtime call bind(slow_case); fpop(); // pop incorrect result or int(Y) - fp_runtime_fallback(is_exp ? CAST_FROM_FN_PTR(address, SharedRuntime::dexp) : CAST_FROM_FN_PTR(address, SharedRuntime::dpow), - is_exp ? 1 : 2, num_fpu_regs_in_use); + fp_runtime_fallback(CAST_FROM_FN_PTR(address, SharedRuntime::dpow), 2, num_fpu_regs_in_use); // Come here with result in F-TOS bind(done); @@ -6267,7 +6245,9 @@ // Save caller's stack pointer into RBP if the frame pointer is preserved. if (PreserveFramePointer) { movptr(rbp, rsp); - addptr(rbp, framesize + wordSize); + if (framesize > 0) { + addptr(rbp, framesize); + } } } @@ -8636,6 +8616,471 @@ notl(crc); // ~c } +#ifdef _LP64 +// S. Gueron / Information Processing Letters 112 (2012) 184 +// Algorithm 4: Computing carry-less multiplication using a precomputed lookup table. +// Input: A 32 bit value B = [byte3, byte2, byte1, byte0]. +// Output: the 64-bit carry-less product of B * CONST +void MacroAssembler::crc32c_ipl_alg4(Register in, uint32_t n, + Register tmp1, Register tmp2, Register tmp3) { + lea(tmp3, ExternalAddress(StubRoutines::crc32c_table_addr())); + if (n > 0) { + addq(tmp3, n * 256 * 8); + } + // Q1 = TABLEExt[n][B & 0xFF]; + movl(tmp1, in); + andl(tmp1, 0x000000FF); + shll(tmp1, 3); + addq(tmp1, tmp3); + movq(tmp1, Address(tmp1, 0)); + + // Q2 = TABLEExt[n][B >> 8 & 0xFF]; + movl(tmp2, in); + shrl(tmp2, 8); + andl(tmp2, 0x000000FF); + shll(tmp2, 3); + addq(tmp2, tmp3); + movq(tmp2, Address(tmp2, 0)); + + shlq(tmp2, 8); + xorq(tmp1, tmp2); + + // Q3 = TABLEExt[n][B >> 16 & 0xFF]; + movl(tmp2, in); + shrl(tmp2, 16); + andl(tmp2, 0x000000FF); + shll(tmp2, 3); + addq(tmp2, tmp3); + movq(tmp2, Address(tmp2, 0)); + + shlq(tmp2, 16); + xorq(tmp1, tmp2); + + // Q4 = TABLEExt[n][B >> 24 & 0xFF]; + shrl(in, 24); + andl(in, 0x000000FF); + shll(in, 3); + addq(in, tmp3); + movq(in, Address(in, 0)); + + shlq(in, 24); + xorq(in, tmp1); + // return Q1 ^ Q2 << 8 ^ Q3 << 16 ^ Q4 << 24; +} + +void MacroAssembler::crc32c_pclmulqdq(XMMRegister w_xtmp1, + Register in_out, + uint32_t const_or_pre_comp_const_index, bool is_pclmulqdq_supported, + XMMRegister w_xtmp2, + Register tmp1, + Register n_tmp2, Register n_tmp3) { + if (is_pclmulqdq_supported) { + movdl(w_xtmp1, in_out); // modified blindly + + movl(tmp1, const_or_pre_comp_const_index); + movdl(w_xtmp2, tmp1); + pclmulqdq(w_xtmp1, w_xtmp2, 0); + + movdq(in_out, w_xtmp1); + } else { + crc32c_ipl_alg4(in_out, const_or_pre_comp_const_index, tmp1, n_tmp2, n_tmp3); + } +} + +// Recombination Alternative 2: No bit-reflections +// T1 = (CRC_A * U1) << 1 +// T2 = (CRC_B * U2) << 1 +// C1 = T1 >> 32 +// C2 = T2 >> 32 +// T1 = T1 & 0xFFFFFFFF +// T2 = T2 & 0xFFFFFFFF +// T1 = CRC32(0, T1) +// T2 = CRC32(0, T2) +// C1 = C1 ^ T1 +// C2 = C2 ^ T2 +// CRC = C1 ^ C2 ^ CRC_C +void MacroAssembler::crc32c_rec_alt2(uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, Register in_out, Register in1, Register in2, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp1, Register tmp2, + Register n_tmp3) { + crc32c_pclmulqdq(w_xtmp1, in_out, const_or_pre_comp_const_index_u1, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); + crc32c_pclmulqdq(w_xtmp2, in1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); + shlq(in_out, 1); + movl(tmp1, in_out); + shrq(in_out, 32); + xorl(tmp2, tmp2); + crc32(tmp2, tmp1, 4); + xorl(in_out, tmp2); // we don't care about upper 32 bit contents here + shlq(in1, 1); + movl(tmp1, in1); + shrq(in1, 32); + xorl(tmp2, tmp2); + crc32(tmp2, tmp1, 4); + xorl(in1, tmp2); + xorl(in_out, in1); + xorl(in_out, in2); +} + +// Set N to predefined value +// Subtract from a lenght of a buffer +// execute in a loop: +// CRC_A = 0xFFFFFFFF, CRC_B = 0, CRC_C = 0 +// for i = 1 to N do +// CRC_A = CRC32(CRC_A, A[i]) +// CRC_B = CRC32(CRC_B, B[i]) +// CRC_C = CRC32(CRC_C, C[i]) +// end for +// Recombine +void MacroAssembler::crc32c_proc_chunk(uint32_t size, uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, + Register in_out1, Register in_out2, Register in_out3, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp4, Register tmp5, + Register n_tmp6) { + Label L_processPartitions; + Label L_processPartition; + Label L_exit; + + bind(L_processPartitions); + cmpl(in_out1, 3 * size); + jcc(Assembler::less, L_exit); + xorl(tmp1, tmp1); + xorl(tmp2, tmp2); + movq(tmp3, in_out2); + addq(tmp3, size); + + bind(L_processPartition); + crc32(in_out3, Address(in_out2, 0), 8); + crc32(tmp1, Address(in_out2, size), 8); + crc32(tmp2, Address(in_out2, size * 2), 8); + addq(in_out2, 8); + cmpq(in_out2, tmp3); + jcc(Assembler::less, L_processPartition); + crc32c_rec_alt2(const_or_pre_comp_const_index_u1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, in_out3, tmp1, tmp2, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + n_tmp6); + addq(in_out2, 2 * size); + subl(in_out1, 3 * size); + jmp(L_processPartitions); + + bind(L_exit); +} +#else +void MacroAssembler::crc32c_ipl_alg4(Register in_out, uint32_t n, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister xtmp1, XMMRegister xtmp2) { + lea(tmp3, ExternalAddress(StubRoutines::crc32c_table_addr())); + if (n > 0) { + addl(tmp3, n * 256 * 8); + } + // Q1 = TABLEExt[n][B & 0xFF]; + movl(tmp1, in_out); + andl(tmp1, 0x000000FF); + shll(tmp1, 3); + addl(tmp1, tmp3); + movq(xtmp1, Address(tmp1, 0)); + + // Q2 = TABLEExt[n][B >> 8 & 0xFF]; + movl(tmp2, in_out); + shrl(tmp2, 8); + andl(tmp2, 0x000000FF); + shll(tmp2, 3); + addl(tmp2, tmp3); + movq(xtmp2, Address(tmp2, 0)); + + psllq(xtmp2, 8); + pxor(xtmp1, xtmp2); + + // Q3 = TABLEExt[n][B >> 16 & 0xFF]; + movl(tmp2, in_out); + shrl(tmp2, 16); + andl(tmp2, 0x000000FF); + shll(tmp2, 3); + addl(tmp2, tmp3); + movq(xtmp2, Address(tmp2, 0)); + + psllq(xtmp2, 16); + pxor(xtmp1, xtmp2); + + // Q4 = TABLEExt[n][B >> 24 & 0xFF]; + shrl(in_out, 24); + andl(in_out, 0x000000FF); + shll(in_out, 3); + addl(in_out, tmp3); + movq(xtmp2, Address(in_out, 0)); + + psllq(xtmp2, 24); + pxor(xtmp1, xtmp2); // Result in CXMM + // return Q1 ^ Q2 << 8 ^ Q3 << 16 ^ Q4 << 24; +} + +void MacroAssembler::crc32c_pclmulqdq(XMMRegister w_xtmp1, + Register in_out, + uint32_t const_or_pre_comp_const_index, bool is_pclmulqdq_supported, + XMMRegister w_xtmp2, + Register tmp1, + Register n_tmp2, Register n_tmp3) { + if (is_pclmulqdq_supported) { + movdl(w_xtmp1, in_out); + + movl(tmp1, const_or_pre_comp_const_index); + movdl(w_xtmp2, tmp1); + pclmulqdq(w_xtmp1, w_xtmp2, 0); + // Keep result in XMM since GPR is 32 bit in length + } else { + crc32c_ipl_alg4(in_out, const_or_pre_comp_const_index, tmp1, n_tmp2, n_tmp3, w_xtmp1, w_xtmp2); + } +} + +void MacroAssembler::crc32c_rec_alt2(uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, Register in_out, Register in1, Register in2, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp1, Register tmp2, + Register n_tmp3) { + crc32c_pclmulqdq(w_xtmp1, in_out, const_or_pre_comp_const_index_u1, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); + crc32c_pclmulqdq(w_xtmp2, in1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, w_xtmp3, tmp1, tmp2, n_tmp3); + + psllq(w_xtmp1, 1); + movdl(tmp1, w_xtmp1); + psrlq(w_xtmp1, 32); + movdl(in_out, w_xtmp1); + + xorl(tmp2, tmp2); + crc32(tmp2, tmp1, 4); + xorl(in_out, tmp2); + + psllq(w_xtmp2, 1); + movdl(tmp1, w_xtmp2); + psrlq(w_xtmp2, 32); + movdl(in1, w_xtmp2); + + xorl(tmp2, tmp2); + crc32(tmp2, tmp1, 4); + xorl(in1, tmp2); + xorl(in_out, in1); + xorl(in_out, in2); +} + +void MacroAssembler::crc32c_proc_chunk(uint32_t size, uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, + Register in_out1, Register in_out2, Register in_out3, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp4, Register tmp5, + Register n_tmp6) { + Label L_processPartitions; + Label L_processPartition; + Label L_exit; + + bind(L_processPartitions); + cmpl(in_out1, 3 * size); + jcc(Assembler::less, L_exit); + xorl(tmp1, tmp1); + xorl(tmp2, tmp2); + movl(tmp3, in_out2); + addl(tmp3, size); + + bind(L_processPartition); + crc32(in_out3, Address(in_out2, 0), 4); + crc32(tmp1, Address(in_out2, size), 4); + crc32(tmp2, Address(in_out2, size*2), 4); + crc32(in_out3, Address(in_out2, 0+4), 4); + crc32(tmp1, Address(in_out2, size+4), 4); + crc32(tmp2, Address(in_out2, size*2+4), 4); + addl(in_out2, 8); + cmpl(in_out2, tmp3); + jcc(Assembler::less, L_processPartition); + + push(tmp3); + push(in_out1); + push(in_out2); + tmp4 = tmp3; + tmp5 = in_out1; + n_tmp6 = in_out2; + + crc32c_rec_alt2(const_or_pre_comp_const_index_u1, const_or_pre_comp_const_index_u2, is_pclmulqdq_supported, in_out3, tmp1, tmp2, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + n_tmp6); + + pop(in_out2); + pop(in_out1); + pop(tmp3); + + addl(in_out2, 2 * size); + subl(in_out1, 3 * size); + jmp(L_processPartitions); + + bind(L_exit); +} +#endif //LP64 + +#ifdef _LP64 +// Algorithm 2: Pipelined usage of the CRC32 instruction. +// Input: A buffer I of L bytes. +// Output: the CRC32C value of the buffer. +// Notations: +// Write L = 24N + r, with N = floor (L/24). +// r = L mod 24 (0 <= r < 24). +// Consider I as the concatenation of A|B|C|R, where A, B, C, each, +// N quadwords, and R consists of r bytes. +// A[j] = I [8j+7:8j], j= 0, 1, ..., N-1 +// B[j] = I [N + 8j+7:N + 8j], j= 0, 1, ..., N-1 +// C[j] = I [2N + 8j+7:2N + 8j], j= 0, 1, ..., N-1 +// if r > 0 R[j] = I [3N +j], j= 0, 1, ...,r-1 +void MacroAssembler::crc32c_ipl_alg2_alt2(Register in_out, Register in1, Register in2, + Register tmp1, Register tmp2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + bool is_pclmulqdq_supported) { + uint32_t const_or_pre_comp_const_index[CRC32C_NUM_PRECOMPUTED_CONSTANTS]; + Label L_wordByWord; + Label L_byteByByteProlog; + Label L_byteByByte; + Label L_exit; + + if (is_pclmulqdq_supported ) { + const_or_pre_comp_const_index[1] = *(uint32_t *)StubRoutines::_crc32c_table_addr; + const_or_pre_comp_const_index[0] = *((uint32_t *)StubRoutines::_crc32c_table_addr+1); + + const_or_pre_comp_const_index[3] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 2); + const_or_pre_comp_const_index[2] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 3); + + const_or_pre_comp_const_index[5] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 4); + const_or_pre_comp_const_index[4] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 5); + assert((CRC32C_NUM_PRECOMPUTED_CONSTANTS - 1 ) == 5, "Checking whether you declared all of the constants based on the number of \"chunks\""); + } else { + const_or_pre_comp_const_index[0] = 1; + const_or_pre_comp_const_index[1] = 0; + + const_or_pre_comp_const_index[2] = 3; + const_or_pre_comp_const_index[3] = 2; + + const_or_pre_comp_const_index[4] = 5; + const_or_pre_comp_const_index[5] = 4; + } + crc32c_proc_chunk(CRC32C_HIGH, const_or_pre_comp_const_index[0], const_or_pre_comp_const_index[1], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + crc32c_proc_chunk(CRC32C_MIDDLE, const_or_pre_comp_const_index[2], const_or_pre_comp_const_index[3], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + crc32c_proc_chunk(CRC32C_LOW, const_or_pre_comp_const_index[4], const_or_pre_comp_const_index[5], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + movl(tmp1, in2); + andl(tmp1, 0x00000007); + negl(tmp1); + addl(tmp1, in2); + addq(tmp1, in1); + + BIND(L_wordByWord); + cmpq(in1, tmp1); + jcc(Assembler::greaterEqual, L_byteByByteProlog); + crc32(in_out, Address(in1, 0), 4); + addq(in1, 4); + jmp(L_wordByWord); + + BIND(L_byteByByteProlog); + andl(in2, 0x00000007); + movl(tmp2, 1); + + BIND(L_byteByByte); + cmpl(tmp2, in2); + jccb(Assembler::greater, L_exit); + crc32(in_out, Address(in1, 0), 1); + incq(in1); + incl(tmp2); + jmp(L_byteByByte); + + BIND(L_exit); +} +#else +void MacroAssembler::crc32c_ipl_alg2_alt2(Register in_out, Register in1, Register in2, + Register tmp1, Register tmp2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + bool is_pclmulqdq_supported) { + uint32_t const_or_pre_comp_const_index[CRC32C_NUM_PRECOMPUTED_CONSTANTS]; + Label L_wordByWord; + Label L_byteByByteProlog; + Label L_byteByByte; + Label L_exit; + + if (is_pclmulqdq_supported) { + const_or_pre_comp_const_index[1] = *(uint32_t *)StubRoutines::_crc32c_table_addr; + const_or_pre_comp_const_index[0] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 1); + + const_or_pre_comp_const_index[3] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 2); + const_or_pre_comp_const_index[2] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 3); + + const_or_pre_comp_const_index[5] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 4); + const_or_pre_comp_const_index[4] = *((uint32_t *)StubRoutines::_crc32c_table_addr + 5); + } else { + const_or_pre_comp_const_index[0] = 1; + const_or_pre_comp_const_index[1] = 0; + + const_or_pre_comp_const_index[2] = 3; + const_or_pre_comp_const_index[3] = 2; + + const_or_pre_comp_const_index[4] = 5; + const_or_pre_comp_const_index[5] = 4; + } + crc32c_proc_chunk(CRC32C_HIGH, const_or_pre_comp_const_index[0], const_or_pre_comp_const_index[1], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + crc32c_proc_chunk(CRC32C_MIDDLE, const_or_pre_comp_const_index[2], const_or_pre_comp_const_index[3], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + crc32c_proc_chunk(CRC32C_LOW, const_or_pre_comp_const_index[4], const_or_pre_comp_const_index[5], is_pclmulqdq_supported, + in2, in1, in_out, + tmp1, tmp2, tmp3, + w_xtmp1, w_xtmp2, w_xtmp3, + tmp4, tmp5, + tmp6); + movl(tmp1, in2); + andl(tmp1, 0x00000007); + negl(tmp1); + addl(tmp1, in2); + addl(tmp1, in1); + + BIND(L_wordByWord); + cmpl(in1, tmp1); + jcc(Assembler::greaterEqual, L_byteByByteProlog); + crc32(in_out, Address(in1,0), 4); + addl(in1, 4); + jmp(L_wordByWord); + + BIND(L_byteByByteProlog); + andl(in2, 0x00000007); + movl(tmp2, 1); + + BIND(L_byteByByte); + cmpl(tmp2, in2); + jccb(Assembler::greater, L_exit); + movb(tmp1, Address(in1, 0)); + crc32(in_out, tmp1, 1); + incl(in1); + incl(tmp2); + jmp(L_byteByByte); + + BIND(L_exit); +} +#endif // LP64 #undef BIND #undef BLOCK_COMMENT diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -907,14 +907,14 @@ // all corner cases and may result in NaN and require fallback to a // runtime call. void fast_pow(); - void fast_exp(); + void fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, + XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, + Register rax, Register rcx, Register rdx, Register tmp); void increase_precision(); void restore_precision(); - // computes exp(x). Fallback to runtime call included. - void exp_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(true, num_fpu_regs_in_use); } // computes pow(x,y). Fallback to runtime call included. - void pow_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(false, num_fpu_regs_in_use); } + void pow_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(num_fpu_regs_in_use); } private: @@ -925,7 +925,7 @@ void pow_exp_core_encoding(); // computes pow(x,y) or exp(x). Fallback to runtime call included. - void pow_or_exp(bool is_exp, int num_fpu_regs_in_use); + void pow_or_exp(int num_fpu_regs_in_use); // these are private because users should be doing movflt/movdbl @@ -971,6 +971,10 @@ void movsd(XMMRegister dst, Address src) { Assembler::movsd(dst, src); } void movsd(XMMRegister dst, AddressLiteral src); + void mulpd(XMMRegister dst, XMMRegister src) { Assembler::mulpd(dst, src); } + void mulpd(XMMRegister dst, Address src) { Assembler::mulpd(dst, src); } + void mulpd(XMMRegister dst, AddressLiteral src); + void mulsd(XMMRegister dst, XMMRegister src) { Assembler::mulsd(dst, src); } void mulsd(XMMRegister dst, Address src) { Assembler::mulsd(dst, src); } void mulsd(XMMRegister dst, AddressLiteral src); @@ -1278,9 +1282,42 @@ Register raxReg); #endif - // CRC32 code for java.util.zip.CRC32::updateBytes() instrinsic. + // CRC32 code for java.util.zip.CRC32::updateBytes() intrinsic. void update_byte_crc32(Register crc, Register val, Register table); void kernel_crc32(Register crc, Register buf, Register len, Register table, Register tmp); + // CRC32C code for java.util.zip.CRC32C::updateBytes() intrinsic + // Note on a naming convention: + // Prefix w = register only used on a Westmere+ architecture + // Prefix n = register only used on a Nehalem architecture +#ifdef _LP64 + void crc32c_ipl_alg4(Register in_out, uint32_t n, + Register tmp1, Register tmp2, Register tmp3); +#else + void crc32c_ipl_alg4(Register in_out, uint32_t n, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister xtmp1, XMMRegister xtmp2); +#endif + void crc32c_pclmulqdq(XMMRegister w_xtmp1, + Register in_out, + uint32_t const_or_pre_comp_const_index, bool is_pclmulqdq_supported, + XMMRegister w_xtmp2, + Register tmp1, + Register n_tmp2, Register n_tmp3); + void crc32c_rec_alt2(uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, Register in_out, Register in1, Register in2, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp1, Register tmp2, + Register n_tmp3); + void crc32c_proc_chunk(uint32_t size, uint32_t const_or_pre_comp_const_index_u1, uint32_t const_or_pre_comp_const_index_u2, bool is_pclmulqdq_supported, + Register in_out1, Register in_out2, Register in_out3, + Register tmp1, Register tmp2, Register tmp3, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + Register tmp4, Register tmp5, + Register n_tmp6); + void crc32c_ipl_alg2_alt2(Register in_out, Register in1, Register in2, + Register tmp1, Register tmp2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, + XMMRegister w_xtmp1, XMMRegister w_xtmp2, XMMRegister w_xtmp3, + bool is_pclmulqdq_supported); // Fold 128-bit data chunk void fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, Register buf, int offset); void fold_128bit_crc32(XMMRegister xcrc, XMMRegister xK, XMMRegister xtmp, XMMRegister xbuf); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/macroAssembler_x86_libm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86_libm.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2015, Intel Corporation. + * Intel Math Library (LIBM) Source Code + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/******************************************************************************/ +// ALGORITHM DESCRIPTION +// --------------------- +// +// Description: +// Let K = 64 (table size). +// x x/log(2) n +// e = 2 = 2 * T[j] * (1 + P(y)) +// where +// x = m*log(2)/K + y, y in [-log(2)/K..log(2)/K] +// m = n*K + j, m,n,j - signed integer, j in [-K/2..K/2] +// j/K +// values of 2 are tabulated as T[j] = T_hi[j] ( 1 + T_lo[j]). +// +// P(y) is a minimax polynomial approximation of exp(x)-1 +// on small interval [-log(2)/K..log(2)/K] (were calculated by Maple V). +// +// To avoid problems with arithmetic overflow and underflow, +// n n1 n2 +// value of 2 is safely computed as 2 * 2 where n1 in [-BIAS/2..BIAS/2] +// where BIAS is a value of exponent bias. +// +// Special cases: +// exp(NaN) = NaN +// exp(+INF) = +INF +// exp(-INF) = 0 +// exp(x) = 1 for subnormals +// for finite argument, only exp(0)=1 is exact +// For IEEE double +// if x > 709.782712893383973096 then exp(x) overflow +// if x < -745.133219101941108420 then exp(x) underflow +// +/******************************************************************************/ + + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "macroAssembler_x86.hpp" + +#ifdef _MSC_VER +#define ALIGNED_(x) __declspec(align(x)) +#else +#define ALIGNED_(x) __attribute__ ((aligned(x))) +#endif + +#ifdef _LP64 + +ALIGNED_(16) juint _cv[] = +{ + 0x652b82feUL, 0x40571547UL, 0x652b82feUL, 0x40571547UL, 0xfefa0000UL, + 0x3f862e42UL, 0xfefa0000UL, 0x3f862e42UL, 0xbc9e3b3aUL, 0x3d1cf79aUL, + 0xbc9e3b3aUL, 0x3d1cf79aUL, 0xfffffffeUL, 0x3fdfffffUL, 0xfffffffeUL, + 0x3fdfffffUL, 0xe3289860UL, 0x3f56c15cUL, 0x555b9e25UL, 0x3fa55555UL, + 0xc090cf0fUL, 0x3f811115UL, 0x55548ba1UL, 0x3fc55555UL +}; + +ALIGNED_(16) juint _shifter[] = +{ + 0x00000000UL, 0x43380000UL, 0x00000000UL, 0x43380000UL +}; + +ALIGNED_(16) juint _mmask[] = +{ + 0xffffffc0UL, 0x00000000UL, 0xffffffc0UL, 0x00000000UL +}; + +ALIGNED_(16) juint _bias[] = +{ + 0x0000ffc0UL, 0x00000000UL, 0x0000ffc0UL, 0x00000000UL +}; + +ALIGNED_(16) juint _Tbl_addr[] = +{ + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0e03754dUL, + 0x3cad7bbfUL, 0x3e778060UL, 0x00002c9aUL, 0x3567f613UL, 0x3c8cd252UL, + 0xd3158574UL, 0x000059b0UL, 0x61e6c861UL, 0x3c60f74eUL, 0x18759bc8UL, + 0x00008745UL, 0x5d837b6cUL, 0x3c979aa6UL, 0x6cf9890fUL, 0x0000b558UL, + 0x702f9cd1UL, 0x3c3ebe3dUL, 0x32d3d1a2UL, 0x0000e3ecUL, 0x1e63bcd8UL, + 0x3ca3516eUL, 0xd0125b50UL, 0x00011301UL, 0x26f0387bUL, 0x3ca4c554UL, + 0xaea92ddfUL, 0x0001429aUL, 0x62523fb6UL, 0x3ca95153UL, 0x3c7d517aUL, + 0x000172b8UL, 0x3f1353bfUL, 0x3c8b898cUL, 0xeb6fcb75UL, 0x0001a35bUL, + 0x3e3a2f5fUL, 0x3c9aecf7UL, 0x3168b9aaUL, 0x0001d487UL, 0x44a6c38dUL, + 0x3c8a6f41UL, 0x88628cd6UL, 0x0002063bUL, 0xe3a8a894UL, 0x3c968efdUL, + 0x6e756238UL, 0x0002387aUL, 0x981fe7f2UL, 0x3c80472bUL, 0x65e27cddUL, + 0x00026b45UL, 0x6d09ab31UL, 0x3c82f7e1UL, 0xf51fdee1UL, 0x00029e9dUL, + 0x720c0ab3UL, 0x3c8b3782UL, 0xa6e4030bUL, 0x0002d285UL, 0x4db0abb6UL, + 0x3c834d75UL, 0x0a31b715UL, 0x000306feUL, 0x5dd3f84aUL, 0x3c8fdd39UL, + 0xb26416ffUL, 0x00033c08UL, 0xcc187d29UL, 0x3ca12f8cUL, 0x373aa9caUL, + 0x000371a7UL, 0x738b5e8bUL, 0x3ca7d229UL, 0x34e59ff6UL, 0x0003a7dbUL, + 0xa72a4c6dUL, 0x3c859f48UL, 0x4c123422UL, 0x0003dea6UL, 0x259d9205UL, + 0x3ca8b846UL, 0x21f72e29UL, 0x0004160aUL, 0x60c2ac12UL, 0x3c4363edUL, + 0x6061892dUL, 0x00044e08UL, 0xdaa10379UL, 0x3c6ecce1UL, 0xb5c13cd0UL, + 0x000486a2UL, 0xbb7aafb0UL, 0x3c7690ceUL, 0xd5362a27UL, 0x0004bfdaUL, + 0x9b282a09UL, 0x3ca083ccUL, 0x769d2ca6UL, 0x0004f9b2UL, 0xc1aae707UL, + 0x3ca509b0UL, 0x569d4f81UL, 0x0005342bUL, 0x18fdd78eUL, 0x3c933505UL, + 0x36b527daUL, 0x00056f47UL, 0xe21c5409UL, 0x3c9063e1UL, 0xdd485429UL, + 0x0005ab07UL, 0x2b64c035UL, 0x3c9432e6UL, 0x15ad2148UL, 0x0005e76fUL, + 0x99f08c0aUL, 0x3ca01284UL, 0xb03a5584UL, 0x0006247eUL, 0x0073dc06UL, + 0x3c99f087UL, 0x82552224UL, 0x00066238UL, 0x0da05571UL, 0x3c998d4dUL, + 0x667f3bccUL, 0x0006a09eUL, 0x86ce4786UL, 0x3ca52bb9UL, 0x3c651a2eUL, + 0x0006dfb2UL, 0x206f0dabUL, 0x3ca32092UL, 0xe8ec5f73UL, 0x00071f75UL, + 0x8e17a7a6UL, 0x3ca06122UL, 0x564267c8UL, 0x00075febUL, 0x461e9f86UL, + 0x3ca244acUL, 0x73eb0186UL, 0x0007a114UL, 0xabd66c55UL, 0x3c65ebe1UL, + 0x36cf4e62UL, 0x0007e2f3UL, 0xbbff67d0UL, 0x3c96fe9fUL, 0x994cce12UL, + 0x00082589UL, 0x14c801dfUL, 0x3c951f14UL, 0x9b4492ecUL, 0x000868d9UL, + 0xc1f0eab4UL, 0x3c8db72fUL, 0x422aa0dbUL, 0x0008ace5UL, 0x59f35f44UL, + 0x3c7bf683UL, 0x99157736UL, 0x0008f1aeUL, 0x9c06283cUL, 0x3ca360baUL, + 0xb0cdc5e4UL, 0x00093737UL, 0x20f962aaUL, 0x3c95e8d1UL, 0x9fde4e4fUL, + 0x00097d82UL, 0x2b91ce27UL, 0x3c71affcUL, 0x82a3f090UL, 0x0009c491UL, + 0x589a2ebdUL, 0x3c9b6d34UL, 0x7b5de564UL, 0x000a0c66UL, 0x9ab89880UL, + 0x3c95277cUL, 0xb23e255cUL, 0x000a5503UL, 0x6e735ab3UL, 0x3c846984UL, + 0x5579fdbfUL, 0x000a9e6bUL, 0x92cb3387UL, 0x3c8c1a77UL, 0x995ad3adUL, + 0x000ae89fUL, 0xdc2d1d96UL, 0x3ca22466UL, 0xb84f15faUL, 0x000b33a2UL, + 0xb19505aeUL, 0x3ca1112eUL, 0xf2fb5e46UL, 0x000b7f76UL, 0x0a5fddcdUL, + 0x3c74ffd7UL, 0x904bc1d2UL, 0x000bcc1eUL, 0x30af0cb3UL, 0x3c736eaeUL, + 0xdd85529cUL, 0x000c199bUL, 0xd10959acUL, 0x3c84e08fUL, 0x2e57d14bUL, + 0x000c67f1UL, 0x6c921968UL, 0x3c676b2cUL, 0xdcef9069UL, 0x000cb720UL, + 0x36df99b3UL, 0x3c937009UL, 0x4a07897bUL, 0x000d072dUL, 0xa63d07a7UL, + 0x3c74a385UL, 0xdcfba487UL, 0x000d5818UL, 0xd5c192acUL, 0x3c8e5a50UL, + 0x03db3285UL, 0x000da9e6UL, 0x1c4a9792UL, 0x3c98bb73UL, 0x337b9b5eUL, + 0x000dfc97UL, 0x603a88d3UL, 0x3c74b604UL, 0xe78b3ff6UL, 0x000e502eUL, + 0x92094926UL, 0x3c916f27UL, 0xa2a490d9UL, 0x000ea4afUL, 0x41aa2008UL, + 0x3c8ec3bcUL, 0xee615a27UL, 0x000efa1bUL, 0x31d185eeUL, 0x3c8a64a9UL, + 0x5b6e4540UL, 0x000f5076UL, 0x4d91cd9dUL, 0x3c77893bUL, 0x819e90d8UL, + 0x000fa7c1UL +}; + +ALIGNED_(16) juint _ALLONES[] = +{ + 0xffffffffUL, 0xffffffffUL, 0xffffffffUL, 0xffffffffUL +}; + +ALIGNED_(16) juint _ebias[] = +{ + 0x00000000UL, 0x3ff00000UL, 0x00000000UL, 0x3ff00000UL +}; + +ALIGNED_(4) juint _XMAX[] = +{ + 0xffffffffUL, 0x7fefffffUL +}; + +ALIGNED_(4) juint _XMIN[] = +{ + 0x00000000UL, 0x00100000UL +}; + +ALIGNED_(4) juint _INF[] = +{ + 0x00000000UL, 0x7ff00000UL +}; + +ALIGNED_(4) juint _ZERO[] = +{ + 0x00000000UL, 0x00000000UL +}; + +ALIGNED_(4) juint _ONE_val[] = +{ + 0x00000000UL, 0x3ff00000UL +}; + + +// Registers: +// input: xmm0 +// scratch: xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 +// rax, rdx, rcx, tmp - r11 + +// Code generated by Intel C compiler for LIBM library + +void MacroAssembler::fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register eax, Register ecx, Register edx, Register tmp) { + Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; + Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; + Label L_2TAG_PACKET_8_0_2, L_2TAG_PACKET_9_0_2, L_2TAG_PACKET_10_0_2, L_2TAG_PACKET_11_0_2; + Label L_2TAG_PACKET_12_0_2, B1_3, B1_5, start; + + assert_different_registers(tmp, eax, ecx, edx); + jmp(start); + address cv = (address)_cv; + address Shifter = (address)_shifter; + address mmask = (address)_mmask; + address bias = (address)_bias; + address Tbl_addr = (address)_Tbl_addr; + address ALLONES = (address)_ALLONES; + address ebias = (address)_ebias; + address XMAX = (address)_XMAX; + address XMIN = (address)_XMIN; + address INF = (address)_INF; + address ZERO = (address)_ZERO; + address ONE_val = (address)_ONE_val; + + bind(start); + subq(rsp, 24); + movsd(Address(rsp, 8), xmm0); + unpcklpd(xmm0, xmm0); + movdqu(xmm1, ExternalAddress(cv)); // 0x652b82feUL, 0x40571547UL, 0x652b82feUL, 0x40571547UL + movdqu(xmm6, ExternalAddress(Shifter)); // 0x00000000UL, 0x43380000UL, 0x00000000UL, 0x43380000UL + movdqu(xmm2, ExternalAddress(16+cv)); // 0xfefa0000UL, 0x3f862e42UL, 0xfefa0000UL, 0x3f862e42UL + movdqu(xmm3, ExternalAddress(32+cv)); // 0xbc9e3b3aUL, 0x3d1cf79aUL, 0xbc9e3b3aUL, 0x3d1cf79aUL + pextrw(eax, xmm0, 3); + andl(eax, 32767); + movl(edx, 16527); + subl(edx, eax); + subl(eax, 15504); + orl(edx, eax); + cmpl(edx, INT_MIN); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_2); + mulpd(xmm1, xmm0); + addpd(xmm1, xmm6); + movapd(xmm7, xmm1); + subpd(xmm1, xmm6); + mulpd(xmm2, xmm1); + movdqu(xmm4, ExternalAddress(64+cv)); // 0xe3289860UL, 0x3f56c15cUL, 0x555b9e25UL, 0x3fa55555UL + mulpd(xmm3, xmm1); + movdqu(xmm5, ExternalAddress(80+cv)); // 0xc090cf0fUL, 0x3f811115UL, 0x55548ba1UL, 0x3fc55555UL + subpd(xmm0, xmm2); + movdl(eax, xmm7); + movl(ecx, eax); + andl(ecx, 63); + shll(ecx, 4); + sarl(eax, 6); + movl(edx, eax); + movdqu(xmm6, ExternalAddress(mmask)); // 0xffffffc0UL, 0x00000000UL, 0xffffffc0UL, 0x00000000UL + pand(xmm7, xmm6); + movdqu(xmm6, ExternalAddress(bias)); // 0x0000ffc0UL, 0x00000000UL, 0x0000ffc0UL, 0x00000000UL + paddq(xmm7, xmm6); + psllq(xmm7, 46); + subpd(xmm0, xmm3); + lea(tmp, ExternalAddress(Tbl_addr)); + movdqu(xmm2, Address(ecx,tmp)); + mulpd(xmm4, xmm0); + movapd(xmm6, xmm0); + movapd(xmm1, xmm0); + mulpd(xmm6, xmm6); + mulpd(xmm0, xmm6); + addpd(xmm5, xmm4); + mulsd(xmm0, xmm6); + mulpd(xmm6, ExternalAddress(48+cv)); // 0xfffffffeUL, 0x3fdfffffUL, 0xfffffffeUL, 0x3fdfffffUL + addsd(xmm1, xmm2); + unpckhpd(xmm2, xmm2); + mulpd(xmm0, xmm5); + addsd(xmm1, xmm0); + por(xmm2, xmm7); + unpckhpd(xmm0, xmm0); + addsd(xmm0, xmm1); + addsd(xmm0, xmm6); + addl(edx, 894); + cmpl(edx, 1916); + jcc (Assembler::above, L_2TAG_PACKET_1_0_2); + mulsd(xmm0, xmm2); + addsd(xmm0, xmm2); + jmp (B1_5); + + bind(L_2TAG_PACKET_1_0_2); + xorpd(xmm3, xmm3); + movdqu(xmm4, ExternalAddress(ALLONES)); // 0xffffffffUL, 0xffffffffUL, 0xffffffffUL, 0xffffffffUL + movl(edx, -1022); + subl(edx, eax); + movdl(xmm5, edx); + psllq(xmm4, xmm5); + movl(ecx, eax); + sarl(eax, 1); + pinsrw(xmm3, eax, 3); + movdqu(xmm6, ExternalAddress(ebias)); // 0x00000000UL, 0x3ff00000UL, 0x00000000UL, 0x3ff00000UL + psllq(xmm3, 4); + psubd(xmm2, xmm3); + mulsd(xmm0, xmm2); + cmpl(edx, 52); + jcc(Assembler::greater, L_2TAG_PACKET_2_0_2); + pand(xmm4, xmm2); + paddd(xmm3, xmm6); + subsd(xmm2, xmm4); + addsd(xmm0, xmm2); + cmpl(ecx, 1023); + jcc(Assembler::greaterEqual, L_2TAG_PACKET_3_0_2); + pextrw(ecx, xmm0, 3); + andl(ecx, 32768); + orl(edx, ecx); + cmpl(edx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_4_0_2); + movapd(xmm6, xmm0); + addsd(xmm0, xmm4); + mulsd(xmm0, xmm3); + pextrw(ecx, xmm0, 3); + andl(ecx, 32752); + cmpl(ecx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_5_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_5_0_2); + mulsd(xmm6, xmm3); + mulsd(xmm4, xmm3); + movdqu(xmm0, xmm6); + pxor(xmm6, xmm4); + psrad(xmm6, 31); + pshufd(xmm6, xmm6, 85); + psllq(xmm0, 1); + psrlq(xmm0, 1); + pxor(xmm0, xmm6); + psrlq(xmm6, 63); + paddq(xmm0, xmm6); + paddq(xmm0, xmm4); + movl(Address(rsp,0), 15); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_4_0_2); + addsd(xmm0, xmm4); + mulsd(xmm0, xmm3); + jmp(B1_5); + + bind(L_2TAG_PACKET_3_0_2); + addsd(xmm0, xmm4); + mulsd(xmm0, xmm3); + pextrw(ecx, xmm0, 3); + andl(ecx, 32752); + cmpl(ecx, 32752); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_7_0_2); + jmp(B1_5); + + bind(L_2TAG_PACKET_2_0_2); + paddd(xmm3, xmm6); + addpd(xmm0, xmm2); + mulsd(xmm0, xmm3); + movl(Address(rsp,0), 15); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_8_0_2); + cmpl(eax, 2146435072); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_9_0_2); + movl(eax, Address(rsp,12)); + cmpl(eax, INT_MIN); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_10_0_2); + movsd(xmm0, ExternalAddress(XMAX)); // 0xffffffffUL, 0x7fefffffUL + mulsd(xmm0, xmm0); + + bind(L_2TAG_PACKET_7_0_2); + movl(Address(rsp,0), 14); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_10_0_2); + movsd(xmm0, ExternalAddress(XMIN)); // 0x00000000UL, 0x00100000UL + mulsd(xmm0, xmm0); + movl(Address(rsp,0), 15); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_9_0_2); + movl(edx, Address(rsp,8)); + cmpl(eax, 2146435072); + jcc(Assembler::above, L_2TAG_PACKET_11_0_2); + cmpl(edx, 0); + jcc(Assembler::notEqual, L_2TAG_PACKET_11_0_2); + movl(eax, Address(rsp,12)); + cmpl(eax, 2146435072); + jcc(Assembler::notEqual, L_2TAG_PACKET_12_0_2); + movsd(xmm0, ExternalAddress(INF)); // 0x00000000UL, 0x7ff00000UL + jmp(B1_5); + + bind(L_2TAG_PACKET_12_0_2); + movsd(xmm0, ExternalAddress(ZERO)); // 0x00000000UL, 0x00000000UL + jmp(B1_5); + + bind(L_2TAG_PACKET_11_0_2); + movsd(xmm0, Address(rsp, 8)); + addsd(xmm0, xmm0); + jmp(B1_5); + + bind(L_2TAG_PACKET_0_0_2); + movl(eax, Address(rsp, 12)); + andl(eax, 2147483647); + cmpl(eax, 1083179008); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_8_0_2); + movsd(Address(rsp, 8), xmm0); + addsd(xmm0, ExternalAddress(ONE_val)); // 0x00000000UL, 0x3ff00000UL + jmp(B1_5); + + bind(L_2TAG_PACKET_6_0_2); + movq(Address(rsp, 16), xmm0); + + bind(B1_3); + movq(xmm0, Address(rsp, 16)); + + bind(B1_5); + addq(rsp, 24); +} +#endif + +#ifndef _LP64 + +ALIGNED_(16) juint _static_const_table[] = +{ + 0x00000000UL, 0xfff00000UL, 0x00000000UL, 0xfff00000UL, 0xffffffc0UL, + 0x00000000UL, 0xffffffc0UL, 0x00000000UL, 0x0000ffc0UL, 0x00000000UL, + 0x0000ffc0UL, 0x00000000UL, 0x00000000UL, 0x43380000UL, 0x00000000UL, + 0x43380000UL, 0x652b82feUL, 0x40571547UL, 0x652b82feUL, 0x40571547UL, + 0xfefa0000UL, 0x3f862e42UL, 0xfefa0000UL, 0x3f862e42UL, 0xbc9e3b3aUL, + 0x3d1cf79aUL, 0xbc9e3b3aUL, 0x3d1cf79aUL, 0xfffffffeUL, 0x3fdfffffUL, + 0xfffffffeUL, 0x3fdfffffUL, 0xe3289860UL, 0x3f56c15cUL, 0x555b9e25UL, + 0x3fa55555UL, 0xc090cf0fUL, 0x3f811115UL, 0x55548ba1UL, 0x3fc55555UL, + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0e03754dUL, + 0x3cad7bbfUL, 0x3e778060UL, 0x00002c9aUL, 0x3567f613UL, 0x3c8cd252UL, + 0xd3158574UL, 0x000059b0UL, 0x61e6c861UL, 0x3c60f74eUL, 0x18759bc8UL, + 0x00008745UL, 0x5d837b6cUL, 0x3c979aa6UL, 0x6cf9890fUL, 0x0000b558UL, + 0x702f9cd1UL, 0x3c3ebe3dUL, 0x32d3d1a2UL, 0x0000e3ecUL, 0x1e63bcd8UL, + 0x3ca3516eUL, 0xd0125b50UL, 0x00011301UL, 0x26f0387bUL, 0x3ca4c554UL, + 0xaea92ddfUL, 0x0001429aUL, 0x62523fb6UL, 0x3ca95153UL, 0x3c7d517aUL, + 0x000172b8UL, 0x3f1353bfUL, 0x3c8b898cUL, 0xeb6fcb75UL, 0x0001a35bUL, + 0x3e3a2f5fUL, 0x3c9aecf7UL, 0x3168b9aaUL, 0x0001d487UL, 0x44a6c38dUL, + 0x3c8a6f41UL, 0x88628cd6UL, 0x0002063bUL, 0xe3a8a894UL, 0x3c968efdUL, + 0x6e756238UL, 0x0002387aUL, 0x981fe7f2UL, 0x3c80472bUL, 0x65e27cddUL, + 0x00026b45UL, 0x6d09ab31UL, 0x3c82f7e1UL, 0xf51fdee1UL, 0x00029e9dUL, + 0x720c0ab3UL, 0x3c8b3782UL, 0xa6e4030bUL, 0x0002d285UL, 0x4db0abb6UL, + 0x3c834d75UL, 0x0a31b715UL, 0x000306feUL, 0x5dd3f84aUL, 0x3c8fdd39UL, + 0xb26416ffUL, 0x00033c08UL, 0xcc187d29UL, 0x3ca12f8cUL, 0x373aa9caUL, + 0x000371a7UL, 0x738b5e8bUL, 0x3ca7d229UL, 0x34e59ff6UL, 0x0003a7dbUL, + 0xa72a4c6dUL, 0x3c859f48UL, 0x4c123422UL, 0x0003dea6UL, 0x259d9205UL, + 0x3ca8b846UL, 0x21f72e29UL, 0x0004160aUL, 0x60c2ac12UL, 0x3c4363edUL, + 0x6061892dUL, 0x00044e08UL, 0xdaa10379UL, 0x3c6ecce1UL, 0xb5c13cd0UL, + 0x000486a2UL, 0xbb7aafb0UL, 0x3c7690ceUL, 0xd5362a27UL, 0x0004bfdaUL, + 0x9b282a09UL, 0x3ca083ccUL, 0x769d2ca6UL, 0x0004f9b2UL, 0xc1aae707UL, + 0x3ca509b0UL, 0x569d4f81UL, 0x0005342bUL, 0x18fdd78eUL, 0x3c933505UL, + 0x36b527daUL, 0x00056f47UL, 0xe21c5409UL, 0x3c9063e1UL, 0xdd485429UL, + 0x0005ab07UL, 0x2b64c035UL, 0x3c9432e6UL, 0x15ad2148UL, 0x0005e76fUL, + 0x99f08c0aUL, 0x3ca01284UL, 0xb03a5584UL, 0x0006247eUL, 0x0073dc06UL, + 0x3c99f087UL, 0x82552224UL, 0x00066238UL, 0x0da05571UL, 0x3c998d4dUL, + 0x667f3bccUL, 0x0006a09eUL, 0x86ce4786UL, 0x3ca52bb9UL, 0x3c651a2eUL, + 0x0006dfb2UL, 0x206f0dabUL, 0x3ca32092UL, 0xe8ec5f73UL, 0x00071f75UL, + 0x8e17a7a6UL, 0x3ca06122UL, 0x564267c8UL, 0x00075febUL, 0x461e9f86UL, + 0x3ca244acUL, 0x73eb0186UL, 0x0007a114UL, 0xabd66c55UL, 0x3c65ebe1UL, + 0x36cf4e62UL, 0x0007e2f3UL, 0xbbff67d0UL, 0x3c96fe9fUL, 0x994cce12UL, + 0x00082589UL, 0x14c801dfUL, 0x3c951f14UL, 0x9b4492ecUL, 0x000868d9UL, + 0xc1f0eab4UL, 0x3c8db72fUL, 0x422aa0dbUL, 0x0008ace5UL, 0x59f35f44UL, + 0x3c7bf683UL, 0x99157736UL, 0x0008f1aeUL, 0x9c06283cUL, 0x3ca360baUL, + 0xb0cdc5e4UL, 0x00093737UL, 0x20f962aaUL, 0x3c95e8d1UL, 0x9fde4e4fUL, + 0x00097d82UL, 0x2b91ce27UL, 0x3c71affcUL, 0x82a3f090UL, 0x0009c491UL, + 0x589a2ebdUL, 0x3c9b6d34UL, 0x7b5de564UL, 0x000a0c66UL, 0x9ab89880UL, + 0x3c95277cUL, 0xb23e255cUL, 0x000a5503UL, 0x6e735ab3UL, 0x3c846984UL, + 0x5579fdbfUL, 0x000a9e6bUL, 0x92cb3387UL, 0x3c8c1a77UL, 0x995ad3adUL, + 0x000ae89fUL, 0xdc2d1d96UL, 0x3ca22466UL, 0xb84f15faUL, 0x000b33a2UL, + 0xb19505aeUL, 0x3ca1112eUL, 0xf2fb5e46UL, 0x000b7f76UL, 0x0a5fddcdUL, + 0x3c74ffd7UL, 0x904bc1d2UL, 0x000bcc1eUL, 0x30af0cb3UL, 0x3c736eaeUL, + 0xdd85529cUL, 0x000c199bUL, 0xd10959acUL, 0x3c84e08fUL, 0x2e57d14bUL, + 0x000c67f1UL, 0x6c921968UL, 0x3c676b2cUL, 0xdcef9069UL, 0x000cb720UL, + 0x36df99b3UL, 0x3c937009UL, 0x4a07897bUL, 0x000d072dUL, 0xa63d07a7UL, + 0x3c74a385UL, 0xdcfba487UL, 0x000d5818UL, 0xd5c192acUL, 0x3c8e5a50UL, + 0x03db3285UL, 0x000da9e6UL, 0x1c4a9792UL, 0x3c98bb73UL, 0x337b9b5eUL, + 0x000dfc97UL, 0x603a88d3UL, 0x3c74b604UL, 0xe78b3ff6UL, 0x000e502eUL, + 0x92094926UL, 0x3c916f27UL, 0xa2a490d9UL, 0x000ea4afUL, 0x41aa2008UL, + 0x3c8ec3bcUL, 0xee615a27UL, 0x000efa1bUL, 0x31d185eeUL, 0x3c8a64a9UL, + 0x5b6e4540UL, 0x000f5076UL, 0x4d91cd9dUL, 0x3c77893bUL, 0x819e90d8UL, + 0x000fa7c1UL, 0x00000000UL, 0x3ff00000UL, 0x00000000UL, 0x7ff00000UL, + 0x00000000UL, 0x00000000UL, 0xffffffffUL, 0x7fefffffUL, 0x00000000UL, + 0x00100000UL +}; + +//registers, +// input: (rbp + 8) +// scratch: xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 +// rax, rdx, rcx, rbx (tmp) + +// Code generated by Intel C compiler for LIBM library + +void MacroAssembler::fast_exp(XMMRegister xmm0, XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, Register eax, Register ecx, Register edx, Register tmp) { + Label L_2TAG_PACKET_0_0_2, L_2TAG_PACKET_1_0_2, L_2TAG_PACKET_2_0_2, L_2TAG_PACKET_3_0_2; + Label L_2TAG_PACKET_4_0_2, L_2TAG_PACKET_5_0_2, L_2TAG_PACKET_6_0_2, L_2TAG_PACKET_7_0_2; + Label L_2TAG_PACKET_8_0_2, L_2TAG_PACKET_9_0_2, L_2TAG_PACKET_10_0_2, L_2TAG_PACKET_11_0_2; + Label L_2TAG_PACKET_12_0_2, L_2TAG_PACKET_13_0_2, B1_3, B1_5, start; + + assert_different_registers(tmp, eax, ecx, edx); + jmp(start); + address static_const_table = (address)_static_const_table; + + bind(start); + subl(rsp, 120); + movl(Address(rsp, 64), tmp); + lea(tmp, ExternalAddress(static_const_table)); + movdqu(xmm0, Address(rsp, 128)); + unpcklpd(xmm0, xmm0); + movdqu(xmm1, Address(tmp, 64)); // 0x652b82feUL, 0x40571547UL, 0x652b82feUL, 0x40571547UL + movdqu(xmm6, Address(tmp, 48)); // 0x00000000UL, 0x43380000UL, 0x00000000UL, 0x43380000UL + movdqu(xmm2, Address(tmp, 80)); // 0xfefa0000UL, 0x3f862e42UL, 0xfefa0000UL, 0x3f862e42UL + movdqu(xmm3, Address(tmp, 96)); // 0xbc9e3b3aUL, 0x3d1cf79aUL, 0xbc9e3b3aUL, 0x3d1cf79aUL + pextrw(eax, xmm0, 3); + andl(eax, 32767); + movl(edx, 16527); + subl(edx, eax); + subl(eax, 15504); + orl(edx, eax); + cmpl(edx, INT_MIN); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_2); + mulpd(xmm1, xmm0); + addpd(xmm1, xmm6); + movapd(xmm7, xmm1); + subpd(xmm1, xmm6); + mulpd(xmm2, xmm1); + movdqu(xmm4, Address(tmp, 128)); // 0xe3289860UL, 0x3f56c15cUL, 0x555b9e25UL, 0x3fa55555UL + mulpd(xmm3, xmm1); + movdqu(xmm5, Address(tmp, 144)); // 0xc090cf0fUL, 0x3f811115UL, 0x55548ba1UL, 0x3fc55555UL + subpd(xmm0, xmm2); + movdl(eax, xmm7); + movl(ecx, eax); + andl(ecx, 63); + shll(ecx, 4); + sarl(eax, 6); + movl(edx, eax); + movdqu(xmm6, Address(tmp, 16)); // 0xffffffc0UL, 0x00000000UL, 0xffffffc0UL, 0x00000000UL + pand(xmm7, xmm6); + movdqu(xmm6, Address(tmp, 32)); // 0x0000ffc0UL, 0x00000000UL, 0x0000ffc0UL, 0x00000000UL + paddq(xmm7, xmm6); + psllq(xmm7, 46); + subpd(xmm0, xmm3); + movdqu(xmm2, Address(tmp, ecx, Address::times_1, 160)); + mulpd(xmm4, xmm0); + movapd(xmm6, xmm0); + movapd(xmm1, xmm0); + mulpd(xmm6, xmm6); + mulpd(xmm0, xmm6); + addpd(xmm5, xmm4); + mulsd(xmm0, xmm6); + mulpd(xmm6, Address(tmp, 112)); // 0xfffffffeUL, 0x3fdfffffUL, 0xfffffffeUL, 0x3fdfffffUL + addsd(xmm1, xmm2); + unpckhpd(xmm2, xmm2); + mulpd(xmm0, xmm5); + addsd(xmm1, xmm0); + por(xmm2, xmm7); + unpckhpd(xmm0, xmm0); + addsd(xmm0, xmm1); + addsd(xmm0, xmm6); + addl(edx, 894); + cmpl(edx, 1916); + jcc (Assembler::above, L_2TAG_PACKET_1_0_2); + mulsd(xmm0, xmm2); + addsd(xmm0, xmm2); + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_1_0_2); + fnstcw(Address(rsp, 24)); + movzwl(edx, Address(rsp, 24)); + orl(edx, 768); + movw(Address(rsp, 28), edx); + fldcw(Address(rsp, 28)); + movl(edx, eax); + sarl(eax, 1); + subl(edx, eax); + movdqu(xmm6, Address(tmp, 0)); // 0x00000000UL, 0xfff00000UL, 0x00000000UL, 0xfff00000UL + pandn(xmm6, xmm2); + addl(eax, 1023); + movdl(xmm3, eax); + psllq(xmm3, 52); + por(xmm6, xmm3); + addl(edx, 1023); + movdl(xmm4, edx); + psllq(xmm4, 52); + movsd(Address(rsp, 8), xmm0); + fld_d(Address(rsp, 8)); + movsd(Address(rsp, 16), xmm6); + fld_d(Address(rsp, 16)); + fmula(1); + faddp(1); + movsd(Address(rsp, 8), xmm4); + fld_d(Address(rsp, 8)); + fmulp(1); + fstp_d(Address(rsp, 8)); + movsd(xmm0,Address(rsp, 8)); + fldcw(Address(rsp, 24)); + pextrw(ecx, xmm0, 3); + andl(ecx, 32752); + cmpl(ecx, 32752); + jcc(Assembler::greaterEqual, L_2TAG_PACKET_3_0_2); + cmpl(ecx, 0); + jcc(Assembler::equal, L_2TAG_PACKET_4_0_2); + jmp(L_2TAG_PACKET_2_0_2); + cmpl(ecx, INT_MIN); + jcc(Assembler::less, L_2TAG_PACKET_3_0_2); + cmpl(ecx, -1064950997); + jcc(Assembler::less, L_2TAG_PACKET_2_0_2); + jcc(Assembler::greater, L_2TAG_PACKET_4_0_2); + movl(edx, Address(rsp, 128)); + cmpl(edx ,-17155601); + jcc(Assembler::less, L_2TAG_PACKET_2_0_2); + jmp(L_2TAG_PACKET_4_0_2); + + bind(L_2TAG_PACKET_3_0_2); + movl(edx, 14); + jmp(L_2TAG_PACKET_5_0_2); + + bind(L_2TAG_PACKET_4_0_2); + movl(edx, 15); + + bind(L_2TAG_PACKET_5_0_2); + movsd(Address(rsp, 0), xmm0); + movsd(xmm0, Address(rsp, 128)); + fld_d(Address(rsp, 0)); + jmp(L_2TAG_PACKET_6_0_2); + + bind(L_2TAG_PACKET_7_0_2); + cmpl(eax, 2146435072); + jcc(Assembler::greaterEqual, L_2TAG_PACKET_8_0_2); + movl(eax, Address(rsp, 132)); + cmpl(eax, INT_MIN); + jcc(Assembler::greaterEqual, L_2TAG_PACKET_9_0_2); + movsd(xmm0, Address(tmp, 1208)); // 0xffffffffUL, 0x7fefffffUL + mulsd(xmm0, xmm0); + movl(edx, 14); + jmp(L_2TAG_PACKET_5_0_2); + + bind(L_2TAG_PACKET_9_0_2); + movsd(xmm0, Address(tmp, 1216)); + mulsd(xmm0, xmm0); + movl(edx, 15); + jmp(L_2TAG_PACKET_5_0_2); + + bind(L_2TAG_PACKET_8_0_2); + movl(edx, Address(rsp, 128)); + cmpl(eax, 2146435072); + jcc(Assembler::above, L_2TAG_PACKET_10_0_2); + cmpl(edx, 0); + jcc(Assembler::notEqual, L_2TAG_PACKET_10_0_2); + movl(eax, Address(rsp, 132)); + cmpl(eax, 2146435072); + jcc(Assembler::notEqual, L_2TAG_PACKET_11_0_2); + movsd(xmm0, Address(tmp, 1192)); // 0x00000000UL, 0x7ff00000UL + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_11_0_2); + movsd(xmm0, Address(tmp, 1200)); // 0x00000000UL, 0x00000000UL + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_10_0_2); + movsd(xmm0, Address(rsp, 128)); + addsd(xmm0, xmm0); + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_0_0_2); + movl(eax, Address(rsp, 132)); + andl(eax, 2147483647); + cmpl(eax, 1083179008); + jcc(Assembler::aboveEqual, L_2TAG_PACKET_7_0_2); + movsd(xmm0, Address(rsp, 128)); + addsd(xmm0, Address(tmp, 1184)); // 0x00000000UL, 0x3ff00000UL + jmp(L_2TAG_PACKET_2_0_2); + + bind(L_2TAG_PACKET_2_0_2); + movsd(Address(rsp, 48), xmm0); + fld_d(Address(rsp, 48)); + + bind(L_2TAG_PACKET_6_0_2); + movl(tmp, Address(rsp, 64)); +} + +#endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/methodHandles_x86.cpp --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,8 +30,6 @@ #include "memory/allocation.inline.hpp" #include "prims/methodHandles.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #define __ _masm-> #ifdef PRODUCT @@ -53,7 +51,7 @@ #ifdef ASSERT static int check_nonzero(const char* xname, int x) { - assert(x != 0, err_msg("%s should be nonzero", xname)); + assert(x != 0, "%s should be nonzero", xname); return x; } #define NONZERO(x) check_nonzero(#x, x) @@ -456,7 +454,7 @@ } default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } @@ -488,7 +486,7 @@ const char* mh_reg_name = has_mh ? "rcx_mh" : "rcx"; tty->print_cr("MH %s %s=" PTR_FORMAT " sp=" PTR_FORMAT, adaptername, mh_reg_name, - (void *)mh, entry_sp); + p2i(mh), p2i(entry_sp)); if (Verbose) { tty->print_cr("Registers:"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/nativeInst_x86.cpp --- a/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -35,18 +35,15 @@ #include "c1/c1_Runtime1.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void NativeInstruction::wrote(int offset) { ICache::invalidate_word(addr_at(offset)); } - void NativeCall::verify() { // Make sure code pattern is actually a call imm32 instruction. int inst = ubyte_at(0); if (inst != instruction_code) { - tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", instruction_address(), + tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()), inst); fatal("not a call disp32"); } @@ -63,7 +60,7 @@ void NativeCall::print() { tty->print_cr(PTR_FORMAT ": call " PTR_FORMAT, - instruction_address(), destination()); + p2i(instruction_address()), p2i(destination())); } // Inserts a native call instruction at a given pc @@ -230,7 +227,7 @@ void NativeMovConstReg::print() { tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT, - instruction_address(), data()); + p2i(instruction_address()), data()); } //------------------------------------------------------------------- @@ -396,7 +393,7 @@ void NativeMovRegMem::print() { - tty->print_cr("0x%x: mov reg, [reg + %x]", instruction_address(), offset()); + tty->print_cr(PTR_FORMAT ": mov reg, [reg + %x]", p2i(instruction_address()), offset()); } //------------------------------------------------------------------- @@ -418,7 +415,7 @@ void NativeLoadAddress::print() { - tty->print_cr("0x%x: lea [reg + %x], reg", instruction_address(), offset()); + tty->print_cr(PTR_FORMAT ": lea [reg + %x], reg", p2i(instruction_address()), offset()); } //-------------------------------------------------------------------------------- @@ -474,6 +471,7 @@ // // In C2 the 5+ byte sized instruction is enforced by code in MachPrologNode::emit. // In C1 the restriction is enforced by CodeEmitter::method_entry +// In JVMCI, the restriction is enforced by HotSpotFrameContext.enter(...) // void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { // complete jump instruction (to be inserted) is in code_buffer; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/nativeInst_x86.hpp --- a/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/nativeInst_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -60,6 +60,7 @@ bool is_nop() { return ubyte_at(0) == nop_instruction_code; } inline bool is_call(); + inline bool is_call_reg(); inline bool is_illegal(); inline bool is_return(); inline bool is_jump(); @@ -180,6 +181,24 @@ return call; } +class NativeCallReg: public NativeInstruction { + public: + enum Intel_specific_constants { + instruction_code = 0xFF, + instruction_offset = 0, + return_address_offset_norex = 2, + return_address_offset_rex = 3 + }; + + int next_instruction_offset() const { + if (ubyte_at(0) == NativeCallReg::instruction_code) { + return return_address_offset_norex; + } else { + return return_address_offset_rex; + } + } +}; + // An interface for accessing/manipulating native mov reg, imm32 instructions. // (used to manipulate inlined 32bit data dll calls, etc.) class NativeMovConstReg: public NativeInstruction { @@ -519,6 +538,9 @@ inline bool NativeInstruction::is_illegal() { return (short)int_at(0) == (short)NativeIllegalInstruction::instruction_code; } inline bool NativeInstruction::is_call() { return ubyte_at(0) == NativeCall::instruction_code; } +inline bool NativeInstruction::is_call_reg() { return ubyte_at(0) == NativeCallReg::instruction_code || + (ubyte_at(1) == NativeCallReg::instruction_code && + (ubyte_at(0) == Assembler::REX || ubyte_at(0) == Assembler::REX_B)); } inline bool NativeInstruction::is_return() { return ubyte_at(0) == NativeReturn::instruction_code || ubyte_at(0) == NativeReturnX::instruction_code; } inline bool NativeInstruction::is_jump() { return ubyte_at(0) == NativeJump::instruction_code || @@ -527,26 +549,24 @@ (ubyte_at(0) & 0xF0) == 0x70; /* short jump */ } inline bool NativeInstruction::is_safepoint_poll() { #ifdef AMD64 - if (Assembler::is_polling_page_far()) { - // two cases, depending on the choice of the base register in the address. - if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix && - ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl && - (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) || - ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && - (ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) { - return true; - } else { - return false; - } - } else { - if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && - ubyte_at(1) == 0x05) { // 00 rax 101 - address fault = addr_at(6) + int_at(2); - return os::is_poll_address(fault); - } else { - return false; - } + // Try decoding a near safepoint first: + if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && + ubyte_at(1) == 0x05) { // 00 rax 101 + address fault = addr_at(6) + int_at(2); + NOT_JVMCI(assert(!Assembler::is_polling_page_far(), "unexpected poll encoding");) + return os::is_poll_address(fault); } + // Now try decoding a far safepoint: + // two cases, depending on the choice of the base register in the address. + if (((ubyte_at(0) & NativeTstRegMem::instruction_rex_prefix_mask) == NativeTstRegMem::instruction_rex_prefix && + ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl && + (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) || + ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && + (ubyte_at(1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg) { + NOT_JVMCI(assert(Assembler::is_polling_page_far(), "unexpected poll encoding");) + return true; + } + return false; #else return ( ubyte_at(0) == NativeMovRegMem::instruction_code_mem2reg || ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl ) && diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/registerMap_x86.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/x86/vm/registerMap_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "runtime/registerMap.hpp" +#include "vmreg_x86.inline.hpp" + +address RegisterMap::pd_location(VMReg reg) const { + if (reg->is_XMMRegister()) { + int regBase = reg->value() - ConcreteRegisterImpl::max_fpr; + if (regBase % 4 == 0) { + // Reads of the low and high 16 byte parts should be handled by location itself + // because they have separate callee saved entries. + // See RegisterSaver::save_live_registers(). + return NULL; + } + VMReg baseReg = as_XMMRegister(regBase / XMMRegisterImpl::max_slots_per_register)->as_VMReg(); + intptr_t offset = (reg->value() - baseReg->value()) * VMRegImpl::stack_slot_size; // offset in bytes + if (offset >= 16) { + // The high part of YMM registers are saved in a their own area in the frame + baseReg = baseReg->next()->next()->next()->next(); + offset -= 16; + } + address baseLocation = location(baseReg); + if (baseLocation != NULL) { + return baseLocation + offset; + } + } + return NULL; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/registerMap_x86.hpp --- a/hotspot/src/cpu/x86/vm/registerMap_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/registerMap_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,11 +31,7 @@ private: // This is the hook for finding a register in an "well-known" location, // such as a register block of a predetermined format. - // Since there is none, we just return NULL. - // See registerMap_sparc.hpp for an example of grabbing registers - // from register save areas of a standard layout. - address pd_location(VMReg reg) const {return NULL;} - + address pd_location(VMReg reg) const; // no PD state to clear or copy: void pd_clear() {} void pd_initialize() {} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/register_x86.cpp --- a/hotspot/src/cpu/x86/vm/register_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/register_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -69,6 +69,31 @@ return is_valid() ? names[encoding()] : "xnoreg"; } +const char* XMMRegisterImpl::sub_word_name(int i) const { + const char* names[number_of_registers * 8] = { + "xmm0:0", "xmm0:1", "xmm0:2", "xmm0:3", "xmm0:4", "xmm0:5", "xmm0:6", "xmm0:7", + "xmm1:0", "xmm1:1", "xmm1:2", "xmm1:3", "xmm1:4", "xmm1:5", "xmm1:6", "xmm1:7", + "xmm2:0", "xmm2:1", "xmm2:2", "xmm2:3", "xmm2:4", "xmm2:5", "xmm2:6", "xmm2:7", + "xmm3:0", "xmm3:1", "xmm3:2", "xmm3:3", "xmm3:4", "xmm3:5", "xmm3:6", "xmm3:7", + "xmm4:0", "xmm4:1", "xmm4:2", "xmm4:3", "xmm4:4", "xmm4:5", "xmm4:6", "xmm4:7", + "xmm5:0", "xmm5:1", "xmm5:2", "xmm5:3", "xmm5:4", "xmm5:5", "xmm5:6", "xmm5:7", + "xmm6:0", "xmm6:1", "xmm6:2", "xmm6:3", "xmm6:4", "xmm6:5", "xmm6:6", "xmm6:7", + "xmm7:0", "xmm7:1", "xmm7:2", "xmm7:3", "xmm7:4", "xmm7:5", "xmm7:6", "xmm7:7", +#ifdef AMD64 + "xmm8:0", "xmm8:1", "xmm8:2", "xmm8:3", "xmm8:4", "xmm8:5", "xmm8:6", "xmm8:7", + "xmm9:0", "xmm9:1", "xmm9:2", "xmm9:3", "xmm9:4", "xmm9:5", "xmm9:6", "xmm9:7", + "xmm10:0", "xmm10:1", "xmm10:2", "xmm10:3", "xmm10:4", "xmm10:5", "xmm10:6", "xmm10:7", + "xmm11:0", "xmm11:1", "xmm11:2", "xmm11:3", "xmm11:4", "xmm11:5", "xmm11:6", "xmm11:7", + "xmm12:0", "xmm12:1", "xmm12:2", "xmm12:3", "xmm12:4", "xmm12:5", "xmm12:6", "xmm12:7", + "xmm13:0", "xmm13:1", "xmm13:2", "xmm13:3", "xmm13:4", "xmm13:5", "xmm13:6", "xmm13:7", + "xmm14:0", "xmm14:1", "xmm14:2", "xmm14:3", "xmm14:4", "xmm14:5", "xmm14:6", "xmm14:7", + "xmm15:0", "xmm15:1", "xmm15:2", "xmm15:3", "xmm15:4", "xmm15:5", "xmm15:6", "xmm15:7", +#endif // AMD64 + }; + assert(i >= 0 && i < 8, "offset too large"); + return is_valid() ? names[encoding() * 8 + i] : "xnoreg"; +} + const char* KRegisterImpl::name() const { const char* names[number_of_registers] = { "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7" diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/register_x86.hpp --- a/hotspot/src/cpu/x86/vm/register_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/register_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -162,9 +162,10 @@ XMMRegister successor() const { return as_XMMRegister(encoding() + 1); } // accessors - int encoding() const { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this )); return (intptr_t)this; } + int encoding() const { assert(is_valid(), "invalid register (%d)", (int)(intptr_t)this ); return (intptr_t)this; } bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } const char* name() const; + const char* sub_word_name(int offset) const; }; @@ -245,7 +246,7 @@ KRegister successor() const { return as_KRegister(encoding() + 1); } // accessors - int encoding() const { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this)); return (intptr_t)this; } + int encoding() const { assert(is_valid(), "invalid register (%d)", (int)(intptr_t)this); return (intptr_t)this; } bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; } const char* name() const; }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/relocInfo_x86.cpp --- a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -180,39 +180,17 @@ void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { #ifdef _LP64 - if (!Assembler::is_polling_page_far()) { - typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); - // This format is imm but it is really disp32 - which = Assembler::disp32_operand; + typedef Assembler::WhichOperand WhichOperand; + WhichOperand which = (WhichOperand) format(); +#if !INCLUDE_JVMCI + assert((which == Assembler::disp32_operand) == !Assembler::is_polling_page_far(), "format not set correctly"); +#endif + if (which == Assembler::disp32_operand) { address orig_addr = old_addr_for(addr(), src, dest); NativeInstruction* oni = nativeInstruction_at(orig_addr); int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); // This poll_addr is incorrect by the size of the instruction it is irrelevant intptr_t poll_addr = (intptr_t)oni + *orig_disp; - - NativeInstruction* ni = nativeInstruction_at(addr()); - intptr_t new_disp = poll_addr - (intptr_t) ni; - - int32_t* disp = (int32_t*) Assembler::locate_operand(addr(), which); - * disp = (int32_t)new_disp; - } -#endif // _LP64 -} - -void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -#ifdef _LP64 - if (!Assembler::is_polling_page_far()) { - typedef Assembler::WhichOperand WhichOperand; - WhichOperand which = (WhichOperand) format(); - // This format is imm but it is really disp32 - which = Assembler::disp32_operand; - address orig_addr = old_addr_for(addr(), src, dest); - NativeInstruction* oni = nativeInstruction_at(orig_addr); - int32_t* orig_disp = (int32_t*) Assembler::locate_operand(orig_addr, which); - // This poll_addr is incorrect by the size of the instruction it is irrelevant - intptr_t poll_addr = (intptr_t)oni + *orig_disp; - NativeInstruction* ni = nativeInstruction_at(addr()); intptr_t new_disp = poll_addr - (intptr_t) ni; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -699,12 +699,11 @@ __ bind(L_fail); } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { - +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Note: rsi contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled // code goes non-entrant while we get args ready. @@ -1434,7 +1433,7 @@ } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -43,6 +43,9 @@ #ifdef COMPILER2 #include "opto/runtime.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif #define __ masm-> @@ -158,23 +161,25 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) { int vect_words = 0; + int ymmhi_offset = -1; int off = 0; int num_xmm_regs = XMMRegisterImpl::number_of_registers; if (UseAVX < 3) { num_xmm_regs = num_xmm_regs/2; } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (save_vectors) { assert(UseAVX > 0, "512bit vectors are supported only with EVEX"); assert(MaxVectorSize == 64, "only 512bit vectors are supported now"); // Save upper half of YMM registers vect_words = 16 * num_xmm_regs / wordSize; if (UseAVX < 3) { + ymmhi_offset = additional_frame_words; additional_frame_words += vect_words; } } #else - assert(!save_vectors, "vectors are generated only by C2"); + assert(!save_vectors, "vectors are generated only by C2 and JVMCI"); #endif // Always make the frame size 16-byte aligned @@ -220,6 +225,7 @@ OopMap* map = new OopMap(frame_size_in_slots, 0); #define STACK_OFFSET(x) VMRegImpl::stack2reg((x) + additional_frame_slots) +#define YMMHI_STACK_OFFSET(x) VMRegImpl::stack2reg((x / VMRegImpl::stack_slot_size) + ymmhi_offset) map->set_callee_saved(STACK_OFFSET( rax_off ), rax->as_VMReg()); map->set_callee_saved(STACK_OFFSET( rcx_off ), rcx->as_VMReg()); @@ -257,6 +263,28 @@ } } +#if defined(COMPILER2) || INCLUDE_JVMCI + if (save_vectors) { + assert(ymmhi_offset != -1, "save area must exist"); + map->set_callee_saved(YMMHI_STACK_OFFSET( 0), xmm0->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 16), xmm1->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 32), xmm2->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 48), xmm3->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 64), xmm4->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 80), xmm5->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET( 96), xmm6->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(112), xmm7->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(128), xmm8->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(144), xmm9->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(160), xmm10->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(176), xmm11->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(192), xmm12->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(208), xmm13->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(224), xmm14->as_VMReg()->next(4)); + map->set_callee_saved(YMMHI_STACK_OFFSET(240), xmm15->as_VMReg()->next(4)); + } +#endif // COMPILER2 || INCLUDE_JVMCI + // %%% These should all be a waste but we'll keep things as they were for now if (true) { map->set_callee_saved(STACK_OFFSET( raxH_off ), rax->as_VMReg()->next()); @@ -307,7 +335,7 @@ // Pop arg register save area __ addptr(rsp, frame::arg_reg_save_area_bytes); } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // On EVEX enabled targets everything is handled in pop fpu state if ((restore_vectors) && (UseAVX < 3)) { assert(UseAVX > 0, "256/512-bit vectors are supported only with AVX"); @@ -320,7 +348,7 @@ __ addptr(rsp, num_xmm_regs*16); } #else - assert(!restore_vectors, "vectors are generated only by C2"); + assert(!restore_vectors, "vectors are generated only by C2 and JVMCI"); #endif // Recover CPU state __ pop_CPU_state(); @@ -655,11 +683,11 @@ __ bind(L_fail); } -static void gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { // Note: r13 contains the senderSP on entry. We must preserve it since // we may do a i2c -> c2i transition if we lose a race where compiled @@ -752,6 +780,18 @@ // Pre-load the register-jump target early, to schedule it better. __ movptr(r11, Address(rbx, in_bytes(Method::from_compiled_offset()))); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // check if this call should be routed towards a specific entry point + __ cmpptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0); + Label no_alternative_target; + __ jcc(Assembler::equal, no_alternative_target); + __ movptr(r11, Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); + __ movptr(Address(r15_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), 0); + __ bind(no_alternative_target); + } +#endif // INCLUDE_JVMCI + // Now generate the shuffle code. Pick up all register args and move the // rest through the floating point stack top. for (int i = 0; i < total_args_passed; i++) { @@ -1695,7 +1735,7 @@ } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg_res("unexpected intrinsic id %d", iid)); + fatal("unexpected intrinsic id %d", iid); } if (member_reg != noreg) { @@ -2685,7 +2725,13 @@ // Allocate space for the code ResourceMark rm; // Setup code generation tools - CodeBuffer buffer("deopt_blob", 2048, 1024); + int pad = 0; +#if INCLUDE_JVMCI + if (EnableJVMCI) { + pad += 512; // Increase the buffer size when compiling for JVMCI + } +#endif + CodeBuffer buffer("deopt_blob", 2048+pad, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; OopMap* map = NULL; @@ -2734,6 +2780,12 @@ __ jmp(cont); int reexecute_offset = __ pc() - start; +#if INCLUDE_JVMCI && !defined(COMPILER1) + if (EnableJVMCI && UseJVMCICompiler) { + // JVMCI does not use this kind of deoptimization + __ should_not_reach_here(); + } +#endif // Reexecute case // return address is the pc describes what bci to do re-execute at @@ -2744,6 +2796,38 @@ __ movl(r14, Deoptimization::Unpack_reexecute); // callee-saved __ jmp(cont); +#if INCLUDE_JVMCI + Label after_fetch_unroll_info_call; + int implicit_exception_uncommon_trap_offset = 0; + int uncommon_trap_offset = 0; + + if (EnableJVMCI) { + implicit_exception_uncommon_trap_offset = __ pc() - start; + + __ pushptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); + __ movptr(Address(r15_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset())), (int32_t)NULL_WORD); + + uncommon_trap_offset = __ pc() - start; + + // Save everything in sight. + RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words); + // fetch_unroll_info needs to call last_java_frame() + __ set_last_Java_frame(noreg, noreg, NULL); + + __ movl(c_rarg1, Address(r15_thread, in_bytes(JavaThread::pending_deoptimization_offset()))); + __ movl(Address(r15_thread, in_bytes(JavaThread::pending_deoptimization_offset())), -1); + + __ movl(r14, (int32_t)Deoptimization::Unpack_reexecute); + __ mov(c_rarg0, r15_thread); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); + oop_maps->add_gc_map( __ pc()-start, map->deep_copy()); + + __ reset_last_Java_frame(false, false); + + __ jmp(after_fetch_unroll_info_call); + } // EnableJVMCI +#endif // INCLUDE_JVMCI + int exception_offset = __ pc() - start; // Prolog for exception case @@ -2829,6 +2913,12 @@ __ reset_last_Java_frame(false, false); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + __ bind(after_fetch_unroll_info_call); + } +#endif + // Load UnrollBlock* into rdi __ mov(rdi, rax); @@ -3003,6 +3093,12 @@ _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); + _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); + } +#endif } #ifdef COMPILER2 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -2135,14 +2135,6 @@ __ ret(0); } { - StubCodeMark mark(this, "StubRoutines", "exp"); - StubRoutines::_intrinsic_exp = (double (*)(double)) __ pc(); - - __ fld_d(Address(rsp, 4)); - __ exp_with_fallback(0); - __ ret(0); - } - { StubCodeMark mark(this, "StubRoutines", "pow"); StubRoutines::_intrinsic_pow = (double (*)(double,double)) __ pc(); @@ -2991,6 +2983,89 @@ return start; } + /** + * Arguments: + * + * Inputs: + * rsp(4) - int crc + * rsp(8) - byte* buf + * rsp(12) - int length + * rsp(16) - table_start - optional (present only when doing a library_calll, + * not used by x86 algorithm) + * + * Ouput: + * rax - int crc result + */ + address generate_updateBytesCRC32C(bool is_pclmulqdq_supported) { + assert(UseCRC32CIntrinsics, "need SSE4_2"); + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32C"); + address start = __ pc(); + const Register crc = rax; // crc + const Register buf = rcx; // source java byte array address + const Register len = rdx; // length + const Register d = rbx; + const Register g = rsi; + const Register h = rdi; + const Register empty = 0; // will never be used, in order not + // to change a signature for crc32c_IPL_Alg2_Alt2 + // between 64/32 I'm just keeping it here + assert_different_registers(crc, buf, len, d, g, h); + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + Address crc_arg(rsp, 4 + 4 + 0); // ESP+4 + + // we need to add additional 4 because __ enter + // have just pushed ebp on a stack + Address buf_arg(rsp, 4 + 4 + 4); + Address len_arg(rsp, 4 + 4 + 8); + // Load up: + __ movl(crc, crc_arg); + __ movl(buf, buf_arg); + __ movl(len, len_arg); + __ push(d); + __ push(g); + __ push(h); + __ crc32c_ipl_alg2_alt2(crc, buf, len, + d, g, h, + empty, empty, empty, + xmm0, xmm1, xmm2, + is_pclmulqdq_supported); + __ pop(h); + __ pop(g); + __ pop(d); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + } + + address generate_libmExp() { + address start = __ pc(); + + const XMMRegister x0 = xmm0; + const XMMRegister x1 = xmm1; + const XMMRegister x2 = xmm2; + const XMMRegister x3 = xmm3; + + const XMMRegister x4 = xmm4; + const XMMRegister x5 = xmm5; + const XMMRegister x6 = xmm6; + const XMMRegister x7 = xmm7; + + const Register tmp = rbx; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + __ fast_exp(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + + } + + // Safefetch stubs. void generate_safefetch(const char* name, int size, address* entry, address* fault_pc, address* continuation_pc) { @@ -3204,6 +3279,16 @@ StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table; StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32(); } + + if (UseCRC32CIntrinsics) { + bool supports_clmul = VM_Version::supports_clmul(); + StubRoutines::x86::generate_CRC32C_table(supports_clmul); + StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table; + StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul); + } + if (VM_Version::supports_sse2()) { + StubRoutines::_dexp = generate_libmExp(); + } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -3039,19 +3039,6 @@ __ ret(0); } { - StubCodeMark mark(this, "StubRoutines", "exp"); - StubRoutines::_intrinsic_exp = (double (*)(double)) __ pc(); - - __ subq(rsp, 8); - __ movdbl(Address(rsp, 0), xmm0); - __ fld_d(Address(rsp, 0)); - __ exp_with_fallback(0); - __ fstp_d(Address(rsp, 0)); - __ movdbl(xmm0, Address(rsp, 0)); - __ addq(rsp, 8); - __ ret(0); - } - { StubCodeMark mark(this, "StubRoutines", "pow"); StubRoutines::_intrinsic_pow = (double (*)(double,double)) __ pc(); @@ -3958,6 +3945,64 @@ return start; } + /** + * Arguments: + * + * Inputs: + * c_rarg0 - int crc + * c_rarg1 - byte* buf + * c_rarg2 - long length + * c_rarg3 - table_start - optional (present only when doing a library_calll, + * not used by x86 algorithm) + * + * Ouput: + * rax - int crc result + */ + address generate_updateBytesCRC32C(bool is_pclmulqdq_supported) { + assert(UseCRC32CIntrinsics, "need SSE4_2"); + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32C"); + address start = __ pc(); + //reg.arg int#0 int#1 int#2 int#3 int#4 int#5 float regs + //Windows RCX RDX R8 R9 none none XMM0..XMM3 + //Lin / Sol RDI RSI RDX RCX R8 R9 XMM0..XMM7 + const Register crc = c_rarg0; // crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; // length + const Register a = rax; + const Register j = r9; + const Register k = r10; + const Register l = r11; +#ifdef _WIN64 + const Register y = rdi; + const Register z = rsi; +#else + const Register y = rcx; + const Register z = r8; +#endif + assert_different_registers(crc, buf, len, a, j, k, l, y, z); + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame +#ifdef _WIN64 + __ push(y); + __ push(z); +#endif + __ crc32c_ipl_alg2_alt2(crc, buf, len, + a, j, k, + l, y, z, + c_farg0, c_farg1, c_farg2, + is_pclmulqdq_supported); + __ movl(rax, crc); +#ifdef _WIN64 + __ pop(z); + __ pop(y); +#endif + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + } /** * Arguments: @@ -4122,6 +4167,44 @@ return start; } + address generate_libmExp() { + address start = __ pc(); + + const XMMRegister x0 = xmm0; + const XMMRegister x1 = xmm1; + const XMMRegister x2 = xmm2; + const XMMRegister x3 = xmm3; + + const XMMRegister x4 = xmm4; + const XMMRegister x5 = xmm5; + const XMMRegister x6 = xmm6; + const XMMRegister x7 = xmm7; + + const Register tmp = r11; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + +#ifdef _WIN64 + // save the xmm registers which must be preserved 6-7 + __ movdqu(xmm_save(6), as_XMMRegister(6)); + __ movdqu(xmm_save(7), as_XMMRegister(7)); +#endif + __ fast_exp(x0, x1, x2, x3, x4, x5, x6, x7, rax, rcx, rdx, tmp); + +#ifdef _WIN64 + // restore xmm regs belonging to calling function + __ movdqu(as_XMMRegister(6), xmm_save(6)); + __ movdqu(as_XMMRegister(7), xmm_save(7)); +#endif + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + + } + #undef __ #define __ masm-> @@ -4302,6 +4385,14 @@ StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table; StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32(); } + + if (UseCRC32CIntrinsics) { + bool supports_clmul = VM_Version::supports_clmul(); + StubRoutines::x86::generate_CRC32C_table(supports_clmul); + StubRoutines::_crc32c_table_addr = (address)StubRoutines::x86::_crc32c_table; + StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(supports_clmul); + } + StubRoutines::_dexp = generate_libmExp(); } void generate_all() { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -27,6 +27,7 @@ #include "runtime/frame.inline.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" +#include "crc32c.h" // Implementation of the platform-specific part of StubRoutines - for // a description of how to extend it, see the stubRoutines.hpp file. @@ -130,3 +131,107 @@ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL }; + +#define D 32 +#define P 0x82F63B78 // Reflection of Castagnoli (0x11EDC6F41) + +#define TILL_CYCLE 31 +uint32_t _crc32c_pow_2k_table[TILL_CYCLE]; // because _crc32c_pow_2k_table[TILL_CYCLE == 31] == _crc32c_pow_2k_table[0] + +// A. Kadatch and B. Jenkins / Everything we know about CRC but afraid to forget September 3, 2010 8 +// Listing 1: Multiplication of normalized polynomials +// "a" and "b" occupy D least significant bits. +uint32_t crc32c_multiply(uint32_t a, uint32_t b) { + uint32_t product = 0; + uint32_t b_pow_x_table[D + 1]; // b_pow_x_table[k] = (b * x**k) mod P + b_pow_x_table[0] = b; + for (int k = 0; k < D; ++k) { + // If "a" has non-zero coefficient at x**k,/ add ((b * x**k) mod P) to the result. + if ((a & (uint64_t)(1 << (D - 1 - k))) != 0) product ^= b_pow_x_table[k]; + + // Compute b_pow_x_table[k+1] = (b ** x**(k+1)) mod P. + if (b_pow_x_table[k] & 1) { + // If degree of (b_pow_x_table[k] * x) is D, then + // degree of (b_pow_x_table[k] * x - P) is less than D. + b_pow_x_table[k + 1] = (b_pow_x_table[k] >> 1) ^ P; + } + else { + b_pow_x_table[k + 1] = b_pow_x_table[k] >> 1; + } + } + return product; +} +#undef D +#undef P + +// A. Kadatch and B. Jenkins / Everything we know about CRC but afraid to forget September 3, 2010 9 +void crc32c_init_pow_2k(void) { + // _crc32c_pow_2k_table(0) = + // x^(2^k) mod P(x) = x mod P(x) = x + // Since we are operating on a reflected values + // x = 10b, reflect(x) = 0x40000000 + _crc32c_pow_2k_table[0] = 0x40000000; + + for (int k = 1; k < TILL_CYCLE; k++) { + // _crc32c_pow_2k_table(k+1) = _crc32c_pow_2k_table(k-1)^2 mod P(x) + uint32_t tmp = _crc32c_pow_2k_table[k - 1]; + _crc32c_pow_2k_table[k] = crc32c_multiply(tmp, tmp); + } +} + +// x^N mod P(x) +uint32_t crc32c_f_pow_n(uint32_t n) { + // result = 1 (polynomial) + uint32_t one, result = 0x80000000, i = 0; + + while (one = (n & 1), (n == 1 || n - one > 0)) { + if (one) { + result = crc32c_multiply(result, _crc32c_pow_2k_table[i]); + } + n >>= 1; + i++; + } + + return result; +} + +juint *StubRoutines::x86::_crc32c_table; + +void StubRoutines::x86::generate_CRC32C_table(bool is_pclmulqdq_table_supported) { + + static juint pow_n[CRC32C_NUM_PRECOMPUTED_CONSTANTS]; + + crc32c_init_pow_2k(); + + pow_n[0] = crc32c_f_pow_n(CRC32C_HIGH * 8); // 8N * 8 = 64N + pow_n[1] = crc32c_f_pow_n(CRC32C_HIGH * 8 * 2); // 128N + + pow_n[2] = crc32c_f_pow_n(CRC32C_MIDDLE * 8); + pow_n[3] = crc32c_f_pow_n(CRC32C_MIDDLE * 8 * 2); + + pow_n[4] = crc32c_f_pow_n(CRC32C_LOW * 8); + pow_n[CRC32C_NUM_PRECOMPUTED_CONSTANTS - 1] = + crc32c_f_pow_n(CRC32C_LOW * 8 * 2); + + if (is_pclmulqdq_table_supported) { + _crc32c_table = pow_n; + } else { + static julong pclmulqdq_table[CRC32C_NUM_PRECOMPUTED_CONSTANTS * 256]; + + for (int j = 0; j < CRC32C_NUM_PRECOMPUTED_CONSTANTS; j++) { + static juint X_CONST = pow_n[j]; + for (int64_t i = 0; i < 256; i++) { // to force 64 bit wide computations + // S. Gueron / Information Processing Letters 112 (2012) 184 + // Algorithm 3: Generating a carry-less multiplication lookup table. + // Input: A 32-bit constant, X_CONST. + // Output: A table of 256 entries, each one is a 64-bit quadword, + // that can be used for computing "byte" * X_CONST, for a given byte. + pclmulqdq_table[j * 256 + i] = + ((i & 1) * X_CONST) ^ ((i & 2) * X_CONST) ^ ((i & 4) * X_CONST) ^ + ((i & 8) * X_CONST) ^ ((i & 16) * X_CONST) ^ ((i & 32) * X_CONST) ^ + ((i & 64) * X_CONST) ^ ((i & 128) * X_CONST); + } + } + _crc32c_table = (juint*)pclmulqdq_table; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp --- a/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,6 +36,8 @@ // masks and table for CRC32 static uint64_t _crc_by128_masks[]; static juint _crc_table[]; + // table for CRC32C + static juint* _crc32c_table; // swap mask for ghash static address _ghash_long_swap_mask_addr; static address _ghash_byte_swap_mask_addr; @@ -46,5 +48,6 @@ static address crc_by128_masks_addr() { return (address)_crc_by128_masks; } static address ghash_long_swap_mask_addr() { return _ghash_long_swap_mask_addr; } static address ghash_byte_swap_mask_addr() { return _ghash_byte_swap_mask_addr; } + static void generate_CRC32C_table(bool is_pclmulqdq_supported); #endif // CPU_X86_VM_STUBROUTINES_X86_32_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -538,7 +538,7 @@ // Allocate monitor and lock method (asm interpreter) // rbx, - Method* // -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags (rbx, Method::access_flags_offset()); const Address monitor_block_top (rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize); @@ -697,15 +697,14 @@ __ jmp(rdi); __ bind(slow_path); - (void) generate_normal_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); return entry; } #endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } /** @@ -753,12 +752,10 @@ // generate a vanilla native entry as the slow path __ bind(slow_path); - - (void) generate_native_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); return entry; } - return generate_native_entry(false); + return NULL; } /** @@ -790,18 +787,25 @@ const Register buf = rdx; // source java byte array address const Register len = rdi; // length + // value x86_32 + // interp. arg ptr ESP + 4 + // int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len) + // 3 2 1 0 + // int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len) + // 4 2,3 1 0 + // Arguments are reversed on java expression stack - __ movl(len, Address(rsp, wordSize)); // Length + __ movl(len, Address(rsp, 4 + 0)); // Length // Calculate address of start element if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) { - __ movptr(buf, Address(rsp, 3*wordSize)); // long buf - __ addptr(buf, Address(rsp, 2*wordSize)); // + offset - __ movl(crc, Address(rsp, 5*wordSize)); // Initial CRC + __ movptr(buf, Address(rsp, 4 + 2 * wordSize)); // long buf + __ addptr(buf, Address(rsp, 4 + 1 * wordSize)); // + offset + __ movl(crc, Address(rsp, 4 + 4 * wordSize)); // Initial CRC } else { - __ movptr(buf, Address(rsp, 3*wordSize)); // byte[] array + __ movptr(buf, Address(rsp, 4 + 2 * wordSize)); // byte[] array __ addptr(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size - __ addptr(buf, Address(rsp, 2*wordSize)); // + offset - __ movl(crc, Address(rsp, 4*wordSize)); // Initial CRC + __ addptr(buf, Address(rsp, 4 + 1 * wordSize)); // + offset + __ movl(crc, Address(rsp, 4 + 3 * wordSize)); // Initial CRC } __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32()), crc, buf, len); @@ -814,12 +818,57 @@ // generate a vanilla native entry as the slow path __ bind(slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); + return entry; + } + return NULL; +} - (void) generate_native_entry(false); +/** +* Method entry for static native methods: +* int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int end) +* int java.util.zip.CRC32C.updateByteBuffer(int crc, long address, int off, int end) +*/ +address InterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + if (UseCRC32CIntrinsics) { + address entry = __ pc(); + // Load parameters + const Register crc = rax; // crc + const Register buf = rcx; // source java byte array address + const Register len = rdx; // length + const Register end = len; + + // value x86_32 + // interp. arg ptr ESP + 4 + // int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int end) + // 3 2 1 0 + // int java.util.zip.CRC32.updateByteBuffer(int crc, long address, int off, int end) + // 4 2,3 1 0 + + // Arguments are reversed on java expression stack + __ movl(end, Address(rsp, 4 + 0)); // end + __ subl(len, Address(rsp, 4 + 1 * wordSize)); // end - offset == length + // Calculate address of start element + if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { + __ movptr(buf, Address(rsp, 4 + 2 * wordSize)); // long address + __ addptr(buf, Address(rsp, 4 + 1 * wordSize)); // + offset + __ movl(crc, Address(rsp, 4 + 4 * wordSize)); // Initial CRC + } else { + __ movptr(buf, Address(rsp, 4 + 2 * wordSize)); // byte[] array + __ addptr(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size + __ addptr(buf, Address(rsp, 4 + 1 * wordSize)); // + offset + __ movl(crc, Address(rsp, 4 + 3 * wordSize)); // Initial CRC + } + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32C()), crc, buf, len); + // result in rax + // _areturn + __ pop(rdi); // get return address + __ mov(rsp, rsi); // set sp to sender sp + __ jmp(rdi); return entry; } - return generate_native_entry(false); + return NULL; } /** @@ -827,10 +876,8 @@ * java.lang.Float.intBitsToFloat(int bits) */ address InterpreterGenerator::generate_Float_intBitsToFloat_entry() { - address entry; - if (UseSSE >= 1) { - entry = __ pc(); + address entry = __ pc(); // rsi: the sender's SP @@ -844,11 +891,10 @@ __ pop(rdi); // get return address __ mov(rsp, rsi); // set rsp to the sender's SP __ jmp(rdi); - } else { - entry = generate_native_entry(false); + return entry; } - return entry; + return NULL; } /** @@ -856,10 +902,8 @@ * java.lang.Float.floatToRawIntBits(float value) */ address InterpreterGenerator::generate_Float_floatToRawIntBits_entry() { - address entry; - if (UseSSE >= 1) { - entry = __ pc(); + address entry = __ pc(); // rsi: the sender's SP @@ -873,11 +917,10 @@ __ pop(rdi); // get return address __ mov(rsp, rsi); // set rsp to the sender's SP __ jmp(rdi); - } else { - entry = generate_native_entry(false); + return entry; } - return entry; + return NULL; } @@ -886,10 +929,8 @@ * java.lang.Double.longBitsToDouble(long bits) */ address InterpreterGenerator::generate_Double_longBitsToDouble_entry() { - address entry; - if (UseSSE >= 2) { - entry = __ pc(); + address entry = __ pc(); // rsi: the sender's SP @@ -903,11 +944,10 @@ __ pop(rdi); // get return address __ mov(rsp, rsi); // set rsp to the sender's SP __ jmp(rdi); - } else { - entry = generate_native_entry(false); + return entry; } - return entry; + return NULL; } /** @@ -915,10 +955,8 @@ * java.lang.Double.doubleToRawLongBits(double value) */ address InterpreterGenerator::generate_Double_doubleToRawLongBits_entry() { - address entry; - if (UseSSE >= 2) { - entry = __ pc(); + address entry = __ pc(); // rsi: the sender's SP @@ -933,11 +971,10 @@ __ pop(rdi); // get return address __ mov(rsp, rsi); // set rsp to the sender's SP __ jmp(rdi); - } else { - entry = generate_native_entry(false); + return entry; } - return entry; + return NULL; } // diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -198,13 +198,27 @@ } -address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, - int step) { +address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step) { address entry = __ pc(); // NULL last_sp until next java call __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); __ restore_bcp(); __ restore_locals(); +#if INCLUDE_JVMCI + // Check if we need to take lock at entry of synchronized method. + if (UseJVMCICompiler) { + Label L; + __ cmpb(Address(r15_thread, JavaThread::pending_monitorenter_offset()), 0); + __ jcc(Assembler::zero, L); + // Clear flag. + __ movb(Address(r15_thread, JavaThread::pending_monitorenter_offset()), 0); + // Satisfy calling convention for lock_method(). + __ get_method(rbx); + // Take lock. + lock_method(); + __ bind(L); + } +#endif // handle exceptions { Label L; @@ -500,7 +514,7 @@ // rax // c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs) // rscratch1, rscratch2 (scratch regs) -void InterpreterGenerator::lock_method(void) { +void TemplateInterpreterGenerator::lock_method() { // synchronize method const Address access_flags(rbx, Method::access_flags_offset()); const Address monitor_block_top( @@ -677,15 +691,14 @@ // generate a vanilla interpreter entry as the slow path __ bind(slow_path); - (void) generate_normal_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); return entry; } #endif // INCLUDE_ALL_GCS // If G1 is not enabled then attempt to go through the accessor entry point // Reference.get is an accessor - return generate_jump_to_normal_entry(); + return NULL; } /** @@ -733,12 +746,10 @@ // generate a vanilla native entry as the slow path __ bind(slow_path); - - (void) generate_native_entry(false); - + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); return entry; } - return generate_native_entry(false); + return NULL; } /** @@ -796,12 +807,61 @@ // generate a vanilla native entry as the slow path __ bind(slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); + return entry; + } + return NULL; +} - (void) generate_native_entry(false); +/** +* Method entry for static native methods: +* int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int end) +* int java.util.zip.CRC32C.updateByteBuffer(int crc, long address, int off, int end) +*/ +address InterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + if (UseCRC32CIntrinsics) { + address entry = __ pc(); + // Load parameters + const Register crc = c_rarg0; // crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; + const Register off = c_rarg3; // offset + const Register end = len; + + // Arguments are reversed on java expression stack + // Calculate address of start element + if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { + __ movptr(buf, Address(rsp, 3 * wordSize)); // long buf + __ movl2ptr(off, Address(rsp, 2 * wordSize)); // offset + __ addq(buf, off); // + offset + __ movl(crc, Address(rsp, 5 * wordSize)); // Initial CRC + // Note on 5 * wordSize vs. 4 * wordSize: + // * int java.util.zip.CRC32C.updateByteBuffer(int crc, long address, int off, int end) + // 4 2,3 1 0 + // end starts at SP + 8 + // The Java(R) Virtual Machine Specification Java SE 7 Edition + // 4.10.2.3. Values of Types long and double + // "When calculating operand stack length, values of type long and double have length two." + } else { + __ movptr(buf, Address(rsp, 3 * wordSize)); // byte[] array + __ addptr(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size + __ movl2ptr(off, Address(rsp, 2 * wordSize)); // offset + __ addq(buf, off); // + offset + __ movl(crc, Address(rsp, 4 * wordSize)); // Initial CRC + } + __ movl(end, Address(rsp, wordSize)); // end + __ subl(end, off); // end - off + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32C()), crc, buf, len); + // result in rax + // _areturn + __ pop(rdi); // get return address + __ mov(rsp, r13); // set sp to sender sp + __ jmp(rdi); return entry; } - return generate_native_entry(false); + + return NULL; } // Interpreter stub for calling a native method. (asm interpreter) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/templateTable_x86.cpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -3595,6 +3595,8 @@ __ profile_virtual_call(rax, rlocals, rdx); // get target Method* & entry point __ lookup_virtual_method(rax, index, method); + __ profile_called_method(method, rdx, rbcp); + __ profile_arguments_type(rdx, method, rbcp, true); __ jump_from_interpreted(method, rdx); } @@ -3694,6 +3696,7 @@ __ testptr(rbx, rbx); __ jcc(Assembler::zero, no_such_method); + __ profile_called_method(rbx, rbcp, rdx); __ profile_arguments_type(rdx, rbx, rbcp, true); // do the call diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/vmStructs_x86.hpp --- a/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/vmStructs_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -37,13 +37,50 @@ /******************************/ \ /* JavaFrameAnchor */ \ /******************************/ \ - volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \ + static_field(VM_Version, _cpuFeatures, uint64_t) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_toplevel_type(VM_Version) -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ + LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \ + declare_constant(frame::interpreter_frame_sender_sp_offset) \ + declare_constant(frame::interpreter_frame_last_sp_offset) \ + declare_constant(VM_Version::CPU_CX8) \ + declare_constant(VM_Version::CPU_CMOV) \ + declare_constant(VM_Version::CPU_FXSR) \ + declare_constant(VM_Version::CPU_HT) \ + declare_constant(VM_Version::CPU_MMX) \ + declare_constant(VM_Version::CPU_3DNOW_PREFETCH) \ + declare_constant(VM_Version::CPU_SSE) \ + declare_constant(VM_Version::CPU_SSE2) \ + declare_constant(VM_Version::CPU_SSE3) \ + declare_constant(VM_Version::CPU_SSSE3) \ + declare_constant(VM_Version::CPU_SSE4A) \ + declare_constant(VM_Version::CPU_SSE4_1) \ + declare_constant(VM_Version::CPU_SSE4_2) \ + declare_constant(VM_Version::CPU_POPCNT) \ + declare_constant(VM_Version::CPU_LZCNT) \ + declare_constant(VM_Version::CPU_TSC) \ + declare_constant(VM_Version::CPU_TSCINV) \ + declare_constant(VM_Version::CPU_AVX) \ + declare_constant(VM_Version::CPU_AVX2) \ + declare_constant(VM_Version::CPU_AES) \ + declare_constant(VM_Version::CPU_ERMS) \ + declare_constant(VM_Version::CPU_CLMUL) \ + declare_constant(VM_Version::CPU_BMI1) \ + declare_constant(VM_Version::CPU_BMI2) \ + declare_constant(VM_Version::CPU_RTM) \ + declare_constant(VM_Version::CPU_ADX) \ + declare_constant(VM_Version::CPU_AVX512F) \ + declare_constant(VM_Version::CPU_AVX512DQ) \ + declare_constant(VM_Version::CPU_AVX512PF) \ + declare_constant(VM_Version::CPU_AVX512ER) \ + declare_constant(VM_Version::CPU_AVX512CD) \ + declare_constant(VM_Version::CPU_AVX512BW) #define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/vm_version_x86.cpp --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -661,6 +661,18 @@ FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } + if (supports_sse4_2()) { + if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { + UseCRC32CIntrinsics = true; + } + } + else if (UseCRC32CIntrinsics) { + if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { + warning("CRC32C intrinsics are not available on this CPU"); + } + FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); + } + // The AES intrinsic stubs require AES instruction support (of course) // but also require sse3 mode for instructions it use. if (UseAES && (UseSSE > 2)) { @@ -704,12 +716,6 @@ FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } - if (UseCRC32CIntrinsics) { - if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) - warning("CRC32C intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); - } - if (UseAdler32Intrinsics) { warning("Adler32Intrinsics not available on this CPU."); FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); @@ -781,6 +787,8 @@ FLAG_SET_DEFAULT(UseFPUForSpilling, false); } } +#endif +#if defined(COMPILER2) || INCLUDE_JVMCI if (MaxVectorSize > 0) { if (!is_power_of_2(MaxVectorSize)) { warning("MaxVectorSize must be a power of 2"); @@ -797,7 +805,7 @@ // Vectors (in XMM) are only supported with SSE2+ FLAG_SET_DEFAULT(MaxVectorSize, 0); } -#ifdef ASSERT +#if defined(COMPILER2) && defined(ASSERT) if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) { tty->print_cr("State of YMM registers after signal handle:"); int nreg = 2 LP64_ONLY(+2); @@ -810,9 +818,11 @@ tty->cr(); } } -#endif +#endif // COMPILER2 && ASSERT } +#endif // COMPILER2 || INCLUDE_JVMCI +#ifdef COMPILER2 #ifdef _LP64 if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; @@ -1082,11 +1092,6 @@ } #endif // COMPILER2 - assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value"); - - // set valid Prefetch instruction - if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0; - if( AllocatePrefetchInstr > 3 ) AllocatePrefetchInstr = 3; if( AllocatePrefetchInstr == 3 && !supports_3dnow_prefetch() ) AllocatePrefetchInstr=0; if( !supports_sse() && supports_3dnow_prefetch() ) AllocatePrefetchInstr = 3; @@ -1125,7 +1130,6 @@ } #endif } - assert(AllocatePrefetchDistance % AllocatePrefetchStepSize == 0, "invalid value"); #ifdef _LP64 // Prefetch settings diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/vm_version_x86.hpp --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,6 +29,7 @@ #include "runtime/vm_version.hpp" class VM_Version : public Abstract_VM_Version { + friend class VMStructs; public: // cpuid result register layouts. These are all unions of a uint32_t // (in case anyone wants access to the register as a whole) and a bitfield. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -35,8 +35,6 @@ #include "opto/runtime.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // machine-dependent part of VtableStubs: create VtableStub of correct size and // initialize its code @@ -113,7 +111,7 @@ if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d", - vtable_index, s->entry_point(), + vtable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } @@ -206,7 +204,7 @@ if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d", - itable_index, s->entry_point(), + itable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/x86.ad --- a/hotspot/src/cpu/x86/vm/x86.ad Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/x86.ad Thu Oct 22 11:13:08 2015 -0700 @@ -1712,6 +1712,18 @@ return ret_value; // Per default match rules are supported. } +const int Matcher::float_pressure(int default_pressure_threshold) { + int float_pressure_threshold = default_pressure_threshold; +#ifdef _LP64 + if (UseAVX > 2) { + // Increase pressure threshold on machines with AVX3 which have + // 2x more XMM registers. + float_pressure_threshold = default_pressure_threshold * 2; + } +#endif + return float_pressure_threshold; +} + // Max vector size in bytes. 0 if not supported. const int Matcher::vector_width_in_bytes(BasicType bt) { assert(is_java_primitive(bt), "only primitive type vectors"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/x86_32.ad --- a/hotspot/src/cpu/x86/vm/x86_32.ad Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/x86_32.ad Thu Oct 22 11:13:08 2015 -0700 @@ -580,7 +580,11 @@ st->print("MOV [ESP + #%d], EBP\t# Save EBP",framesize); if (PreserveFramePointer) { st->print("\n\t"); - st->print("MOV EBP, [ESP + #%d]\t# Save the caller's SP into EBP", (framesize + wordSize)); + st->print("MOV EBP, ESP\t# Save the caller's SP into EBP"); + if (framesize > 0) { + st->print("\n\t"); + st->print("ADD EBP, #%d", framesize); + } } } @@ -9911,35 +9915,6 @@ ins_pipe( pipe_slow ); %} - -instruct expDPR_reg(regDPR1 dpr1, eAXRegI rax, eDXRegI rdx, eCXRegI rcx, eFlagsReg cr) %{ - predicate (UseSSE<=1); - match(Set dpr1 (ExpD dpr1)); - effect(KILL rax, KILL rcx, KILL rdx, KILL cr); - format %{ "fast_exp $dpr1 -> $dpr1 // KILL $rax, $rcx, $rdx" %} - ins_encode %{ - __ fast_exp(); - %} - ins_pipe( pipe_slow ); -%} - -instruct expD_reg(regD dst, regD src, eAXRegI rax, eDXRegI rdx, eCXRegI rcx, eFlagsReg cr) %{ - predicate (UseSSE>=2); - match(Set dst (ExpD src)); - effect(KILL rax, KILL rcx, KILL rdx, KILL cr); - format %{ "fast_exp $dst -> $src // KILL $rax, $rcx, $rdx" %} - ins_encode %{ - __ subptr(rsp, 8); - __ movdbl(Address(rsp, 0), $src$$XMMRegister); - __ fld_d(Address(rsp, 0)); - __ fast_exp(); - __ fstp_d(Address(rsp, 0)); - __ movdbl($dst$$XMMRegister, Address(rsp, 0)); - __ addptr(rsp, 8); - %} - ins_pipe( pipe_slow ); -%} - instruct log10DPR_reg(regDPR1 dst, regDPR1 src) %{ predicate (UseSSE<=1); // The source Double operand on FPU stack diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/x86/vm/x86_64.ad --- a/hotspot/src/cpu/x86/vm/x86_64.ad Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/x86/vm/x86_64.ad Thu Oct 22 11:13:08 2015 -0700 @@ -867,7 +867,11 @@ st->print("movq [rsp + #%d], rbp\t# Save rbp",framesize); if (PreserveFramePointer) { st->print("\n\t"); - st->print("movq rbp, [rsp + #%d]\t# Save the caller's SP into rbp", (framesize + wordSize)); + st->print("movq rbp, rsp\t# Save the caller's SP into rbp"); + if (framesize > 0) { + st->print("\n\t"); + st->print("addq rbp, #%d", framesize); + } } } @@ -2136,12 +2140,13 @@ RELOC_DISP32); } if (_method) { - // Emit stub for static call. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); + // Emit stubs for static call. + address mark = cbuf.insts_mark(); + address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark); if (stub == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; - } + } } %} @@ -3767,6 +3772,22 @@ %} %} +operand indPosIndexScale(any_RegP reg, rRegI idx, immI2 scale) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + predicate(n->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); + match(AddP reg (LShiftL (ConvI2L idx) scale)); + + op_cost(10); + format %{"[$reg + pos $idx << $scale]" %} + interface(MEMORY_INTER) %{ + base($reg); + index($idx); + scale($scale); + disp(0x0); + %} +%} + // Indirect Memory Times Scale Plus Index Register Plus Offset Operand operand indIndexScaleOffset(any_RegP reg, immL32 off, rRegL lreg, immI2 scale) %{ @@ -4159,7 +4180,7 @@ // case of this is memory operands. opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, - indIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset, + indIndexScale, indPosIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset, indCompressedOopOffset, indirectNarrow, indOffset8Narrow, indOffset32Narrow, indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, @@ -5186,6 +5207,17 @@ ins_pipe(ialu_reg_reg_fat); %} +instruct leaPPosIdxScale(rRegP dst, indPosIndexScale mem) +%{ + match(Set dst mem); + + ins_cost(110); + format %{ "leaq $dst, $mem\t# ptr idxscale" %} + opcode(0x8D); + ins_encode(REX_reg_mem_wide(dst, mem), OpcP, reg_mem(dst, mem)); + ins_pipe(ialu_reg_reg_fat); +%} + instruct leaPIdxScaleOff(rRegP dst, indIndexScaleOffset mem) %{ match(Set dst mem); @@ -9871,22 +9903,6 @@ ins_pipe( pipe_slow ); %} -instruct expD_reg(regD dst, regD src, rax_RegI rax, rdx_RegI rdx, rcx_RegI rcx, rFlagsReg cr) %{ - match(Set dst (ExpD src)); - effect(KILL rax, KILL rcx, KILL rdx, KILL cr); - format %{ "fast_exp $dst -> $src // KILL $rax, $rcx, $rdx" %} - ins_encode %{ - __ subptr(rsp, 8); - __ movdbl(Address(rsp, 0), $src$$XMMRegister); - __ fld_d(Address(rsp, 0)); - __ fast_exp(); - __ fstp_d(Address(rsp, 0)); - __ movdbl($dst$$XMMRegister, Address(rsp, 0)); - __ addptr(rsp, 8); - %} - ins_pipe( pipe_slow ); -%} - //----------Arithmetic Conversion Instructions--------------------------------- instruct roundFloat_nop(regF dst) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -816,7 +816,7 @@ // If G1 is not enabled then attempt to go through the normal entry point // Reference.get could be instrumented by jvmti - return generate_normal_entry(false); + return NULL; } address InterpreterGenerator::generate_native_entry(bool synchronized) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp --- a/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/cpu/zero/vm/interpreterGenerator_zero.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -42,4 +42,5 @@ // Not supported address generate_CRC32_update_entry() { return NULL; } address generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } + address generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { return NULL; } #endif // CPU_ZERO_VM_INTERPRETERGENERATOR_ZERO_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.amd64; + +import static jdk.vm.ci.code.MemoryBarriers.*; +import static jdk.vm.ci.code.Register.*; + +import java.nio.*; +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.meta.*; + +/** + * Represents the AMD64 architecture. + */ +public class AMD64 extends Architecture { + + public static final RegisterCategory CPU = new RegisterCategory("CPU"); + + // @formatter:off + + // General purpose CPU registers + public static final Register rax = new Register(0, 0, "rax", CPU); + public static final Register rcx = new Register(1, 1, "rcx", CPU); + public static final Register rdx = new Register(2, 2, "rdx", CPU); + public static final Register rbx = new Register(3, 3, "rbx", CPU); + public static final Register rsp = new Register(4, 4, "rsp", CPU); + public static final Register rbp = new Register(5, 5, "rbp", CPU); + public static final Register rsi = new Register(6, 6, "rsi", CPU); + public static final Register rdi = new Register(7, 7, "rdi", CPU); + + public static final Register r8 = new Register(8, 8, "r8", CPU); + public static final Register r9 = new Register(9, 9, "r9", CPU); + public static final Register r10 = new Register(10, 10, "r10", CPU); + public static final Register r11 = new Register(11, 11, "r11", CPU); + public static final Register r12 = new Register(12, 12, "r12", CPU); + public static final Register r13 = new Register(13, 13, "r13", CPU); + public static final Register r14 = new Register(14, 14, "r14", CPU); + public static final Register r15 = new Register(15, 15, "r15", CPU); + + public static final Register[] cpuRegisters = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15 + }; + + private static final int XMM_REFERENCE_MAP_SHIFT = 2; + + public static final RegisterCategory XMM = new RegisterCategory("XMM", cpuRegisters.length, XMM_REFERENCE_MAP_SHIFT); + + // XMM registers + public static final Register xmm0 = new Register(16, 0, "xmm0", XMM); + public static final Register xmm1 = new Register(17, 1, "xmm1", XMM); + public static final Register xmm2 = new Register(18, 2, "xmm2", XMM); + public static final Register xmm3 = new Register(19, 3, "xmm3", XMM); + public static final Register xmm4 = new Register(20, 4, "xmm4", XMM); + public static final Register xmm5 = new Register(21, 5, "xmm5", XMM); + public static final Register xmm6 = new Register(22, 6, "xmm6", XMM); + public static final Register xmm7 = new Register(23, 7, "xmm7", XMM); + + public static final Register xmm8 = new Register(24, 8, "xmm8", XMM); + public static final Register xmm9 = new Register(25, 9, "xmm9", XMM); + public static final Register xmm10 = new Register(26, 10, "xmm10", XMM); + public static final Register xmm11 = new Register(27, 11, "xmm11", XMM); + public static final Register xmm12 = new Register(28, 12, "xmm12", XMM); + public static final Register xmm13 = new Register(29, 13, "xmm13", XMM); + public static final Register xmm14 = new Register(30, 14, "xmm14", XMM); + public static final Register xmm15 = new Register(31, 15, "xmm15", XMM); + + public static final Register[] xmmRegisters = { + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + + public static final Register[] cpuxmmRegisters = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + + /** + * Register used to construct an instruction-relative address. + */ + public static final Register rip = new Register(32, -1, "rip", SPECIAL); + + public static final Register[] allRegisters = { + rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, + r8, r9, r10, r11, r12, r13, r14, r15, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, + rip + }; + + // @formatter:on + + /** + * Basic set of CPU features mirroring what is returned from the cpuid instruction. See: + * {@code VM_Version::cpuFeatureFlags}. + */ + public static enum CPUFeature { + CX8, + CMOV, + FXSR, + HT, + MMX, + AMD_3DNOW_PREFETCH, + SSE, + SSE2, + SSE3, + SSSE3, + SSE4A, + SSE4_1, + SSE4_2, + POPCNT, + LZCNT, + TSC, + TSCINV, + AVX, + AVX2, + AES, + ERMS, + CLMUL, + BMI1, + BMI2, + RTM, + ADX, + AVX512F, + AVX512DQ, + AVX512PF, + AVX512ER, + AVX512CD, + AVX512BW + } + + private final EnumSet features; + + /** + * Set of flags to control code emission. + */ + public static enum Flag { + UseCountLeadingZerosInstruction, + UseCountTrailingZerosInstruction + } + + private final EnumSet flags; + + public AMD64(EnumSet features, EnumSet flags) { + super("AMD64", JavaKind.Long, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, cpuRegisters.length + (xmmRegisters.length << XMM_REFERENCE_MAP_SHIFT), 8); + this.features = features; + this.flags = flags; + assert features.contains(CPUFeature.SSE2) : "minimum config for x64"; + } + + public EnumSet getFeatures() { + return features; + } + + public EnumSet getFlags() { + return flags; + } + + @Override + public PlatformKind getPlatformKind(JavaKind javaKind) { + if (javaKind.isObject()) { + return getWordKind(); + } else { + return javaKind; + } + } + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind platformKind) { + if (!(platformKind instanceof JavaKind)) { + return false; + } + + JavaKind kind = (JavaKind) platformKind; + if (category.equals(CPU)) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + return true; + } + } else if (category.equals(XMM)) { + switch (kind) { + case Float: + case Double: + return true; + } + } + + return false; + } + + @Override + public PlatformKind getLargestStorableKind(RegisterCategory category) { + if (category.equals(CPU)) { + return JavaKind.Long; + } else if (category.equals(XMM)) { + return JavaKind.Double; + } else { + return JavaKind.Illegal; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/overview.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/overview.html Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,37 @@ + + + + + + + + +The jdk.vm.ci.code project provides an API to the runtime's native code cache. +It allows installation and execution of native code. + + + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/AbstractAddress.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/AbstractAddress.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Abstract base class that represents a platform specific address. + */ +public abstract class AbstractAddress { +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import java.nio.*; +import java.util.*; + +import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.meta.*; + +/** + * Represents a CPU architecture, including information such as its endianness, CPU registers, word + * width, etc. + */ +public abstract class Architecture { + + /** + * The number of entries required in a {@link ReferenceMap} covering all the registers that may + * store references. The index of a register in the reference map is given by + * {@link Register#getReferenceMapIndex()}. + */ + private final int registerReferenceMapSize; + + /** + * The architecture specific type of a native word. + */ + private final PlatformKind wordKind; + + /** + * The name of this architecture (e.g. "AMD64", "SPARCv9"). + */ + private final String name; + + /** + * Array of all available registers on this architecture. The index of each register in this + * array is equal to its {@linkplain Register#number number}. + */ + private final Register[] registers; + + /** + * The byte ordering can be either little or big endian. + */ + private final ByteOrder byteOrder; + + /** + * Whether the architecture supports unaligned memory accesses. + */ + private final boolean unalignedMemoryAccess; + + /** + * Mask of the barrier constants denoting the barriers that are not required to be explicitly + * inserted under this architecture. + */ + private final int implicitMemoryBarriers; + + /** + * Offset in bytes from the beginning of a call instruction to the displacement. + */ + private final int machineCodeCallDisplacementOffset; + + /** + * The size of the return address pushed to the stack by a call instruction. A value of 0 + * denotes that call linkage uses registers instead (e.g. SPARC). + */ + private final int returnAddressSize; + + protected Architecture(String name, PlatformKind wordKind, ByteOrder byteOrder, boolean unalignedMemoryAccess, Register[] registers, int implicitMemoryBarriers, int nativeCallDisplacementOffset, + int registerReferenceMapSize, int returnAddressSize) { + this.name = name; + this.registers = registers; + this.wordKind = wordKind; + this.byteOrder = byteOrder; + this.unalignedMemoryAccess = unalignedMemoryAccess; + this.implicitMemoryBarriers = implicitMemoryBarriers; + this.machineCodeCallDisplacementOffset = nativeCallDisplacementOffset; + this.registerReferenceMapSize = registerReferenceMapSize; + this.returnAddressSize = returnAddressSize; + } + + /** + * Converts this architecture to a string. + * + * @return the string representation of this architecture + */ + @Override + public final String toString() { + return getName().toLowerCase(); + } + + public int getRegisterReferenceMapSize() { + return registerReferenceMapSize; + } + + /** + * Gets the natural size of words (typically registers and pointers) of this architecture, in + * bytes. + */ + public int getWordSize() { + return wordKind.getSizeInBytes(); + } + + public PlatformKind getWordKind() { + return wordKind; + } + + /** + * Gets the name of this architecture. + */ + public String getName() { + return name; + } + + /** + * Gets an array of all available registers on this architecture. The index of each register in + * this array is equal to its {@linkplain Register#number number}. + */ + public Register[] getRegisters() { + return registers.clone(); + } + + public ByteOrder getByteOrder() { + return byteOrder; + } + + /** + * @return true if the architecture supports unaligned memory accesses. + */ + public boolean supportsUnalignedMemoryAccess() { + return unalignedMemoryAccess; + } + + /** + * Gets the size of the return address pushed to the stack by a call instruction. A value of 0 + * denotes that call linkage uses registers instead. + */ + public int getReturnAddressSize() { + return returnAddressSize; + } + + /** + * Gets the offset in bytes from the beginning of a call instruction to the displacement. + */ + public int getMachineCodeCallDisplacementOffset() { + return machineCodeCallDisplacementOffset; + } + + /** + * Determines the barriers in a given barrier mask that are explicitly required on this + * architecture. + * + * @param barriers a mask of the barrier constants + * @return the value of {@code barriers} minus the barriers unnecessary on this architecture + */ + public final int requiredBarriers(int barriers) { + return barriers & ~implicitMemoryBarriers; + } + + /** + * Determine whether a kind can be stored in a register of a given category. + * + * @param category the category of the register + * @param kind the kind that should be stored in the register + */ + public abstract boolean canStoreValue(RegisterCategory category, PlatformKind kind); + + /** + * Return the largest kind that can be stored in a register of a given category. + * + * @param category the category of the register + * @return the largest kind that can be stored in a register {@code category} + */ + public abstract PlatformKind getLargestStorableKind(RegisterCategory category); + + /** + * Return the {@link PlatformKind} that is used to store values of a given {@link JavaKind}. + */ + public abstract PlatformKind getPlatformKind(JavaKind javaKind); + + @Override + public final boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Architecture) { + Architecture that = (Architecture) obj; + if (this.name.equals(that.name)) { + assert this.byteOrder.equals(that.byteOrder); + assert this.implicitMemoryBarriers == that.implicitMemoryBarriers; + assert this.machineCodeCallDisplacementOffset == that.machineCodeCallDisplacementOffset; + assert this.registerReferenceMapSize == that.registerReferenceMapSize; + assert Arrays.equals(this.registers, that.registers); + assert this.returnAddressSize == that.returnAddressSize; + assert this.unalignedMemoryAccess == that.unalignedMemoryAccess; + assert this.wordKind == that.wordKind; + return true; + } + } + return false; + } + + @Override + public final int hashCode() { + return name.hashCode(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BailoutException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BailoutException.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +/** + * Exception thrown when the compiler refuses to compile a method because of problems with the + * method. e.g. bytecode wouldn't verify, too big, JSR/ret too complicated, etc. This exception is + * not meant to indicate problems with the compiler itself. + */ +public class BailoutException extends RuntimeException { + + public static final long serialVersionUID = 8974598793458772L; + private final boolean permanent; + + /** + * Creates a new {@link BailoutException}. + * + * + * @param args parameters to the formatter + */ + public BailoutException(String format, Object... args) { + super(String.format(Locale.ENGLISH, format, args)); + this.permanent = true; + } + + /** + * Creates a new {@link BailoutException}. + * + * + * @param args parameters to the formatter + */ + public BailoutException(Throwable cause, String format, Object... args) { + super(String.format(Locale.ENGLISH, format, args), cause); + this.permanent = true; + } + + /** + * Creates a new {@link BailoutException}. + * + * @param permanent specifies whether this exception will occur again if compilation is retried + * @param args parameters to the formatter + */ + public BailoutException(boolean permanent, String format, Object... args) { + super(String.format(Locale.ENGLISH, format, args)); + this.permanent = permanent; + } + + /** + * @return whether this exception will occur again if compilation is retried + */ + public boolean isPermanent() { + return permanent; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodeFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodeFrame.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents the Java bytecode frame state(s) at a given position including {@link Value locations} + * where to find the local variables, operand stack values and locked objects of the bytecode + * frame(s). + */ +public class BytecodeFrame extends BytecodePosition { + + /** + * An array of values representing how to reconstruct the state of the Java frame. This is array + * is partitioned as follows: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Start index (inclusive)End index (exclusive)Description
0numLocalsLocal variables
numLocalsnumLocals + numStackOperand stack
numLocals + numStackvalues.lengthLocked objects
+ *

+ * Note that the number of locals and the number of stack slots may be smaller than the maximum + * number of locals and stack slots as specified in the compiled method. + */ + public final JavaValue[] values; + + /** + * An array describing the Java kind of the {@link #values}. It records a kind for the locals + * and the operand stack. + */ + public final JavaKind[] slotKinds; + + /** + * The number of locals in the values array. + */ + public final int numLocals; + + /** + * The number of stack slots in the values array. + */ + public final int numStack; + + /** + * The number of locks in the values array. + */ + public final int numLocks; + + /** + * True if this is a position inside an exception handler before the exception object has been + * consumed. In this case, {@link #numStack} {@code == 1} and {@link #getStackValue(int) + * getStackValue(0)} is the location of the exception object. If deoptimization happens at this + * position, the interpreter will rethrow the exception instead of executing the bytecode + * instruction at this position. + */ + public final boolean rethrowException; + + public final boolean duringCall; + + /** + * This BCI should be used for frame states that are built for code with no meaningful BCI. + */ + public static final int UNKNOWN_BCI = -5; + + /** + * The BCI for exception unwind. This is synthetic code and has no representation in bytecode. + * In contrast with {@link #AFTER_EXCEPTION_BCI}, at this point, if the method is synchronized, + * the monitor is still held. + */ + public static final int UNWIND_BCI = -1; + + /** + * The BCI for the state before starting to execute a method. Note that if the method is + * synchronized, the monitor is not yet held. + */ + public static final int BEFORE_BCI = -2; + + /** + * The BCI for the state after finishing the execution of a method and returning normally. Note + * that if the method was synchronized the monitor is already released. + */ + public static final int AFTER_BCI = -3; + + /** + * The BCI for exception unwind. This is synthetic code and has no representation in bytecode. + * In contrast with {@link #UNWIND_BCI}, at this point, if the method is synchronized, the + * monitor is already released. + */ + public static final int AFTER_EXCEPTION_BCI = -4; + + /** + * This BCI should be used for states that cannot be the target of a deoptimization, like + * snippet frame states. + */ + public static final int INVALID_FRAMESTATE_BCI = -6; + + /** + * Determines if a given BCI matches one of the placeholder BCI constants defined in this class. + */ + public static boolean isPlaceholderBci(int bci) { + return bci < 0; + } + + /** + * Gets the name of a given placeholder BCI. + */ + public static String getPlaceholderBciName(int bci) { + assert isPlaceholderBci(bci); + if (bci == BytecodeFrame.AFTER_BCI) { + return "AFTER_BCI"; + } else if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { + return "AFTER_EXCEPTION_BCI"; + } else if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { + return "INVALID_FRAMESTATE_BCI"; + } else if (bci == BytecodeFrame.BEFORE_BCI) { + return "BEFORE_BCI"; + } else if (bci == BytecodeFrame.UNKNOWN_BCI) { + return "UNKNOWN_BCI"; + } else { + assert bci == BytecodeFrame.UNWIND_BCI; + return "UNWIND_BCI"; + } + } + + /** + * Creates a new frame object. + * + * @param caller the caller frame (which may be {@code null}) + * @param method the method + * @param bci a BCI within the method + * @param rethrowException specifies if the VM should re-throw the pending exception when + * deopt'ing using this frame + * @param values the frame state {@link #values} + * @param numLocals the number of local variables + * @param numStack the depth of the stack + * @param numLocks the number of locked objects + */ + public BytecodeFrame(BytecodeFrame caller, ResolvedJavaMethod method, int bci, boolean rethrowException, boolean duringCall, JavaValue[] values, JavaKind[] slotKinds, int numLocals, int numStack, + int numLocks) { + super(caller, method, bci); + assert values != null; + this.rethrowException = rethrowException; + this.duringCall = duringCall; + this.values = values; + this.slotKinds = slotKinds; + this.numLocals = numLocals; + this.numStack = numStack; + this.numLocks = numLocks; + assert !rethrowException || numStack == 1 : "must have exception on top of the stack"; + } + + /** + * Ensure that the frame state is formatted as expected by the JVM, with null or Illegal in the + * slot following a double word item. This should really be checked in FrameState itself but + * because of Word type rewriting and alternative backends that can't be done. + */ + public boolean validateFormat() { + if (caller() != null) { + caller().validateFormat(); + } + for (int i = 0; i < numLocals + numStack; i++) { + if (values[i] != null) { + JavaKind kind = slotKinds[i]; + if (kind.needsTwoSlots()) { + assert slotKinds.length > i + 1 : String.format("missing second word %s", this); + assert slotKinds[i + 1] == JavaKind.Illegal : this; + } + } + } + return true; + } + + /** + * Gets the value representing the specified local variable. + * + * @param i the local variable index + * @return the value that can be used to reconstruct the local's current value + */ + public JavaValue getLocalValue(int i) { + return values[i]; + } + + /** + * Gets the value representing the specified stack slot. + * + * @param i the stack index + * @return the value that can be used to reconstruct the stack slot's current value + */ + public JavaValue getStackValue(int i) { + return values[i + numLocals]; + } + + /** + * Gets the value representing the specified lock. + * + * @param i the lock index + * @return the value that can be used to reconstruct the lock's current value + */ + public JavaValue getLockValue(int i) { + return values[i + numLocals + numStack]; + } + + /** + * Gets the caller of this frame. + * + * @return {@code null} if this frame has no caller + */ + public BytecodeFrame caller() { + return (BytecodeFrame) getCaller(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof BytecodeFrame && super.equals(obj)) { + BytecodeFrame that = (BytecodeFrame) obj; + // @formatter:off + if (this.duringCall == that.duringCall && + this.rethrowException == that.rethrowException && + this.numLocals == that.numLocals && + this.numLocks == that.numLocks && + this.numStack == that.numStack && + Arrays.equals(this.values, that.values)) { + return true; + } + // @formatter:off + return true; + } + return false; + } + + @Override + public String toString() { + return CodeUtil.append(new StringBuilder(100), this).toString(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents a code position, that is, a chain of inlined methods with bytecode locations, that is + * communicated from the compiler to the runtime system. A code position can be used by the runtime + * system to reconstruct a source-level stack trace for exceptions and to create + * {@linkplain BytecodeFrame frames} for deoptimization. + */ +public class BytecodePosition { + + private final BytecodePosition caller; + private final ResolvedJavaMethod method; + private final int bci; + + /** + * Constructs a new object representing a given parent/caller, a given method, and a given BCI. + * + * @param caller the parent position + * @param method the method + * @param bci a BCI within the method + */ + public BytecodePosition(BytecodePosition caller, ResolvedJavaMethod method, int bci) { + assert method != null; + this.caller = caller; + this.method = method; + this.bci = bci; + } + + /** + * Converts this code position to a string representation. + * + * @return a string representation of this code position + */ + @Override + public String toString() { + return CodeUtil.append(new StringBuilder(100), this).toString(); + } + + /** + * Deep equality test. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && getClass() == obj.getClass()) { + BytecodePosition that = (BytecodePosition) obj; + if (this.bci == that.bci && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.caller, that.caller)) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return getBCI(); + } + + /** + * @return The location within the method, as a bytecode index. The constant {@code -1} may be + * used to indicate the location is unknown, for example within code synthesized by the + * compiler. + */ + public int getBCI() { + return bci; + } + + /** + * @return The runtime interface method for this position. + */ + public ResolvedJavaMethod getMethod() { + return method; + } + + /** + * The position where this position has been called, {@code null} if none. + */ + public BytecodePosition getCaller() { + return caller; + } + + /** + * Adds a caller to the current position returning the new position. + */ + public BytecodePosition addCaller(BytecodePosition link) { + if (getCaller() == null) { + return new BytecodePosition(link, getMethod(), getBCI()); + } else { + return new BytecodePosition(getCaller().addCaller(link), getMethod(), getBCI()); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CallingConvention.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CallingConvention.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import static jdk.vm.ci.code.ValueUtil.*; + +import jdk.vm.ci.meta.*; + +/** + * A calling convention describes the locations in which the arguments for a call are placed and the + * location in which the return value is placed if the call is not void. + */ +public class CallingConvention { + + /** + * Constants denoting the type of a call for which a calling convention is requested. + */ + public enum Type { + /** + * A request for the outgoing argument locations at a call site to Java code. + */ + JavaCall(true), + + /** + * A request for the incoming argument locations. + */ + JavaCallee(false), + + /** + * A request for the outgoing argument locations at a call site to external native code that + * complies with the platform ABI. + */ + NativeCall(true); + + /** + * Determines if this is a request for the outgoing argument locations at a call site. + */ + public final boolean out; + + public static final Type[] VALUES = values(); + + private Type(boolean out) { + this.out = out; + } + } + + /** + * The amount of stack space (in bytes) required for the stack-based arguments of the call. + */ + private final int stackSize; + + private final AllocatableValue returnLocation; + + /** + * The ordered locations in which the arguments are placed. + */ + private final AllocatableValue[] argumentLocations; + + /** + * Creates a description of the registers and stack locations used by a call. + * + * @param stackSize amount of stack space (in bytes) required for the stack-based arguments of + * the call + * @param returnLocation the location for the return value or {@link Value#ILLEGAL} if a void + * call + * @param argumentLocations the ordered locations in which the arguments are placed + */ + public CallingConvention(int stackSize, AllocatableValue returnLocation, AllocatableValue... argumentLocations) { + assert argumentLocations != null; + assert returnLocation != null; + this.argumentLocations = argumentLocations; + this.stackSize = stackSize; + this.returnLocation = returnLocation; + assert verify(); + } + + /** + * Gets the location for the return value or {@link Value#ILLEGAL} if a void call. + */ + public AllocatableValue getReturn() { + return returnLocation; + } + + /** + * Gets the location for the {@code index}'th argument. + */ + public AllocatableValue getArgument(int index) { + return argumentLocations[index]; + } + + /** + * Gets the amount of stack space (in bytes) required for the stack-based arguments of the call. + */ + public int getStackSize() { + return stackSize; + } + + /** + * Gets the number of locations required for the arguments. + */ + public int getArgumentCount() { + return argumentLocations.length; + } + + /** + * Gets the locations required for the arguments. + */ + public AllocatableValue[] getArguments() { + if (argumentLocations.length == 0) { + return argumentLocations; + } + return argumentLocations.clone(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("CallingConvention["); + String sep = ""; + for (Value op : argumentLocations) { + sb.append(sep).append(op); + sep = ", "; + } + if (!returnLocation.equals(Value.ILLEGAL)) { + sb.append(" -> ").append(returnLocation); + } + sb.append("]"); + return sb.toString(); + } + + private boolean verify() { + for (int i = 0; i < argumentLocations.length; i++) { + Value location = argumentLocations[i]; + assert isStackSlot(location) || isAllocatableValue(location); + } + return true; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import jdk.vm.ci.code.CompilationResult.*; +import jdk.vm.ci.code.DataSection.*; +import jdk.vm.ci.meta.*; + +/** + * Access to code cache related details and requirements. + */ +public interface CodeCacheProvider { + + /** + * Adds the given compilation result as an implementation of the given method without making it + * the default implementation. + * + * @param method a method to which the executable code is begin added + * @param compResult the compilation result to be added + * @param speculationLog the speculation log to be used + * @return a reference to the compiled and ready-to-run code or throws a + * {@link BailoutException} if the code installation failed + */ + InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode); + + /** + * Sets the given compilation result as the default implementation of the given method. + * + * @param method a method to which the executable code is begin added + * @param compResult the compilation result to be added + * @return a reference to the compiled and ready-to-run code or null if the code installation + * failed + */ + InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult); + + /** + * Gets a name for a {@link Mark} mark. + */ + default String getMarkName(Mark mark) { + return String.valueOf(mark.id); + } + + /** + * Gets a name for the {@linkplain Call#target target} of a {@link Call}. + */ + default String getTargetName(Call call) { + return String.valueOf(call.target); + } + + /** + * Gets the register configuration to use when compiling a given method. + */ + RegisterConfig getRegisterConfig(); + + /** + * Minimum size of the stack area reserved for outgoing parameters. This area is reserved in all + * cases, even when the compiled method has no regular call instructions. + * + * @return the minimum size of the outgoing parameter area in bytes + */ + int getMinimumOutgoingSize(); + + /** + * Determines if a {@link DataPatch} should be created for a given primitive constant that is + * part of a {@link CompilationResult}. A data patch is always created for an object constant. + */ + boolean needsDataPatch(JavaConstant constant); + + /** + * Create a {@link Data} item for one or more {@link Constant Constants}, that can be used in a + * {@link DataPatch}. If more than one {@link Constant} is given, then they are tightly packed + * into a single {@link Data} item. + */ + Data createDataItem(Constant... constants); + + /** + * Gets a description of the target architecture. + */ + TargetDescription getTarget(); + + /** + * Create a new speculation log for the target runtime. + */ + SpeculationLog createSpeculationLog(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeUtil.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Miscellaneous collection of utility methods used by {@code jdk.vm.ci.code} and its clients. + */ +public class CodeUtil { + + public static final String NEW_LINE = String.format("%n"); + + public static final int K = 1024; + public static final int M = 1024 * 1024; + + public static boolean isOdd(int n) { + return (n & 1) == 1; + } + + public static boolean isEven(int n) { + return (n & 1) == 0; + } + + /** + * Checks whether the specified integer is a power of two. + * + * @param val the value to check + * @return {@code true} if the value is a power of two; {@code false} otherwise + */ + public static boolean isPowerOf2(int val) { + return val > 0 && (val & val - 1) == 0; + } + + /** + * Checks whether the specified long is a power of two. + * + * @param val the value to check + * @return {@code true} if the value is a power of two; {@code false} otherwise + */ + public static boolean isPowerOf2(long val) { + return val > 0 && (val & val - 1) == 0; + } + + /** + * Computes the log (base 2) of the specified integer, rounding down. (E.g {@code log2(8) = 3}, + * {@code log2(21) = 4} ) + * + * @param val the value + * @return the log base 2 of the value + */ + public static int log2(int val) { + assert val > 0; + return (Integer.SIZE - 1) - Integer.numberOfLeadingZeros(val); + } + + /** + * Computes the log (base 2) of the specified long, rounding down. (E.g {@code log2(8) = 3}, + * {@code log2(21) = 4}) + * + * @param val the value + * @return the log base 2 of the value + */ + public static int log2(long val) { + assert val > 0; + return (Long.SIZE - 1) - Long.numberOfLeadingZeros(val); + } + + /** + * Narrow an integer value to a given bit width, and return the result as a signed long. + * + * @param value the value + * @param resultBits the result bit width + * @return {@code value} interpreted as {@code resultBits} bit number, encoded as signed long + */ + public static long narrow(long value, int resultBits) { + long ret = value & mask(resultBits); + return signExtend(ret, resultBits); + } + + /** + * Sign extend an integer. + * + * @param value the input value + * @param inputBits the bit width of the input value + * @return a signed long with the same value as the signed {@code inputBits}-bit number + * {@code value} + */ + public static long signExtend(long value, int inputBits) { + if (inputBits < 64) { + if ((value >>> (inputBits - 1) & 1) == 1) { + return value | (-1L << inputBits); + } else { + return value & ~(-1L << inputBits); + } + } else { + return value; + } + } + + /** + * Zero extend an integer. + * + * @param value the input value + * @param inputBits the bit width of the input value + * @return an unsigned long with the same value as the unsigned {@code inputBits}-bit number + * {@code value} + */ + public static long zeroExtend(long value, int inputBits) { + if (inputBits < 64) { + return value & ~(-1L << inputBits); + } else { + return value; + } + } + + /** + * Convert an integer to long. + * + * @param value the input value + * @param inputBits the bit width of the input value + * @param unsigned whether the values should be interpreted as signed or unsigned + * @return a long with the same value as the {@code inputBits}-bit number {@code value} + */ + public static long convert(long value, int inputBits, boolean unsigned) { + if (unsigned) { + return zeroExtend(value, inputBits); + } else { + return signExtend(value, inputBits); + } + } + + /** + * Get a bitmask with the low {@code bits} bit set and the high {@code 64 - bits} bit clear. + */ + public static long mask(int bits) { + assert 0 <= bits && bits <= 64; + if (bits == 64) { + return 0xffffffffffffffffL; + } else { + return (1L << bits) - 1; + } + } + + /** + * Get the minimum value representable in a {@code bits} bit signed integer. + */ + public static long minValue(int bits) { + assert 0 < bits && bits <= 64; + return -1L << (bits - 1); + } + + /** + * Get the maximum value representable in a {@code bits} bit signed integer. + */ + public static long maxValue(int bits) { + assert 0 < bits && bits <= 64; + return mask(bits - 1); + } + + /** + * Formats the values in a frame as a tabulated string. + * + * @param frame + * @return the values in {@code frame} as a tabulated string + */ + public static String tabulateValues(BytecodeFrame frame) { + int cols = Math.max(frame.numLocals, Math.max(frame.numStack, frame.numLocks)); + assert cols > 0; + ArrayList cells = new ArrayList<>(); + cells.add(""); + for (int i = 0; i < cols; i++) { + cells.add(i); + } + cols++; + if (frame.numLocals != 0) { + cells.add("locals:"); + cells.addAll(Arrays.asList(frame.values).subList(0, frame.numLocals)); + cells.addAll(Collections.nCopies(cols - frame.numLocals - 1, "")); + } + if (frame.numStack != 0) { + cells.add("stack:"); + cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals, frame.numLocals + frame.numStack)); + cells.addAll(Collections.nCopies(cols - frame.numStack - 1, "")); + } + if (frame.numLocks != 0) { + cells.add("locks:"); + cells.addAll(Arrays.asList(frame.values).subList(frame.numLocals + frame.numStack, frame.values.length)); + cells.addAll(Collections.nCopies(cols - frame.numLocks - 1, "")); + } + Object[] cellArray = cells.toArray(); + for (int i = 0; i < cellArray.length; i++) { + if ((i % cols) != 0) { + cellArray[i] = "|" + cellArray[i]; + } + } + return CodeUtil.tabulate(cellArray, cols, 1, 1); + } + + /** + * Formats a given table as a string. The value of each cell is produced by + * {@link String#valueOf(Object)}. + * + * @param cells the cells of the table in row-major order + * @param cols the number of columns per row + * @param lpad the number of space padding inserted before each formatted cell value + * @param rpad the number of space padding inserted after each formatted cell value + * @return a string with one line per row and each column left-aligned + */ + public static String tabulate(Object[] cells, int cols, int lpad, int rpad) { + int rows = (cells.length + (cols - 1)) / cols; + int[] colWidths = new int[cols]; + for (int col = 0; col < cols; col++) { + for (int row = 0; row < rows; row++) { + int index = col + (row * cols); + if (index < cells.length) { + Object cell = cells[index]; + colWidths[col] = Math.max(colWidths[col], String.valueOf(cell).length()); + } + } + } + StringBuilder sb = new StringBuilder(); + String nl = NEW_LINE; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + int index = col + (row * cols); + if (index < cells.length) { + for (int i = 0; i < lpad; i++) { + sb.append(' '); + } + Object cell = cells[index]; + String s = String.valueOf(cell); + int w = s.length(); + sb.append(s); + while (w < colWidths[col]) { + sb.append(' '); + w++; + } + for (int i = 0; i < rpad; i++) { + sb.append(' '); + } + } + } + sb.append(nl); + } + return sb.toString(); + } + + /** + * Appends a formatted code position to a {@link StringBuilder}. + * + * @param sb the {@link StringBuilder} to append to + * @param pos the code position to format and append to {@code sb} + * @return the value of {@code sb} + */ + public static StringBuilder append(StringBuilder sb, BytecodePosition pos) { + MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI()); + if (pos.getCaller() != null) { + sb.append(NEW_LINE); + append(sb, pos.getCaller()); + } + return sb; + } + + /** + * Appends a formatted frame to a {@link StringBuilder}. + * + * @param sb the {@link StringBuilder} to append to + * @param frame the frame to format and append to {@code sb} + * @return the value of {@code sb} + */ + public static StringBuilder append(StringBuilder sb, BytecodeFrame frame) { + MetaUtil.appendLocation(sb.append("at "), frame.getMethod(), frame.getBCI()); + assert sb.charAt(sb.length() - 1) == ']'; + sb.deleteCharAt(sb.length() - 1); + sb.append(", duringCall: ").append(frame.duringCall).append(", rethrow: ").append(frame.rethrowException).append(']'); + if (frame.values != null && frame.values.length > 0) { + sb.append(NEW_LINE); + String table = tabulateValues(frame); + String[] rows = table.split(NEW_LINE); + for (int i = 0; i < rows.length; i++) { + String row = rows[i]; + if (!row.trim().isEmpty()) { + sb.append(" ").append(row); + if (i != rows.length - 1) { + sb.append(NEW_LINE); + } + } + } + } + if (frame.caller() != null) { + sb.append(NEW_LINE); + append(sb, frame.caller()); + } else if (frame.getCaller() != null) { + sb.append(NEW_LINE); + append(sb, frame.getCaller()); + } + return sb; + } + + public interface RefMapFormatter { + + String formatStackSlot(int frameRefMapIndex); + + String formatRegister(int regRefMapIndex); + } + + /** + * Formats a location in a register reference map. + */ + public static class DefaultRegFormatter implements RefMapFormatter { + + private final Register[] registers; + + public DefaultRegFormatter(Architecture arch) { + registers = new Register[arch.getRegisterReferenceMapSize()]; + for (Register r : arch.getRegisters()) { + if (r.getReferenceMapIndex() >= 0) { + registers[r.getReferenceMapIndex()] = r; + } + } + } + + public String formatStackSlot(int frameRefMapIndex) { + return null; + } + + public String formatRegister(int regRefMapIndex) { + int i = regRefMapIndex; + int idx = 0; + while (registers[i] == null) { + i--; + idx++; + } + if (idx == 0) { + return registers[i].toString(); + } else { + return String.format("%s+%d", registers[i].toString(), idx); + } + } + } + + /** + * Formats a location present in a register or frame reference map. + */ + public static class DefaultRefMapFormatter extends DefaultRegFormatter { + + /** + * The size of a stack slot. + */ + public final int slotSize; + + /** + * The register used as the frame pointer. + */ + public final Register fp; + + /** + * The offset (in bytes) from the slot pointed to by {@link #fp} to the slot corresponding + * to bit 0 in the frame reference map. + */ + public final int refMapToFPOffset; + + public DefaultRefMapFormatter(Architecture arch, int slotSize, Register fp, int refMapToFPOffset) { + super(arch); + this.slotSize = slotSize; + this.fp = fp; + this.refMapToFPOffset = refMapToFPOffset; + } + + @Override + public String formatStackSlot(int frameRefMapIndex) { + int refMapOffset = frameRefMapIndex * slotSize; + int fpOffset = refMapOffset + refMapToFPOffset; + if (fpOffset >= 0) { + return fp + "+" + fpOffset; + } + return fp.name + fpOffset; + } + } + + public static class NumberedRefMapFormatter implements RefMapFormatter { + + public String formatStackSlot(int frameRefMapIndex) { + return "s" + frameRefMapIndex; + } + + public String formatRegister(int regRefMapIndex) { + return "r" + regRefMapIndex; + } + } + + /** + * Appends a formatted debug info to a {@link StringBuilder}. + * + * @param sb the {@link StringBuilder} to append to + * @param info the debug info to format and append to {@code sb} + * @return the value of {@code sb} + */ + public static StringBuilder append(StringBuilder sb, DebugInfo info, RefMapFormatter formatterArg) { + RefMapFormatter formatter = formatterArg; + if (formatter == null) { + formatter = new NumberedRefMapFormatter(); + } + String nl = NEW_LINE; + ReferenceMap refMap = info.getReferenceMap(); + if (refMap != null) { + sb.append(refMap.toString()); + } + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append("callee-save-info:").append(nl); + Map map = calleeSaveInfo.slotsToRegisters(true); + for (Map.Entry e : map.entrySet()) { + sb.append(" ").append(e.getValue()).append(" -> ").append(formatter.formatStackSlot(e.getKey())).append(nl); + } + } + BytecodeFrame frame = info.frame(); + if (frame != null) { + append(sb, frame); + } else if (info.getBytecodePosition() != null) { + append(sb, info.getBytecodePosition()); + } + return sb; + } + + /** + * Create a calling convention from a {@link ResolvedJavaMethod}. + */ + public static CallingConvention getCallingConvention(CodeCacheProvider codeCache, CallingConvention.Type type, ResolvedJavaMethod method, boolean stackOnly) { + Signature sig = method.getSignature(); + JavaType retType = sig.getReturnType(null); + int sigCount = sig.getParameterCount(false); + JavaType[] argTypes; + int argIndex = 0; + if (!method.isStatic()) { + argTypes = new JavaType[sigCount + 1]; + argTypes[argIndex++] = method.getDeclaringClass(); + } else { + argTypes = new JavaType[sigCount]; + } + for (int i = 0; i < sigCount; i++) { + argTypes[argIndex++] = sig.getParameterType(i, null); + } + + RegisterConfig registerConfig = codeCache.getRegisterConfig(); + return registerConfig.getCallingConvention(type, retType, argTypes, codeCache.getTarget(), stackOnly); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationResult.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1054 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import static java.util.Collections.*; +import static jdk.vm.ci.meta.MetaUtil.*; + +import java.util.*; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.*; + +/** + * Represents the output from compiling a method, including the compiled machine code, associated + * data and references, relocation information, deoptimization information, etc. + */ +public class CompilationResult { + + /** + * Represents a code position with associated additional information. + */ + public abstract static class Site { + + /** + * The position (or offset) of this site with respect to the start of the target method. + */ + public final int pcOffset; + + public Site(int pos) { + this.pcOffset = pos; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public abstract boolean equals(Object obj); + } + + /** + * Represents an infopoint with associated debug info. Note that safepoints are also infopoints. + */ + public static class Infopoint extends Site implements Comparable { + + public final DebugInfo debugInfo; + + public final InfopointReason reason; + + public Infopoint(int pcOffset, DebugInfo debugInfo, InfopointReason reason) { + super(pcOffset); + this.debugInfo = debugInfo; + this.reason = reason; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(pcOffset); + sb.append("[]"); + appendDebugInfo(sb, debugInfo); + return sb.toString(); + } + + @Override + public int compareTo(Infopoint o) { + if (pcOffset < o.pcOffset) { + return -1; + } else if (pcOffset > o.pcOffset) { + return 1; + } + return this.reason.compareTo(o.reason); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj != null && obj.getClass() == getClass()) { + Infopoint that = (Infopoint) obj; + if (this.pcOffset == that.pcOffset && Objects.equals(this.debugInfo, that.debugInfo) && Objects.equals(this.reason, that.reason)) { + return true; + } + } + return false; + } + } + + public enum MetaSpaceAccessType { + Move, + Store, // store only works for compressed oops (memory <- 32bit value). Compressed oops is + // not supported using AOT. TODO: Look at HotSpotStoreConstantOp + Compare; // HotSpotCompareMemoryConstantOp, HotSpotCompareConstantOp + + private MetaSpaceAccessType() { + } + } + + /** + * Represents a meta space pointer access in the code. + */ + public static final class MetaSpaceAccess extends Infopoint { + + private static final long serialVersionUID = 1701958512608684706L; + + /** + * Metaspace reference. + */ + public final Object reference; // Object here is a HotSpotResolvedObjectType or a + // HotSpotMetaSpaceConstant + + public final MetaSpaceAccessType type; + + /** + * Instruction size. + */ + public final int instructionSize; + + public MetaSpaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int pcOffset, DebugInfo debugInfo) { + super(pcOffset, debugInfo, InfopointReason.METASPACE_ACCESS); + this.type = type; + this.reference = reference; + this.instructionSize = instructionSize; + } + } + + /** + * Represents a call in the code. + */ + public static final class Call extends Infopoint { + + /** + * The target of the call. + */ + public final InvokeTarget target; + + /** + * The size of the call instruction. + */ + public final int size; + + /** + * Specifies if this call is direct or indirect. A direct call has an immediate operand + * encoding the absolute or relative (to the call itself) address of the target. An indirect + * call has a register or memory operand specifying the target address of the call. + */ + public final boolean direct; + + public Call(InvokeTarget target, int pcOffset, int size, boolean direct, DebugInfo debugInfo) { + super(pcOffset, debugInfo, InfopointReason.CALL); + this.size = size; + this.target = target; + this.direct = direct; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Call && super.equals(obj)) { + Call that = (Call) obj; + if (this.size == that.size && this.direct == that.direct && Objects.equals(this.target, that.target)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(pcOffset); + sb.append('['); + sb.append(target); + sb.append(']'); + + if (debugInfo != null) { + appendDebugInfo(sb, debugInfo); + } + + return sb.toString(); + } + } + + /** + * Represents some external data that is referenced by the code. + */ + public abstract static class Reference { + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(Object obj); + } + + public static final class ConstantReference extends Reference { + + private final VMConstant constant; + + public ConstantReference(VMConstant constant) { + this.constant = constant; + } + + public VMConstant getConstant() { + return constant; + } + + @Override + public String toString() { + return constant.toString(); + } + + @Override + public int hashCode() { + return constant.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ConstantReference) { + ConstantReference that = (ConstantReference) obj; + return Objects.equals(this.constant, that.constant); + } + return false; + } + } + + public static final class DataSectionReference extends Reference { + + private boolean initialized; + private int offset; + + public DataSectionReference() { + // will be set after the data section layout is fixed + offset = 0xDEADDEAD; + } + + public int getOffset() { + assert initialized; + + return offset; + } + + public void setOffset(int offset) { + assert !initialized; + initialized = true; + + this.offset = offset; + } + + @Override + public int hashCode() { + return offset; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataSectionReference) { + DataSectionReference that = (DataSectionReference) obj; + return this.offset == that.offset; + } + return false; + } + } + + /** + * Represents a code site that references some data. The associated data can be either a + * {@link DataSectionReference reference} to the data section, or it may be an inlined + * {@link JavaConstant} that needs to be patched. + */ + public static final class DataPatch extends Site { + + public Reference reference; + public Object note; + + public DataPatch(int pcOffset, Reference reference) { + super(pcOffset); + this.reference = reference; + this.note = null; + } + + public DataPatch(int pcOffset, Reference reference, Object note) { + super(pcOffset); + this.reference = reference; + this.note = note; + } + + @Override + public String toString() { + if (note != null) { + return String.format("%d[, note: %s]", pcOffset, reference.toString(), note.toString()); + } else { + return String.format("%d[]", pcOffset, reference.toString()); + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataPatch) { + DataPatch that = (DataPatch) obj; + if (this.pcOffset == that.pcOffset && Objects.equals(this.reference, that.reference) && Objects.equals(this.note, that.note)) { + return true; + } + } + return false; + } + } + + /** + * Provides extra information about instructions or data at specific positions in + * {@link CompilationResult#getTargetCode()}. This is optional information that can be used to + * enhance a disassembly of the code. + */ + public abstract static class CodeAnnotation { + + public final int position; + + public CodeAnnotation(int position) { + this.position = position; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public abstract boolean equals(Object obj); + } + + /** + * A string comment about one or more instructions at a specific position in the code. + */ + public static final class CodeComment extends CodeAnnotation { + + public final String value; + + public CodeComment(int position, String comment) { + super(position); + this.value = comment; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof CodeComment) { + CodeComment that = (CodeComment) obj; + if (this.position == that.position && this.value.equals(that.value)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "@" + position + ": " + value; + } + } + + /** + * Describes a table of signed offsets embedded in the code. The offsets are relative to the + * starting address of the table. This type of table maybe generated when translating a + * multi-way branch based on a key value from a dense value set (e.g. the {@code tableswitch} + * JVM instruction). + * + * The table is indexed by the contiguous range of integers from {@link #low} to {@link #high} + * inclusive. + */ + public static final class JumpTable extends CodeAnnotation { + + /** + * The low value in the key range (inclusive). + */ + public final int low; + + /** + * The high value in the key range (inclusive). + */ + public final int high; + + /** + * The size (in bytes) of each table entry. + */ + public final int entrySize; + + public JumpTable(int position, int low, int high, int entrySize) { + super(position); + this.low = low; + this.high = high; + this.entrySize = entrySize; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof JumpTable) { + JumpTable that = (JumpTable) obj; + if (this.position == that.position && this.entrySize == that.entrySize && this.low == that.low && this.high == that.high) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "@" + position + ": [" + low + " .. " + high + "]"; + } + } + + /** + * Represents exception handler information for a specific code position. It includes the catch + * code position as well as the caught exception type. + */ + public static final class ExceptionHandler extends Site { + + public final int handlerPos; + + ExceptionHandler(int pcOffset, int handlerPos) { + super(pcOffset); + this.handlerPos = handlerPos; + } + + @Override + public String toString() { + return String.format("%d[]", pcOffset, handlerPos); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof ExceptionHandler) { + ExceptionHandler that = (ExceptionHandler) obj; + if (this.pcOffset == that.pcOffset && this.handlerPos == that.handlerPos) { + return true; + } + } + return false; + } + } + + /** + * Represents a mark in the machine code that can be used by the runtime for its own purposes. A + * mark can reference other marks. + */ + public static final class Mark extends Site { + + public final Object id; + + public Mark(int pcOffset, Object id) { + super(pcOffset); + this.id = id; + } + + @Override + public String toString() { + if (id == null) { + return String.format("%d[]", pcOffset); + } else if (id instanceof Integer) { + return String.format("%d[]", pcOffset, Integer.toHexString((Integer) id)); + } else { + return String.format("%d[]", pcOffset, id.toString()); + } + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Mark) { + Mark that = (Mark) obj; + if (this.pcOffset == that.pcOffset && Objects.equals(this.id, that.id)) { + return true; + } + } + return false; + } + } + + private int id = -1; + + /** + * Specifies whether this compilation is a {@code +ImmutableCode} {@code +GeneratePIC} + * compilation. + */ + private final boolean isImmutablePIC; + + private int entryBCI = -1; + + private final DataSection dataSection = new DataSection(); + + private final List infopoints = new ArrayList<>(); + private final List dataPatches = new ArrayList<>(); + private final List exceptionHandlers = new ArrayList<>(); + private final List marks = new ArrayList<>(); + + private int totalFrameSize = -1; + private int customStackAreaOffset = -1; + + private final String name; + + /** + * The buffer containing the emitted machine code. + */ + private byte[] targetCode; + + /** + * The leading number of bytes in {@link #targetCode} containing the emitted machine code. + */ + private int targetCodeSize; + + private ArrayList annotations; + + private Assumption[] assumptions; + + /** + * The list of the methods whose bytecodes were used as input to the compilation. If + * {@code null}, then the compilation did not record method dependencies. Otherwise, the first + * element of this array is the root method of the compilation. + */ + private ResolvedJavaMethod[] methods; + + private int bytecodeSize; + + private boolean hasUnsafeAccess; + + public CompilationResult() { + this(null); + } + + public CompilationResult(String name) { + this.name = name; + this.isImmutablePIC = false; + } + + public CompilationResult(boolean isImmutablePIC) { + this.name = null; + this.isImmutablePIC = isImmutablePIC; + } + + @Override + public int hashCode() { + // CompilationResult instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + if (methods != null) { + return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]"; + } + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj != null && obj.getClass() == getClass()) { + CompilationResult that = (CompilationResult) obj; + // @formatter:off + if (this.entryBCI == that.entryBCI && + this.id == that.id && + this.customStackAreaOffset == that.customStackAreaOffset && + this.totalFrameSize == that.totalFrameSize && + this.targetCodeSize == that.targetCodeSize && + Objects.equals(this.name, that.name) && + Objects.equals(this.annotations, that.annotations) && + Objects.equals(this.dataSection, that.dataSection) && + Objects.equals(this.exceptionHandlers, that.exceptionHandlers) && + Objects.equals(this.dataPatches, that.dataPatches) && + Objects.equals(this.infopoints, that.infopoints) && + Objects.equals(this.marks, that.marks) && + Arrays.equals(this.assumptions, that.assumptions) && + Arrays.equals(targetCode, that.targetCode)) { + return true; + } + // @formatter:on + } + return false; + } + + /** + * @return the compile id + */ + public int getId() { + return id; + } + + /** + * @param id the compile id to set + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return true is this is a {@code +ImmutableCode} {@code +GeneratePIC} compilation, false + * otherwise. + */ + public boolean isImmutablePIC() { + return isImmutablePIC; + } + + /** + * @return the entryBCI + */ + public int getEntryBCI() { + return entryBCI; + } + + /** + * @param entryBCI the entryBCI to set + */ + public void setEntryBCI(int entryBCI) { + this.entryBCI = entryBCI; + } + + /** + * Sets the assumptions made during compilation. + */ + public void setAssumptions(Assumption[] assumptions) { + this.assumptions = assumptions; + } + + /** + * Gets the assumptions made during compilation. + */ + public Assumption[] getAssumptions() { + return assumptions; + } + + /** + * Sets the methods whose bytecodes were used as input to the compilation. + * + * @param rootMethod the root method of the compilation + * @param inlinedMethods the methods inlined during compilation + */ + public void setMethods(ResolvedJavaMethod rootMethod, Collection inlinedMethods) { + assert rootMethod != null; + assert inlinedMethods != null; + if (inlinedMethods.contains(rootMethod)) { + methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]); + for (int i = 0; i < methods.length; i++) { + if (methods[i].equals(rootMethod)) { + if (i != 0) { + ResolvedJavaMethod tmp = methods[0]; + methods[0] = methods[i]; + methods[i] = tmp; + } + break; + } + } + } else { + methods = new ResolvedJavaMethod[1 + inlinedMethods.size()]; + methods[0] = rootMethod; + int i = 1; + for (ResolvedJavaMethod m : inlinedMethods) { + methods[i++] = m; + } + } + } + + /** + * Gets the methods whose bytecodes were used as input to the compilation. + * + * @return {@code null} if the compilation did not record method dependencies otherwise the + * methods whose bytecodes were used as input to the compilation with the first element + * being the root method of the compilation + */ + public ResolvedJavaMethod[] getMethods() { + return methods; + } + + public void setBytecodeSize(int bytecodeSize) { + this.bytecodeSize = bytecodeSize; + } + + public int getBytecodeSize() { + return bytecodeSize; + } + + public DataSection getDataSection() { + return dataSection; + } + + /** + * The total frame size of the method in bytes. This includes the return address pushed onto the + * stack, if any. + * + * @return the frame size + */ + public int getTotalFrameSize() { + assert totalFrameSize != -1 : "frame size not yet initialized!"; + return totalFrameSize; + } + + /** + * Sets the total frame size in bytes. This includes the return address pushed onto the stack, + * if any. + * + * @param size the size of the frame in bytes + */ + public void setTotalFrameSize(int size) { + totalFrameSize = size; + } + + /** + * Sets the machine that has been generated by the compiler. + * + * @param code the machine code generated + * @param size the size of the machine code + */ + public void setTargetCode(byte[] code, int size) { + targetCode = code; + targetCodeSize = size; + } + + /** + * Records a data patch in the code section. The data patch can refer to something in the + * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined + * constant}. + * + * @param codePos The position in the code that needs to be patched. + * @param ref The reference that should be inserted in the code. + */ + public void recordDataPatch(int codePos, Reference ref) { + assert codePos >= 0 && ref != null; + dataPatches.add(new DataPatch(codePos, ref)); + } + + /** + * Records a data patch in the code section. The data patch can refer to something in the + * {@link DataSectionReference data section} or directly to an {@link ConstantReference inlined + * constant}. + * + * @param codePos The position in the code that needs to be patched. + * @param ref The reference that should be inserted in the code. + * @param note The note attached to data patch for use by post-processing tools + */ + public void recordDataPatchWithNote(int codePos, Reference ref, Object note) { + assert codePos >= 0 && ref != null; + dataPatches.add(new DataPatch(codePos, ref, note)); + } + + /** + * Records metaspace access. + */ + public void recordMetaspaceAccess(Object reference, int instructionSize, MetaSpaceAccessType type, int codePos, DebugInfo debugInfo) { + final MetaSpaceAccess metaspace = new MetaSpaceAccess(reference, instructionSize, type, codePos, debugInfo); + addInfopoint(metaspace); + } + + /** + * Records a call in the code array. + * + * @param codePos the position of the call in the code array + * @param size the size of the call instruction + * @param target the being called + * @param debugInfo the debug info for the call + * @param direct specifies if this is a {@linkplain Call#direct direct} call + */ + public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) { + final Call call = new Call(target, codePos, size, direct, debugInfo); + addInfopoint(call); + } + + /** + * Records an exception handler for this method. + * + * @param codePos the position in the code that is covered by the handler + * @param handlerPos the position of the handler + */ + public void recordExceptionHandler(int codePos, int handlerPos) { + assert validateExceptionHandlerAdd(codePos, handlerPos) : String.format("Duplicate exception handler for pc 0x%x handlerPos 0x%x", codePos, handlerPos); + exceptionHandlers.add(new ExceptionHandler(codePos, handlerPos)); + } + + /** + * Validate if the exception handler for codePos already exists and handlerPos is different. + * + * @param codePos + * @param handlerPos + * @return true if the validation is successful + */ + private boolean validateExceptionHandlerAdd(int codePos, int handlerPos) { + ExceptionHandler exHandler = getExceptionHandlerForCodePos(codePos); + return exHandler == null || exHandler.handlerPos == handlerPos; + } + + /** + * Returns the first ExceptionHandler which matches codePos. + * + * @param codePos position to search for + * @return first matching ExceptionHandler + */ + private ExceptionHandler getExceptionHandlerForCodePos(int codePos) { + for (ExceptionHandler h : exceptionHandlers) { + if (h.pcOffset == codePos) { + return h; + } + } + return null; + } + + /** + * Records an infopoint in the code array. + * + * @param codePos the position of the infopoint in the code array + * @param debugInfo the debug info for the infopoint + */ + public void recordInfopoint(int codePos, DebugInfo debugInfo, InfopointReason reason) { + addInfopoint(new Infopoint(codePos, debugInfo, reason)); + } + + /** + * Records a custom infopoint in the code section. + * + * Compiler implementations can use this method to record non-standard infopoints, which are not + * handled by the dedicated methods like {@link #recordCall}. + * + * @param infopoint the infopoint to record, usually a derived class from {@link Infopoint} + */ + public void addInfopoint(Infopoint infopoint) { + // The infopoints list must always be sorted + if (!infopoints.isEmpty()) { + Infopoint previousInfopoint = infopoints.get(infopoints.size() - 1); + if (previousInfopoint.pcOffset > infopoint.pcOffset) { + // This re-sorting should be very rare + Collections.sort(infopoints); + previousInfopoint = infopoints.get(infopoints.size() - 1); + } + if (previousInfopoint.pcOffset == infopoint.pcOffset) { + if (infopoint.reason.canBeOmitted()) { + return; + } + if (previousInfopoint.reason.canBeOmitted()) { + Infopoint removed = infopoints.remove(infopoints.size() - 1); + assert removed == previousInfopoint; + } else { + throw new RuntimeException("Infopoints that can not be omited should have distinct PCs"); + } + } + } + infopoints.add(infopoint); + } + + /** + * Records an instruction mark within this method. + * + * @param codePos the position in the code that is covered by the handler + * @param markId the identifier for this mark + */ + public Mark recordMark(int codePos, Object markId) { + Mark mark = new Mark(codePos, markId); + marks.add(mark); + return mark; + } + + /** + * Offset in bytes for the custom stack area (relative to sp). + * + * @return the offset in bytes + */ + public int getCustomStackAreaOffset() { + return customStackAreaOffset; + } + + /** + * @see #getCustomStackAreaOffset() + * @param offset + */ + public void setCustomStackAreaOffset(int offset) { + customStackAreaOffset = offset; + } + + /** + * @return the machine code generated for this method + */ + public byte[] getTargetCode() { + return targetCode; + } + + /** + * @return the size of the machine code generated for this method + */ + public int getTargetCodeSize() { + return targetCodeSize; + } + + /** + * @return the code annotations or {@code null} if there are none + */ + public List getAnnotations() { + if (annotations == null) { + return Collections.emptyList(); + } + return annotations; + } + + public void addAnnotation(CodeAnnotation annotation) { + assert annotation != null; + if (annotations == null) { + annotations = new ArrayList<>(); + } + annotations.add(annotation); + } + + private static void appendDebugInfo(StringBuilder sb, DebugInfo info) { + if (info != null) { + ReferenceMap refMap = info.getReferenceMap(); + if (refMap != null) { + sb.append(refMap.toString()); + sb.append(']'); + } + RegisterSaveLayout calleeSaveInfo = info.getCalleeSaveInfo(); + if (calleeSaveInfo != null) { + sb.append(" callee-save-info["); + String sep = ""; + for (Map.Entry e : calleeSaveInfo.registersToSlots(true).entrySet()) { + sb.append(sep).append(e.getKey()).append("->").append(e.getValue()); + sep = ", "; + } + sb.append(']'); + } + BytecodePosition codePos = info.getBytecodePosition(); + if (codePos != null) { + MetaUtil.appendLocation(sb.append(" "), codePos.getMethod(), codePos.getBCI()); + if (info.hasFrame()) { + sb.append(" #locals=").append(info.frame().numLocals).append(" #expr=").append(info.frame().numStack); + if (info.frame().numLocks > 0) { + sb.append(" #locks=").append(info.frame().numLocks); + } + } + } + } + } + + /** + * @return the list of infopoints, sorted by {@link Site#pcOffset} + */ + public List getInfopoints() { + if (infopoints.isEmpty()) { + return emptyList(); + } + return unmodifiableList(infopoints); + } + + /** + * @return the list of data references + */ + public List getDataPatches() { + if (dataPatches.isEmpty()) { + return emptyList(); + } + return unmodifiableList(dataPatches); + } + + /** + * @return the list of exception handlers + */ + public List getExceptionHandlers() { + if (exceptionHandlers.isEmpty()) { + return emptyList(); + } + return unmodifiableList(exceptionHandlers); + } + + /** + * @return the list of marks + */ + public List getMarks() { + if (marks.isEmpty()) { + return emptyList(); + } + return unmodifiableList(marks); + } + + public String getName() { + return name; + } + + public void setHasUnsafeAccess(boolean hasUnsafeAccess) { + this.hasUnsafeAccess = hasUnsafeAccess; + } + + public boolean hasUnsafeAccess() { + return hasUnsafeAccess; + } + + public void reset() { + hasUnsafeAccess = false; + infopoints.clear(); + dataPatches.clear(); + exceptionHandlers.clear(); + marks.clear(); + dataSection.clear(); + if (annotations != null) { + annotations.clear(); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DataSection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DataSection.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import static jdk.vm.ci.meta.MetaUtil.*; + +import java.nio.*; +import java.util.*; +import java.util.function.*; + +import jdk.vm.ci.code.CompilationResult.*; +import jdk.vm.ci.code.DataSection.*; +import jdk.vm.ci.meta.*; + +public final class DataSection implements Iterable { + + @FunctionalInterface + public interface DataBuilder { + + void emit(ByteBuffer buffer, Consumer patch); + + static DataBuilder raw(byte[] data) { + return (buffer, patch) -> buffer.put(data); + } + + static DataBuilder serializable(SerializableConstant c) { + return (buffer, patch) -> c.serialize(buffer); + } + + static DataBuilder zero(int size) { + switch (size) { + case 1: + return (buffer, patch) -> buffer.put((byte) 0); + case 2: + return (buffer, patch) -> buffer.putShort((short) 0); + case 4: + return (buffer, patch) -> buffer.putInt(0); + case 8: + return (buffer, patch) -> buffer.putLong(0L); + default: + return (buffer, patch) -> { + int rest = size; + while (rest > 8) { + buffer.putLong(0L); + rest -= 8; + } + while (rest > 0) { + buffer.put((byte) 0); + rest--; + } + }; + } + } + } + + public static final class Data { + + private int alignment; + private final int size; + private final DataBuilder builder; + + private DataSectionReference ref; + + public Data(int alignment, int size, DataBuilder builder) { + this.alignment = alignment; + this.size = size; + this.builder = builder; + + // initialized in DataSection.insertData(Data) + ref = null; + } + + public void updateAlignment(int newAlignment) { + if (newAlignment == alignment) { + return; + } + alignment = lcm(alignment, newAlignment); + } + + public int getAlignment() { + return alignment; + } + + public int getSize() { + return size; + } + + public DataBuilder getBuilder() { + return builder; + } + + @Override + public int hashCode() { + // Data instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + assert ref != null; + if (obj == this) { + return true; + } + if (obj instanceof Data) { + Data that = (Data) obj; + if (this.alignment == that.alignment && this.size == that.size && this.ref.equals(that.ref)) { + return true; + } + } + return false; + } + } + + private final ArrayList dataItems = new ArrayList<>(); + + private boolean finalLayout; + private int sectionAlignment; + private int sectionSize; + + @Override + public int hashCode() { + // DataSection instances should not be used as hash map keys + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DataSection) { + DataSection that = (DataSection) obj; + if (this.finalLayout == that.finalLayout && this.sectionAlignment == that.sectionAlignment && this.sectionSize == that.sectionSize && Objects.equals(this.dataItems, that.dataItems)) { + return true; + } + } + return false; + } + + /** + * Insert a {@link Data} item into the data section. If the item is already in the data section, + * the same {@link DataSectionReference} is returned. + * + * @param data the {@link Data} item to be inserted + * @return a unique {@link DataSectionReference} identifying the {@link Data} item + */ + public DataSectionReference insertData(Data data) { + assert !finalLayout; + if (data.ref == null) { + data.ref = new DataSectionReference(); + dataItems.add(data); + } + return data.ref; + } + + /** + * Compute the layout of the data section. This can be called only once, and after it has been + * called, the data section can no longer be modified. + */ + public void finalizeLayout() { + assert !finalLayout; + finalLayout = true; + + // simple heuristic: put items with larger alignment requirement first + dataItems.sort((a, b) -> a.alignment - b.alignment); + + int position = 0; + for (Data d : dataItems) { + sectionAlignment = lcm(sectionAlignment, d.alignment); + position = align(position, d.alignment); + + d.ref.setOffset(position); + position += d.size; + } + + sectionSize = position; + } + + public boolean isFinalized() { + return finalLayout; + } + + /** + * Get the size of the data section. Can only be called after {@link #finalizeLayout}. + */ + public int getSectionSize() { + assert finalLayout; + return sectionSize; + } + + /** + * Get the minimum alignment requirement of the data section. Can only be called after + * {@link #finalizeLayout}. + */ + public int getSectionAlignment() { + assert finalLayout; + return sectionAlignment; + } + + /** + * Build the data section. Can only be called after {@link #finalizeLayout}. + * + * @param buffer The {@link ByteBuffer} where the data section should be built. The buffer must + * hold at least {@link #getSectionSize()} bytes. + * @param patch A {@link Consumer} to receive {@link DataPatch data patches} for relocations in + * the data section. + */ + public void buildDataSection(ByteBuffer buffer, Consumer patch) { + assert finalLayout; + for (Data d : dataItems) { + buffer.position(d.ref.getOffset()); + d.builder.emit(buffer, patch); + } + } + + public Data findData(DataSectionReference ref) { + for (Data d : dataItems) { + if (d.ref == ref) { + return d; + } + } + return null; + } + + public Iterator iterator() { + return dataItems.iterator(); + } + + public static int lcm(int x, int y) { + if (x == 0) { + return y; + } else if (y == 0) { + return x; + } + + int a = Math.max(x, y); + int b = Math.min(x, y); + while (b > 0) { + int tmp = a % b; + a = b; + b = tmp; + } + + int gcd = a; + return x * y / gcd; + } + + private static int align(int position, int alignment) { + return ((position + alignment - 1) / alignment) * alignment; + } + + public void clear() { + assert !finalLayout; + this.dataItems.clear(); + this.sectionAlignment = 0; + this.sectionSize = 0; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import java.util.*; + +/** + * Represents the debugging information for a particular point of execution. This information + * includes: + *
    + *
  • a {@linkplain #getBytecodePosition() bytecode position}
  • + *
  • a reference map for registers and stack slots in the current frame
  • + *
  • a map from bytecode locals and operand stack slots to their values or locations from which + * their values can be read
  • + *
  • a map from the registers (in the caller's frame) to the slots where they are saved in the + * current frame
  • + *
+ */ +public final class DebugInfo { + + private final BytecodePosition bytecodePosition; + private ReferenceMap referenceMap; + @SuppressWarnings("unused") private final VirtualObject[] virtualObjectMapping; + private RegisterSaveLayout calleeSaveInfo; + + /** + * Creates a new {@link DebugInfo} from the given values. + * + * @param codePos the {@linkplain BytecodePosition code position} or {@linkplain BytecodeFrame + * frame} info + * @param virtualObjectMapping the mapping of {@link VirtualObject}s to their real values + */ + public DebugInfo(BytecodePosition codePos, VirtualObject[] virtualObjectMapping) { + this.bytecodePosition = codePos; + this.virtualObjectMapping = virtualObjectMapping; + } + + public DebugInfo(BytecodePosition codePos) { + this(codePos, null); + } + + public void setReferenceMap(ReferenceMap referenceMap) { + this.referenceMap = referenceMap; + } + + /** + * @return {@code true} if this debug information has a frame + */ + public boolean hasFrame() { + return getBytecodePosition() instanceof BytecodeFrame; + } + + /** + * Gets the deoptimization information for each inlined frame (if available). + * + * @return {@code null} if no frame de-opt info is {@linkplain #hasFrame() available} + */ + public BytecodeFrame frame() { + if (hasFrame()) { + return (BytecodeFrame) getBytecodePosition(); + } + return null; + } + + @Override + public String toString() { + return CodeUtil.append(new StringBuilder(100), this, null).toString(); + } + + /** + * @return The code position (including all inlined methods) of this debug info. If this is a + * {@link BytecodeFrame} instance, then it is also the deoptimization information for + * each inlined frame. + */ + public BytecodePosition getBytecodePosition() { + return bytecodePosition; + } + + public ReferenceMap getReferenceMap() { + return referenceMap; + } + + /** + * Sets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. + */ + public void setCalleeSaveInfo(RegisterSaveLayout calleeSaveInfo) { + this.calleeSaveInfo = calleeSaveInfo; + } + + /** + * Gets the map from the registers (in the caller's frame) to the slots where they are saved in + * the current frame. If no such information is available, {@code null} is returned. + */ + public RegisterSaveLayout getCalleeSaveInfo() { + return calleeSaveInfo; + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof DebugInfo) { + DebugInfo that = (DebugInfo) obj; + if (Objects.equals(this.bytecodePosition, that.bytecodePosition) && Objects.equals(this.calleeSaveInfo, that.calleeSaveInfo) && Objects.equals(this.referenceMap, that.referenceMap)) { + return true; + } + } + return false; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InfopointReason.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InfopointReason.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * A reason for infopoint insertion. + */ +public enum InfopointReason { + UNKNOWN(false), + SAFEPOINT(false), + CALL(false), + IMPLICIT_EXCEPTION(false), + METHOD_START(true), + METHOD_END(true), + LINE_NUMBER(true), + METASPACE_ACCESS(true); + + private InfopointReason(boolean canBeOmitted) { + this.canBeOmitted = canBeOmitted; + } + + private final boolean canBeOmitted; + + public boolean canBeOmitted() { + return canBeOmitted; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Represents a compiled instance of a method. It may have been invalidated or removed in the + * meantime. + */ +public class InstalledCode { + + /** + * Raw address of this code blob. + */ + private long address; + + /** + * Counts how often the address field was reassigned. + */ + private long version; + + protected final String name; + + public InstalledCode(String name) { + this.name = name; + } + + public final void setAddress(long address) { + this.address = address; + version++; + } + + /** + * @return the address of this code blob + */ + public final long getAddress() { + return address; + } + + /** + * @return the address of this code blob + */ + public final long getVersion() { + return version; + } + + /** + * Returns the name of this code blob. + */ + public String getName() { + return name; + } + + /** + * Returns the start address of this installed code if it is {@linkplain #isValid() valid}, 0 + * otherwise. + */ + public long getStart() { + return 0; + } + + /** + * Returns the number of instruction bytes for this code. + */ + public long getCodeSize() { + return 0; + } + + /** + * Returns a copy of this installed code if it is {@linkplain #isValid() valid}, null otherwise. + */ + public byte[] getCode() { + return null; + } + + /** + * @return true if the code represented by this object is still valid, false otherwise (may + * happen due to deopt, etc.) + */ + public boolean isValid() { + return address != 0; + } + + /** + * Invalidates this installed code such that any subsequent + * {@linkplain #executeVarargs(Object...) invocation} will throw an + * {@link InvalidInstalledCodeException}. + */ + public void invalidate() { + throw new UnsupportedOperationException(); + } + + /** + * Executes the installed code with a variable number of arguments. + * + * @param args the array of object arguments + * @return the value returned by the executed code + */ + @SuppressWarnings("unused") + public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { + throw new UnsupportedOperationException(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Exception thrown by the runtime in case an invalidated machine code is called. + */ +public final class InvalidInstalledCodeException extends Exception { + + private static final long serialVersionUID = -3540232440794244844L; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Location.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Location.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +/** + * Represents a location where a value can be stored. This can be either a {@link Register} or a + * stack slot. + */ +public final class Location { + + public final Register reg; + public final int offset; + + private Location(Register reg, int offset) { + this.reg = reg; + this.offset = offset; + } + + /** + * Create a {@link Location} for a register. + */ + public static Location register(Register reg) { + return new Location(reg, 0); + } + + /** + * Create a {@link Location} for a vector subregister. + * + * @param reg the {@link Register vector register} + * @param offset the offset in bytes into the vector register + */ + public static Location subregister(Register reg, int offset) { + return new Location(reg, offset); + } + + /** + * Create a {@link Location} for a stack slot. + */ + public static Location stack(int offset) { + return new Location(null, offset); + } + + public boolean isRegister() { + return reg != null; + } + + public boolean isStack() { + return reg == null; + } + + @Override + public String toString() { + String regName; + if (isRegister()) { + regName = reg.name + ":"; + } else { + regName = "stack:"; + } + return regName + offset; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +/** + * Constants and intrinsic definition for memory barriers. + * + * The documentation for each constant is taken from Doug Lea's The JSR-133 Cookbook for Compiler + * Writers. + *

+ * The {@code JMM_*} constants capture the memory barriers necessary to implement the Java Memory + * Model with respect to volatile field accesses. Their values are explained by this comment from + * templateTable_i486.cpp in the HotSpot source code: + * + *

+ * Volatile variables demand their effects be made known to all CPU's in
+ * order.  Store buffers on most chips allow reads & writes to reorder; the
+ * JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of
+ * memory barrier (i.e., it's not sufficient that the interpreter does not
+ * reorder volatile references, the hardware also must not reorder them).
+ *
+ * According to the new Java Memory Model (JMM):
+ * (1) All volatiles are serialized wrt to each other.
+ * ALSO reads & writes act as acquire & release, so:
+ * (2) A read cannot let unrelated NON-volatile memory refs that happen after
+ * the read float up to before the read.  It's OK for non-volatile memory refs
+ * that happen before the volatile read to float down below it.
+ * (3) Similarly, a volatile write cannot let unrelated NON-volatile memory refs
+ * that happen BEFORE the write float down to after the write.  It's OK for
+ * non-volatile memory refs that happen after the volatile write to float up
+ * before it.
+ *
+ * We only put in barriers around volatile refs (they are expensive), not
+ * _between_ memory refs (which would require us to track the flavor of the
+ * previous memory refs).  Requirements (2) and (3) require some barriers
+ * before volatile stores and after volatile loads.  These nearly cover
+ * requirement (1) but miss the volatile-store-volatile-load case.  This final
+ * case is placed after volatile-stores although it could just as well go
+ * before volatile-loads.
+ * 
+ */ +public class MemoryBarriers { + + /** + * The sequence {@code Load1; LoadLoad; Load2} ensures that {@code Load1}'s data are loaded + * before data accessed by {@code Load2} and all subsequent load instructions are loaded. In + * general, explicit {@code LoadLoad} barriers are needed on processors that perform speculative + * loads and/or out-of-order processing in which waiting load instructions can bypass waiting + * stores. On processors that guarantee to always preserve load ordering, these barriers amount + * to no-ops. + */ + public static final int LOAD_LOAD = 0x0001; + + /** + * The sequence {@code Load1; LoadStore; Store2} ensures that {@code Load1}'s data are loaded + * before all data associated with {@code Store2} and subsequent store instructions are flushed. + * {@code LoadStore} barriers are needed only on those out-of-order processors in which waiting + * store instructions can bypass loads. + */ + public static final int LOAD_STORE = 0x0002; + + /** + * The sequence {@code Store1; StoreLoad; Load2} ensures that {@code Store1}'s data are made + * visible to other processors (i.e., flushed to main memory) before data accessed by + * {@code Load2} and all subsequent load instructions are loaded. {@code StoreLoad} barriers + * protect against a subsequent load incorrectly using {@code Store1}'s data value rather than + * that from a more recent store to the same location performed by a different processor. + * Because of this, on the processors discussed below, a {@code StoreLoad} is strictly necessary + * only for separating stores from subsequent loads of the same location(s) as were stored + * before the barrier. {@code StoreLoad} barriers are needed on nearly all recent + * multiprocessors, and are usually the most expensive kind. Part of the reason they are + * expensive is that they must disable mechanisms that ordinarily bypass cache to satisfy loads + * from write-buffers. This might be implemented by letting the buffer fully flush, among other + * possible stalls. + */ + public static final int STORE_LOAD = 0x0004; + + /** + * The sequence {@code Store1; StoreStore; Store2} ensures that {@code Store1}'s data are + * visible to other processors (i.e., flushed to memory) before the data associated with + * {@code Store2} and all subsequent store instructions. In general, {@code StoreStore} barriers + * are needed on processors that do not otherwise guarantee strict ordering of flushes from + * write buffers and/or caches to other processors or main memory. + */ + public static final int STORE_STORE = 0x0008; + + public static final int JMM_PRE_VOLATILE_WRITE = LOAD_STORE | STORE_STORE; + public static final int JMM_POST_VOLATILE_WRITE = STORE_LOAD | STORE_STORE; + public static final int JMM_PRE_VOLATILE_READ = 0; + public static final int JMM_POST_VOLATILE_READ = LOAD_LOAD | LOAD_STORE; + + public static String barriersString(int barriers) { + StringBuilder sb = new StringBuilder(); + sb.append((barriers & LOAD_LOAD) != 0 ? "LOAD_LOAD " : ""); + sb.append((barriers & LOAD_STORE) != 0 ? "LOAD_STORE " : ""); + sb.append((barriers & STORE_LOAD) != 0 ? "STORE_LOAD " : ""); + sb.append((barriers & STORE_STORE) != 0 ? "STORE_STORE " : ""); + return sb.toString().trim(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ReferenceMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ReferenceMap.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +public abstract class ReferenceMap { +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Register.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Register.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * Represents a target machine register. + */ +public final class Register implements Comparable { + + public static final RegisterCategory SPECIAL = new RegisterCategory("SPECIAL"); + + /** + * Invalid register. + */ + public static final Register None = new Register(-1, -1, "noreg", SPECIAL); + + /** + * Frame pointer of the current method. All spill slots and outgoing stack-based arguments are + * addressed relative to this register. + */ + public static final Register Frame = new Register(-2, -2, "framereg", SPECIAL); + + public static final Register CallerFrame = new Register(-3, -3, "callerframereg", SPECIAL); + + /** + * The identifier for this register that is unique across all the registers in a + * {@link Architecture}. A valid register has {@code number > 0}. + */ + public final int number; + + /** + * The mnemonic of this register. + */ + public final String name; + + /** + * The actual encoding in a target machine instruction for this register, which may or may not + * be the same as {@link #number}. + */ + public final int encoding; + + /** + * The assembler calls this method to get the register's encoding. + */ + public int encoding() { + return encoding; + } + + /** + * A platform specific register category that describes which values can be stored in a + * register. + */ + private final RegisterCategory registerCategory; + + /** + * A platform specific register type that describes which values can be stored in a register. + */ + public static class RegisterCategory { + + private final String name; + + private final int referenceMapOffset; + private final int referenceMapShift; + + public RegisterCategory(String name) { + this(name, 0, 0); + } + + public RegisterCategory(String name, int referenceMapOffset) { + this(name, referenceMapOffset, 0); + } + + public RegisterCategory(String name, int referenceMapOffset, int referenceMapShift) { + this.name = name; + this.referenceMapOffset = referenceMapOffset; + this.referenceMapShift = referenceMapShift; + } + + @Override + public String toString() { + return name; + } + + @Override + public int hashCode() { + return 23 + name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RegisterCategory) { + RegisterCategory that = (RegisterCategory) obj; + return this.referenceMapOffset == that.referenceMapOffset && this.referenceMapShift == that.referenceMapShift && this.name.equals(that.name); + } + return false; + } + } + + /** + * Creates a {@link Register} instance. + * + * @param number unique identifier for the register + * @param encoding the target machine encoding for the register + * @param name the mnemonic name for the register + * @param registerCategory the register category + */ + public Register(int number, int encoding, String name, RegisterCategory registerCategory) { + this.number = number; + this.name = name; + this.registerCategory = registerCategory; + this.encoding = encoding; + } + + public RegisterCategory getRegisterCategory() { + return registerCategory; + } + + /** + * Get the start index of this register in the {@link ReferenceMap}. + */ + public int getReferenceMapIndex() { + return (encoding << registerCategory.referenceMapShift) + registerCategory.referenceMapOffset; + } + + /** + * Gets this register as a {@linkplain RegisterValue value} with a specified kind. + * + * @param kind the specified kind + * @return the {@link RegisterValue} + */ + public RegisterValue asValue(LIRKind kind) { + return new RegisterValue(kind, this); + } + + /** + * Gets this register as a {@linkplain RegisterValue value} with no particular kind. + * + * @return a {@link RegisterValue} with {@link JavaKind#Illegal} kind. + */ + public RegisterValue asValue() { + return asValue(LIRKind.Illegal); + } + + /** + * Determines if this is a valid register. + * + * @return {@code true} iff this register is valid + */ + public boolean isValid() { + return number >= 0; + } + + /** + * Gets the maximum register {@linkplain #number number} in a given set of registers. + * + * @param registers the set of registers to process + * @return the maximum register number for any register in {@code registers} + */ + public static int maxRegisterNumber(Register[] registers) { + int max = Integer.MIN_VALUE; + for (Register r : registers) { + if (r.number > max) { + max = r.number; + } + } + return max; + } + + /** + * Gets the maximum register {@linkplain #encoding encoding} in a given set of registers. + * + * @param registers the set of registers to process + * @return the maximum register encoding for any register in {@code registers} + */ + public static int maxRegisterEncoding(Register[] registers) { + int max = Integer.MIN_VALUE; + for (Register r : registers) { + if (r.encoding > max) { + max = r.encoding; + } + } + return max; + } + + @Override + public String toString() { + return name; + } + + @Override + public int compareTo(Register o) { + if (number < o.number) { + return -1; + } + if (number > o.number) { + return 1; + } + return 0; + } + + @Override + public int hashCode() { + return 17 + name.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Register) { + Register other = (Register) obj; + if (number == other.number) { + assert name.equals(other.name); + assert encoding == other.encoding; + assert registerCategory.equals(other.registerCategory); + return true; + } + } + return false; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterAttributes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterAttributes.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.util.*; + +/** + * A collection of register attributes. The specific attribute values for a register may be local to + * a compilation context. For example, a {@link RegisterConfig} in use during a compilation will + * determine which registers are callee saved. + */ +public class RegisterAttributes { + + private final boolean callerSave; + private final boolean calleeSave; + private final boolean allocatable; + + public RegisterAttributes(boolean isCallerSave, boolean isCalleeSave, boolean isAllocatable) { + this.callerSave = isCallerSave; + this.calleeSave = isCalleeSave; + this.allocatable = isAllocatable; + } + + public static final RegisterAttributes NONE = new RegisterAttributes(false, false, false); + + /** + * Creates a map from register {@linkplain Register#number numbers} to register + * {@linkplain RegisterAttributes attributes} for a given register configuration and set of + * registers. + * + * @param registerConfig a register configuration + * @param registers a set of registers + * @return an array whose length is the max register number in {@code registers} plus 1. An + * element at index i holds the attributes of the register whose number is i. + */ + public static RegisterAttributes[] createMap(RegisterConfig registerConfig, Register[] registers) { + RegisterAttributes[] map = new RegisterAttributes[registers.length]; + for (Register reg : registers) { + if (reg != null) { + Register[] csr = registerConfig.getCalleeSaveRegisters(); + RegisterAttributes attr = new RegisterAttributes(Arrays.asList(registerConfig.getCallerSaveRegisters()).contains(reg), csr == null ? false : Arrays.asList(csr).contains(reg), + Arrays.asList(registerConfig.getAllocatableRegisters()).contains(reg)); + if (map.length <= reg.number) { + map = Arrays.copyOf(map, reg.number + 1); + } + map[reg.number] = attr; + } + } + for (int i = 0; i < map.length; i++) { + if (map[i] == null) { + map[i] = NONE; + } + } + return map; + } + + /** + * @return Denotes a register that is available for use by a register allocator. + */ + public boolean isAllocatable() { + return allocatable; + } + + /** + * @return Denotes a register whose value preservation (if required) across a call is the + * responsibility of the callee. + */ + public boolean isCalleeSave() { + return calleeSave; + } + + /** + * @return Denotes a register whose value preservation (if required) across a call is the + * responsibility of the caller. + */ + public boolean isCallerSave() { + return callerSave; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterConfig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterConfig.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import jdk.vm.ci.code.CallingConvention.*; +import jdk.vm.ci.meta.*; + +/** + * A register configuration binds roles and {@linkplain RegisterAttributes attributes} to physical + * registers. + */ +public interface RegisterConfig { + + /** + * Gets the register to be used for returning a value of a given kind. + */ + Register getReturnRegister(JavaKind kind); + + /** + * Gets the maximum allowed size of the frame. + */ + default int getMaximumFrameSize() { + return Integer.MAX_VALUE; + } + + /** + * Gets the register to which {@link Register#Frame} and {@link Register#CallerFrame} are bound. + */ + Register getFrameRegister(); + + /** + * Gets the calling convention describing how arguments are passed. + * + * @param type the type of calling convention being requested + * @param returnType the return type (can be null for methods returning {@code void}) + * @param parameterTypes the types of the arguments of the call + * @param target the target platform + * @param stackOnly ignore registers + */ + CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly); + + /** + * Gets the ordered set of registers that are can be used to pass parameters according to a + * given calling convention. + * + * @param type the type of calling convention + * @param kind specifies what kind of registers is being requested + * @return the ordered set of registers that may be used to pass parameters in a call conforming + * to {@code type} + */ + Register[] getCallingConventionRegisters(Type type, JavaKind kind); + + /** + * Gets the set of all registers that might be used by the register allocator. + * + * To get the set of registers the register allocator is allowed to use see + * {@link RegisterAllocationConfig#getAllocatableRegisters()} + */ + @SuppressWarnings("javadoc") + Register[] getAllocatableRegisters(); + + /** + * Filters a set of registers and returns only those that can be used by the register allocator + * for a value of a particular kind. + */ + Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers); + + /** + * Gets the registers whose values must be preserved by a method across any call it makes. + */ + Register[] getCallerSaveRegisters(); + + /** + * Gets the registers whose values must be preserved by the callee. + */ + Register[] getCalleeSaveRegisters(); + + /** + * Gets a map from register {@linkplain Register#number numbers} to register + * {@linkplain RegisterAttributes attributes} for this register configuration. + * + * @return an array where an element at index i holds the attributes of the register whose + * number is i + */ + RegisterAttributes[] getAttributesMap(); + + /** + * Gets the register corresponding to a runtime-defined role. + * + * @param id the identifier of a runtime-defined register role + * @return the register playing the role specified by {@code id} + */ + Register getRegisterForRole(int id); + + /** + * Determines if all {@link #getAllocatableRegisters() allocatable} registers are + * {@link #getCallerSaveRegisters() caller saved}. + */ + boolean areAllAllocatableRegistersCallerSaved(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterSaveLayout.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterSaveLayout.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import java.util.*; + +/** + * A map from registers to frame slots. This can be used to describe where callee saved registers + * are saved in a callee's frame. + */ +public final class RegisterSaveLayout { + + /** + * Keys. + */ + private final Register[] registers; + + /** + * Slot indexes relative to stack pointer. + */ + private final int[] slots; + + /** + * Creates a map from registers to frame slots. + * + * @param registers the keys in the map + * @param slots frame slot index for each register in {@code registers} + */ + public RegisterSaveLayout(Register[] registers, int[] slots) { + assert registers.length == slots.length; + this.registers = registers; + this.slots = slots; + assert registersToSlots(false).size() == registers.length : "non-unique registers"; + assert new HashSet<>(registersToSlots(false).values()).size() == slots.length : "non-unqiue slots"; + } + + /** + * Gets the frame slot index for a given register. + * + * @param register register to get the frame slot index for + * @return frame slot index + */ + public int registerToSlot(Register register) { + for (int i = 0; i < registers.length; i++) { + if (register.equals(registers[i])) { + return slots[i]; + } + } + throw new IllegalArgumentException(register + " not saved by this layout: " + this); + } + + /** + * Gets this layout information as a {@link Map} from registers to slots. + */ + public Map registersToSlots(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(registers[i], slots[i]); + } + return result; + } + + /** + * Gets this layout information as a {@link Map} from slots to registers. + */ + public Map slotsToRegisters(boolean sorted) { + Map result; + if (sorted) { + result = new TreeMap<>(); + } else { + result = new HashMap<>(); + } + for (int i = 0; i < registers.length; i++) { + result.put(slots[i], registers[i]); + } + return result; + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof RegisterSaveLayout) { + RegisterSaveLayout that = (RegisterSaveLayout) obj; + if (Arrays.equals(registers, that.registers) && Arrays.equals(slots, that.slots)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return registersToSlots(true).toString(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * Denotes a register that stores a value of a fixed kind. There is exactly one (canonical) instance + * of {@link RegisterValue} for each ({@link Register}, {@link JavaKind}) pair. Use + * {@link Register#asValue(LIRKind)} to retrieve the canonical {@link RegisterValue} instance for a + * given (register,kind) pair. + */ +public final class RegisterValue extends AllocatableValue { + + private final Register reg; + + /** + * Should only be called from {@link Register#Register} to ensure canonicalization. + */ + protected RegisterValue(LIRKind kind, Register register) { + super(kind); + this.reg = register; + } + + @Override + public String toString() { + return getRegister().name + getKindSuffix(); + } + + /** + * @return the register that contains the value + */ + public Register getRegister() { + return reg; + } + + @Override + public int hashCode() { + return 29 * super.hashCode() + reg.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RegisterValue) { + RegisterValue other = (RegisterValue) obj; + return super.equals(obj) && reg.equals(other.reg); + } + return false; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/SourceStackTrace.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/SourceStackTrace.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +/** + * Class representing a exception with a stack trace of the currently processed position in the + * compiled Java program instead of the stack trace of the compiler. The exception of the compiler + * is saved as the cause of this exception. + */ +public abstract class SourceStackTrace extends BailoutException { + private static final long serialVersionUID = 2144811793442316776L; + + public static SourceStackTrace create(Throwable cause, String format, StackTraceElement[] elements) { + return new SourceStackTrace(cause, format) { + + private static final long serialVersionUID = 6279381376051787907L; + + @Override + public final synchronized Throwable fillInStackTrace() { + assert elements != null; + setStackTrace(elements); + return this; + } + }; + } + + private SourceStackTrace(Throwable cause, String format) { + super(cause, format); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackLockValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackLockValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import static jdk.vm.ci.code.ValueUtil.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents lock information in the debug information. + */ +public final class StackLockValue implements JavaValue { + + private JavaValue owner; + private StackSlotValue slot; + private final boolean eliminated; + + public StackLockValue(JavaValue object, StackSlotValue slot, boolean eliminated) { + this.owner = object; + this.slot = slot; + this.eliminated = eliminated; + } + + public JavaValue getOwner() { + return owner; + } + + public void setOwner(JavaValue newOwner) { + this.owner = newOwner; + } + + public Value getSlot() { + return slot; + } + + public boolean isEliminated() { + return eliminated; + } + + @Override + public String toString() { + return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]"; + } + + @Override + public int hashCode() { + final int prime = 43; + int result = super.hashCode(); + result = prime * result + (eliminated ? 1231 : 1237); + result = prime * result + owner.hashCode(); + result = prime * result + slot.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof StackLockValue) { + StackLockValue other = (StackLockValue) obj; + return super.equals(obj) && eliminated == other.eliminated && owner.equals(other.owner) && slot.equals(other.slot); + } + return false; + } + + public void setSlot(StackSlotValue stackSlot) { + assert slot == null || (isVirtualStackSlot(slot) && (slot.equals(stackSlot) || isStackSlot(stackSlot))) : String.format("Can not set slot for %s to %s", this, stackSlot); + slot = stackSlot; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlot.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlot.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * Represents a compiler spill slot or an outgoing stack-based argument in a method's frame or an + * incoming stack-based argument in a method's {@linkplain #isInCallerFrame() caller's frame}. + */ +public final class StackSlot extends StackSlotValue { + + private final int offset; + private final boolean addFrameSize; + + /** + * Gets a {@link StackSlot} instance representing a stack slot at a given index holding a value + * of a given kind. + * + * @param kind The kind of the value stored in the stack slot. + * @param offset The offset of the stack slot (in bytes) + * @param addFrameSize Specifies if the offset is relative to the stack pointer, or the + * beginning of the frame (stack pointer + total frame size). + */ + public static StackSlot get(LIRKind kind, int offset, boolean addFrameSize) { + assert addFrameSize || offset >= 0; + return new StackSlot(kind, offset, addFrameSize); + } + + /** + * Private constructor to enforce use of {@link #get(LIRKind, int, boolean)} so that a cache can + * be used. + */ + private StackSlot(LIRKind kind, int offset, boolean addFrameSize) { + super(kind); + this.offset = offset; + this.addFrameSize = addFrameSize; + } + + /** + * Gets the offset of this stack slot, relative to the stack pointer. + * + * @return The offset of this slot (in bytes). + */ + public int getOffset(int totalFrameSize) { + assert totalFrameSize > 0 || !addFrameSize; + int result = offset + (addFrameSize ? totalFrameSize : 0); + assert result >= 0; + return result; + } + + public boolean isInCallerFrame() { + return addFrameSize && offset >= 0; + } + + public int getRawOffset() { + return offset; + } + + public boolean getRawAddFrameSize() { + return addFrameSize; + } + + @Override + public String toString() { + if (!addFrameSize) { + return "out:" + offset + getKindSuffix(); + } else if (offset >= 0) { + return "in:" + offset + getKindSuffix(); + } else { + return "stack:" + (-offset) + getKindSuffix(); + } + } + + /** + * Gets this stack slot used to pass an argument from the perspective of a caller. + */ + public StackSlot asOutArg() { + assert offset >= 0; + if (addFrameSize) { + return get(getLIRKind(), offset, false); + } + return this; + } + + /** + * Gets this stack slot used to pass an argument from the perspective of a callee. + */ + public StackSlot asInArg() { + assert offset >= 0; + if (!addFrameSize) { + return get(getLIRKind(), offset, true); + } + return this; + } + + @Override + public int hashCode() { + final int prime = 37; + int result = super.hashCode(); + result = prime * result + (addFrameSize ? 1231 : 1237); + result = prime * result + offset; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof StackSlot) { + StackSlot other = (StackSlot) obj; + return super.equals(obj) && addFrameSize == other.addFrameSize && offset == other.offset; + } + return false; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlotValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlotValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * Common base class for {@linkplain StackSlot real} and {@linkplain VirtualStackSlot virtual} stack + * slots. + */ +public abstract class StackSlotValue extends AllocatableValue { + + public StackSlotValue(LIRKind lirKind) { + super(lirKind); + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/TargetDescription.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/TargetDescription.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import static jdk.vm.ci.meta.MetaUtil.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents the target machine for a compiler, including the CPU architecture, the size of + * pointers and references, alignment of stacks, caches, etc. + */ +public class TargetDescription { + + public final Architecture arch; + + /** + * Specifies if this is a multi-processor system. + */ + public final boolean isMP; + + /** + * Specifies if this target supports encoding objects inline in the machine code. + */ + public final boolean inlineObjects; + + /** + * The machine word size on this target. + */ + public final int wordSize; + + /** + * The kind to be used for representing raw pointers and CPU registers. + */ + public final JavaKind wordKind; + + /** + * The stack alignment requirement of the platform. For example, from Appendix D of Intel 64 and IA-32 Architectures + * Optimization Reference Manual: + * + *
+     *     "It is important to ensure that the stack frame is aligned to a
+     *      16-byte boundary upon function entry to keep local __m128 data,
+     *      parameters, and XMM register spill locations aligned throughout
+     *      a function invocation."
+     * 
+ */ + public final int stackAlignment; + + /** + * Maximum constant displacement at which a memory access can no longer be an implicit null + * check. + */ + public final int implicitNullCheckLimit; + + public TargetDescription(Architecture arch, boolean isMP, int stackAlignment, int implicitNullCheckLimit, boolean inlineObjects) { + this.arch = arch; + this.isMP = isMP; + this.wordSize = arch.getWordSize(); + this.wordKind = JavaKind.fromWordSize(wordSize); + this.stackAlignment = stackAlignment; + this.implicitNullCheckLimit = implicitNullCheckLimit; + this.inlineObjects = inlineObjects; + } + + @Override + public final int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public final boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TargetDescription) { + TargetDescription that = (TargetDescription) obj; + // @formatter:off + if (this.implicitNullCheckLimit == that.implicitNullCheckLimit && + this.inlineObjects == that.inlineObjects && + this.isMP == that.isMP && + this.stackAlignment == that.stackAlignment && + this.wordKind.equals(that.wordKind) && + this.wordSize == that.wordSize && + this.arch.equals(that.arch)) { + return true; + } + // @formatter:on + } + return false; + } + + @Override + public String toString() { + return identityHashCodeString(this); + } + + public int getSizeInBytes(PlatformKind kind) { + return kind.getSizeInBytes(); + } + + public LIRKind getLIRKind(JavaKind javaKind) { + PlatformKind platformKind = arch.getPlatformKind(javaKind); + if (javaKind.isObject()) { + return LIRKind.reference(platformKind); + } else { + return LIRKind.value(platformKind); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/UnsignedMath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/UnsignedMath.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.code; + +import java.math.*; + +//JaCoCo Exclude + +/** + * Utilities for unsigned comparisons. All methods have correct, but slow, standard Java + * implementations so that they can be used with compilers not supporting the intrinsics. + */ +public class UnsignedMath { + + private static final long MASK = 0xffffffffL; + + /** + * Unsigned comparison aboveThan for two numbers. + */ + public static boolean aboveThan(int a, int b) { + return (a & MASK) > (b & MASK); + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + public static boolean aboveOrEqual(int a, int b) { + return (a & MASK) >= (b & MASK); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + public static boolean belowThan(int a, int b) { + return (a & MASK) < (b & MASK); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + public static boolean belowOrEqual(int a, int b) { + return (a & MASK) <= (b & MASK); + } + + /** + * Unsigned comparison aboveThan for two numbers. + */ + public static boolean aboveThan(long a, long b) { + return (a > b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned comparison aboveOrEqual for two numbers. + */ + public static boolean aboveOrEqual(long a, long b) { + return (a >= b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned comparison belowThan for two numbers. + */ + public static boolean belowThan(long a, long b) { + return (a < b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned comparison belowOrEqual for two numbers. + */ + public static boolean belowOrEqual(long a, long b) { + return (a <= b) ^ ((a < 0) != (b < 0)); + } + + /** + * Unsigned division for two numbers. + */ + public static int divide(int a, int b) { + return (int) ((a & MASK) / (b & MASK)); + } + + /** + * Unsigned remainder for two numbers. + */ + public static int remainder(int a, int b) { + return (int) ((a & MASK) % (b & MASK)); + } + + /** + * Unsigned division for two numbers. + */ + public static long divide(long a, long b) { + return bi(a).divide(bi(b)).longValue(); + } + + /** + * Unsigned remainder for two numbers. + */ + public static long remainder(long a, long b) { + return bi(a).remainder(bi(b)).longValue(); + } + + private static BigInteger bi(long unsigned) { + return unsigned >= 0 ? BigInteger.valueOf(unsigned) : BigInteger.valueOf(unsigned & 0x7fffffffffffffffL).setBit(63); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ValueUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ValueUtil.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Utility class for working with the {@link Value} class and its subclasses. + */ +public final class ValueUtil { + + public static boolean isIllegal(Value value) { + assert value != null; + return Value.ILLEGAL.equals(value); + } + + public static boolean isIllegalJavaValue(JavaValue value) { + assert value != null; + return Value.ILLEGAL.equals(value); + } + + public static boolean isLegal(Value value) { + return !isIllegal(value); + } + + public static boolean isVirtualObject(JavaValue value) { + assert value != null; + return value instanceof VirtualObject; + } + + public static VirtualObject asVirtualObject(JavaValue value) { + assert value != null; + return (VirtualObject) value; + } + + public static boolean isConstantJavaValue(JavaValue value) { + assert value != null; + return value instanceof JavaConstant; + } + + public static boolean isAllocatableValue(Value value) { + assert value != null; + return value instanceof AllocatableValue; + } + + public static AllocatableValue asAllocatableValue(Value value) { + assert value != null; + return (AllocatableValue) value; + } + + public static boolean isStackSlot(Value value) { + assert value != null; + return value instanceof StackSlot; + } + + public static StackSlot asStackSlot(Value value) { + assert value != null; + return (StackSlot) value; + } + + public static boolean isStackSlotValue(Value value) { + assert value != null; + return value instanceof StackSlotValue; + } + + public static StackSlotValue asStackSlotValue(Value value) { + assert value != null; + return (StackSlotValue) value; + } + + public static boolean isVirtualStackSlot(Value value) { + assert value != null; + return value instanceof VirtualStackSlot; + } + + public static VirtualStackSlot asVirtualStackSlot(Value value) { + assert value != null; + return (VirtualStackSlot) value; + } + + public static boolean isRegister(Value value) { + assert value != null; + return value instanceof RegisterValue; + } + + public static Register asRegister(Value value) { + return asRegisterValue(value).getRegister(); + } + + public static RegisterValue asRegisterValue(Value value) { + assert value != null; + return (RegisterValue) value; + } + + public static Register asRegister(Value value, PlatformKind kind) { + if (value.getPlatformKind() != kind) { + throw new InternalError("needed: " + kind + " got: " + value.getPlatformKind()); + } else { + return asRegister(value); + } + } + + public static boolean sameRegister(Value v1, Value v2) { + return isRegister(v1) && isRegister(v2) && asRegister(v1).equals(asRegister(v2)); + } + + public static boolean sameRegister(Value v1, Value v2, Value v3) { + return sameRegister(v1, v2) && sameRegister(v1, v3); + } + + /** + * Checks if all the provided values are different physical registers. The parameters can be + * either {@link Register registers}, {@link Value values} or arrays of them. All values that + * are not {@link RegisterValue registers} are ignored. + */ + public static boolean differentRegisters(Object... values) { + List registers = collectRegisters(values, new ArrayList()); + for (int i = 1; i < registers.size(); i++) { + Register r1 = registers.get(i); + for (int j = 0; j < i; j++) { + Register r2 = registers.get(j); + if (r1.equals(r2)) { + return false; + } + } + } + return true; + } + + private static List collectRegisters(Object[] values, List registers) { + for (Object o : values) { + if (o instanceof Register) { + registers.add((Register) o); + } else if (o instanceof Value) { + if (isRegister((Value) o)) { + registers.add(asRegister((Value) o)); + } + } else if (o instanceof Object[]) { + collectRegisters((Object[]) o, registers); + } else { + throw new IllegalArgumentException("Not a Register or Value: " + o); + } + } + return registers; + } + + /** + * Subtract sets of registers (x - y). + * + * @param x a set of register to subtract from. + * @param y a set of registers to subtract. + * @return resulting set of registers (x - y). + */ + public static Value[] subtractRegisters(Value[] x, Value[] y) { + ArrayList result = new ArrayList<>(x.length); + for (Value i : x) { + boolean append = true; + for (Value j : y) { + if (ValueUtil.sameRegister(i, j)) { + append = false; + break; + } + } + if (append) { + result.add(i); + } + } + Value[] resultArray = new Value[result.size()]; + return result.toArray(resultArray); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * An instance of this class represents an object whose allocation was removed by escape analysis. + * The information stored in the {@link VirtualObject} is used during deoptimization to recreate the + * object. + */ +public final class VirtualObject implements JavaValue { + + private final ResolvedJavaType type; + private JavaValue[] values; + private JavaKind[] slotKinds; + private final int id; + + /** + * Creates a new {@link VirtualObject} for the given type, with the given fields. If + * {@code type} is an instance class then {@code values} provides the values for the fields + * returned by {@link ResolvedJavaType#getInstanceFields(boolean) getInstanceFields(true)}. If + * {@code type} is an array then the length of the values array determines the reallocated array + * length. + * + * @param type the type of the object whose allocation was removed during compilation. This can + * be either an instance of an array type. + * @param id a unique id that identifies the object within the debug information for one + * position in the compiled code. + * @return a new {@link VirtualObject} instance. + */ + public static VirtualObject get(ResolvedJavaType type, int id) { + return new VirtualObject(type, id); + } + + private VirtualObject(ResolvedJavaType type, int id) { + this.type = type; + this.id = id; + } + + private static StringBuilder appendValue(StringBuilder buf, JavaValue value, Set visited) { + if (value instanceof VirtualObject) { + VirtualObject vo = (VirtualObject) value; + buf.append("vobject:").append(vo.type.toJavaName(false)).append(':').append(vo.id); + if (!visited.contains(vo)) { + visited.add(vo); + buf.append('{'); + if (vo.values == null) { + buf.append(""); + } else { + if (vo.type.isArray()) { + for (int i = 0; i < vo.values.length; i++) { + if (i != 0) { + buf.append(','); + } + buf.append(i).append('='); + appendValue(buf, vo.values[i], visited); + } + } else { + ResolvedJavaField[] fields = vo.type.getInstanceFields(true); + assert fields.length == vo.values.length : vo.type + ", fields=" + Arrays.toString(fields) + ", values=" + Arrays.toString(vo.values); + for (int i = 0; i < vo.values.length; i++) { + if (i != 0) { + buf.append(','); + } + buf.append(fields[i].getName()).append('='); + appendValue(buf, vo.values[i], visited); + } + } + } + buf.append('}'); + } + } else { + buf.append(value); + } + return buf; + } + + @Override + public String toString() { + Set visited = Collections.newSetFromMap(new IdentityHashMap()); + return appendValue(new StringBuilder(), this, visited).toString(); + } + + /** + * Returns the type of the object whose allocation was removed during compilation. This can be + * either an instance of an array type. + */ + public ResolvedJavaType getType() { + return type; + } + + /** + * Returns an array containing all the values to be stored into the object when it is recreated. + */ + public JavaValue[] getValues() { + return values; + } + + /** + * Returns an array containing the Java kind of all values in the object. + */ + public JavaKind[] getSlotKinds() { + return slotKinds; + } + + /** + * Returns the unique id that identifies the object within the debug information for one + * position in the compiled code. + */ + public int getId() { + return id; + } + + private boolean checkValues() { + assert (values == null) == (slotKinds == null); + if (values != null) { + assert values.length == slotKinds.length; + if (!type.isArray()) { + ResolvedJavaField[] fields = type.getInstanceFields(true); + int fieldIndex = 0; + for (int i = 0; i < values.length; i++) { + ResolvedJavaField field = fields[fieldIndex++]; + JavaKind valKind = slotKinds[i].getStackKind(); + if (field.getJavaKind() == JavaKind.Object) { + assert valKind.isObject() : field + ": " + valKind + " != " + field.getJavaKind(); + } else { + if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && field.getJavaKind() == JavaKind.Int) { + assert fields[fieldIndex].getJavaKind() == JavaKind.Int; + fieldIndex++; + } else { + assert valKind == field.getJavaKind().getStackKind() : field + ": " + valKind + " != " + field.getJavaKind(); + } + } + } + assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values); + } else { + JavaKind componentKind = type.getComponentType().getJavaKind().getStackKind(); + if (componentKind == JavaKind.Object) { + for (int i = 0; i < values.length; i++) { + assert slotKinds[i].isObject() : slotKinds[i] + " != " + componentKind; + } + } else { + for (int i = 0; i < values.length; i++) { + assert slotKinds[i] == componentKind || componentKind.getBitCount() >= slotKinds[i].getBitCount() || + (componentKind == JavaKind.Int && slotKinds[i].getBitCount() >= JavaKind.Int.getBitCount()) : slotKinds[i] + " != " + componentKind; + } + } + } + } + return true; + } + + /** + * Overwrites the current set of values with a new one. + * + * @param values an array containing all the values to be stored into the object when it is + * recreated. + * @param slotKinds an array containing the Java kinds of the values. + */ + public void setValues(JavaValue[] values, JavaKind[] slotKinds) { + this.values = values; + this.slotKinds = slotKinds; + assert checkValues(); + } + + @Override + public int hashCode() { + return 42 + type.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof VirtualObject) { + VirtualObject l = (VirtualObject) o; + if (!l.type.equals(type) || l.values.length != values.length) { + return false; + } + for (int i = 0; i < values.length; i++) { + /* + * Virtual objects can form cycles. Calling equals() could therefore lead to + * infinite recursion. + */ + if (!same(values[i], l.values[i])) { + return false; + } + } + return true; + } + return false; + } + + private static boolean same(Object o1, Object o2) { + return o1 == o2; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualStackSlot.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualStackSlot.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code; + +import jdk.vm.ci.meta.*; + +/** + * {@link VirtualStackSlot}s are stack slots that are not yet fixed to specific frame offset. They + * are replaced by real {@link StackSlot}s with a fixed position in the frame before code emission. + */ +public abstract class VirtualStackSlot extends StackSlotValue { + + private final int id; + + public VirtualStackSlot(int id, LIRKind lirKind) { + super(lirKind); + this.id = id; + } + + public int getId() { + return id; + } + + @Override + public String toString() { + return "vstack:" + id + getKindSuffix(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + id; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + VirtualStackSlot other = (VirtualStackSlot) obj; + if (id != other.id) { + return false; + } + return true; + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/package-info.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. DO NOT ALTER OR + * REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it under the terms of the GNU + * General Public License version 2 only, as published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version 2 along with this work; + * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA or visit www.oracle.com + * if you need additional information or have any questions. + */ +/** + * Package that defines the interface between a Java application that wants to install code and the + * runtime. The runtime provides in implementation of the {@link jdk.vm.ci.code.CodeCacheProvider} + * interface. The method + * {@link jdk.vm.ci.code.CodeCacheProvider#addMethod(jdk.vm.ci.meta.ResolvedJavaMethod, CompilationResult, jdk.vm.ci.meta.SpeculationLog, InstalledCode)} + * can be used to install code for a given method. + */ +package jdk.vm.ci.code; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrame.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code.stack; + +import jdk.vm.ci.meta.*; + +public interface InspectedFrame { + + /** + * Returns the value of the local at the given index. Currently only works for object values. + * This value is a copy iff {@link #isVirtual(int)} is true. + */ + Object getLocal(int index); + + /** + * Returns whether the local at the given index is a virtual object, and therefore the object + * returned by {@link #getLocal(int)} is a copy. + */ + boolean isVirtual(int index); + + /** + * Returns true if the stack frame is a compiled stack frame and there are virtual objects + * anywhere in the current state of the compiled method. This can return true even if + * {@link #isVirtual(int)} return false for all locals. + */ + boolean hasVirtualObjects(); + + /** + * This method will materialize all virtual objects, deoptimize the stack frame and make sure + * that subsequent execution of the deoptimized frame uses the materialized values. + */ + void materializeVirtualObjects(boolean invalidateCode); + + /** + * @return the current bytecode index + */ + int getBytecodeIndex(); + + /** + * @return the current method + */ + ResolvedJavaMethod getMethod(); + + /** + * Checks if the current method is equal to the given method. This is semantically equivalent to + * {@code method.equals(getMethod())}, but can be implemented more efficiently. + */ + boolean isMethod(ResolvedJavaMethod method); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrameVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrameVisitor.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code.stack; + +/** + * Callback interface for {@link StackIntrospection#iterateFrames}. Implementations of + * {@link #visitFrame} return null to indicate that frame iteration should continue and the next + * caller frame should be visited; and return any non-null value to indicate that frame iteration + * should stop. + */ +public interface InspectedFrameVisitor { + + T visitFrame(InspectedFrame frame); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/StackIntrospection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/StackIntrospection.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.code.stack; + +import jdk.vm.ci.meta.*; + +public interface StackIntrospection { + + /** + * Accesses the current stack, providing {@link InspectedFrame}s to the visitor that can be used + * to inspect the stack frames' contents. Iteration continues as long as + * {@link InspectedFrameVisitor#visitFrame}, which is invoked for every {@link InspectedFrame}, + * returns null. Any non-null result of the visitor indicates that frame iteration should stop. + * + * @param initialMethods if this is non-{@code null}, then the stack trace will start at these + * methods + * @param matchingMethods if this is non-{@code null}, then only matching stack frames are + * returned + * @param initialSkip the number of matching methods to skip (including the initial method) + * @param visitor the visitor that is called for every matching method + * @return the last result returned by the visitor (which is non-null to indicate that iteration + * should stop), or null if the whole stack was iterated. + */ + T iterateFrames(ResolvedJavaMethod[] initialMethods, ResolvedJavaMethod[] matchingMethods, int initialSkip, InspectedFrameVisitor visitor); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/JVMCIError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/JVMCIError.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.common; + +import java.util.*; + +/** + * Indicates a condition in JVMCI related code that should never occur during normal operation. + */ +public class JVMCIError extends Error { + + private static final long serialVersionUID = 531632331813456233L; + private final ArrayList context = new ArrayList<>(); + + public static RuntimeException unimplemented() { + throw new JVMCIError("unimplemented"); + } + + public static RuntimeException unimplemented(String msg) { + throw new JVMCIError("unimplemented: %s", msg); + } + + public static RuntimeException shouldNotReachHere() { + throw new JVMCIError("should not reach here"); + } + + public static RuntimeException shouldNotReachHere(String msg) { + throw new JVMCIError("should not reach here: %s", msg); + } + + public static RuntimeException shouldNotReachHere(Throwable cause) { + throw new JVMCIError(cause); + } + + /** + * Checks a given condition and throws a {@link JVMCIError} if it is false. Guarantees are + * stronger than assertions in that they are always checked. Error messages for guarantee + * violations should clearly indicate the nature of the problem as well as a suggested solution + * if possible. + * + * @param condition the condition to check + * @param msg the message that will be associated with the error, in + * {@link String#format(String, Object...)} syntax + * @param args arguments to the format string + */ + public static void guarantee(boolean condition, String msg, Object... args) { + if (!condition) { + throw new JVMCIError("failed guarantee: " + msg, args); + } + } + + /** + * This constructor creates a {@link JVMCIError} with a given message. + * + * @param msg the message that will be associated with the error + */ + public JVMCIError(String msg) { + super(msg); + } + + /** + * This constructor creates a {@link JVMCIError} with a message assembled via + * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to + * always generate the same output. + * + * @param msg the message that will be associated with the error, in String.format syntax + * @param args parameters to String.format - parameters that implement {@link Iterable} will be + * expanded into a [x, x, ...] representation. + */ + public JVMCIError(String msg, Object... args) { + super(format(msg, args)); + } + + /** + * This constructor creates a {@link JVMCIError} for a given causing Throwable instance. + * + * @param cause the original exception that contains additional information on this error + */ + public JVMCIError(Throwable cause) { + super(cause); + } + + /** + * This constructor creates a {@link JVMCIError} and adds all the + * {@linkplain #addContext(String) context} of another {@link JVMCIError}. + * + * @param e the original {@link JVMCIError} + */ + public JVMCIError(JVMCIError e) { + super(e); + context.addAll(e.context); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append(super.toString()); + for (String s : context) { + str.append("\n\tat ").append(s); + } + return str.toString(); + } + + private static String format(String msg, Object... args) { + if (args != null) { + // expand Iterable parameters into a list representation + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof Iterable) { + ArrayList list = new ArrayList<>(); + for (Object o : (Iterable) args[i]) { + list.add(o); + } + args[i] = list.toString(); + } + } + } + return String.format(Locale.ENGLISH, msg, args); + } + + public JVMCIError addContext(String newContext) { + this.context.add(newContext); + return this; + } + + public JVMCIError addContext(String name, Object obj) { + return addContext(format("%s: %s", name, obj)); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/UnsafeUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/UnsafeUtil.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.common; + +import sun.misc.Unsafe; + +/** + * Utilities for operating on raw memory with {@link Unsafe}. + */ +public class UnsafeUtil { + + /** + * Copies the contents of a {@link String} to a native memory buffer as a {@code '\0'} + * terminated C string. The native memory buffer is allocated via + * {@link Unsafe#allocateMemory(long)}. The caller is responsible for releasing the buffer when + * it is no longer needed via {@link Unsafe#freeMemory(long)}. + * + * @return the native memory pointer of the C string created from {@code s} + */ + public static long createCString(Unsafe unsafe, String s) { + return writeCString(unsafe, s, unsafe.allocateMemory(s.length() + 1)); + } + + /** + * Reads a {@code '\0'} terminated C string from native memory and converts it to a + * {@link String}. + * + * @return a Java string + */ + public static String readCString(Unsafe unsafe, long address) { + if (address == 0) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0;; i++) { + char c = (char) unsafe.getByte(address + i); + if (c == 0) { + break; + } + sb.append(c); + } + return sb.toString(); + } + + /** + * Writes the contents of a {@link String} to a native memory buffer as a {@code '\0'} + * terminated C string. The caller is responsible for ensuring the buffer is at least + * {@code s.length() + 1} bytes long. The caller is also responsible for releasing the buffer + * when it is no longer. + * + * @return the value of {@code buf} + */ + public static long writeCString(Unsafe unsafe, String s, long buf) { + int size = s.length(); + for (int i = 0; i < size; i++) { + unsafe.putByte(buf + i, (byte) s.charAt(i)); + } + unsafe.putByte(buf + size, (byte) '\0'); + return buf; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/Compiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/Compiler.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.compiler; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.options.*; + +public interface Compiler { + int INVOCATION_ENTRY_BCI = -1; + + @Option(help = "", type = OptionType.Debug) OptionValue PrintFilter = new OptionValue<>(null); + @Option(help = "", type = OptionType.Debug) OptionValue PrintCompilation = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue PrintAfterCompilation = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue PrintBailout = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue ExitVMOnBailout = new OptionValue<>(false); + @Option(help = "", type = OptionType.Debug) OptionValue ExitVMOnException = new OptionValue<>(true); + @Option(help = "", type = OptionType.Debug) OptionValue PrintStackTraceOnException = new OptionValue<>(false); + + /** + * Request the compilation of a method by this JVMCI compiler. The compiler should compile the + * method to machine code and install it in the code cache if the compilation is successful. + * + * @param method the method that should be compiled + * @param entryBCI the BCI at which to start compiling where -1 denotes a non-OSR compilation + * request and all other values denote an OSR compilation request + * @param jvmciEnv pointer to native {@code JVMCIEnv} object + * @param id a unique identifier for this compilation + */ + void compileMethod(ResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/CompilerFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/CompilerFactory.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.compiler; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.runtime.*; + +/** + * Factory for a JVMCI compiler. + */ +public interface CompilerFactory { + + /** + * Get the name of this compiler. The compiler will be selected when the jvmci.compiler system + * property is equal to this name. + */ + String getCompilerName(); + + /** + * Initialize an {@link Architecture}. The compiler has the opportunity to extend the + * {@link Architecture} description with a custom subclass. + */ + Architecture initializeArchitecture(Architecture arch); + + /** + * Create a new instance of the {@link Compiler}. + */ + Compiler createCompiler(JVMCIRuntime runtime); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/StartupEventListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.compiler/src/jdk/vm/ci/compiler/StartupEventListener.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.compiler; + +public interface StartupEventListener { + + /** + * This method is called before any of the {@link CompilerFactory} methods. + */ + void beforeJVMCIStartup(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot.amd64; + +import static jdk.vm.ci.inittimer.InitTimer.*; + +import java.util.*; + +import jdk.vm.ci.amd64.*; +import jdk.vm.ci.code.*; +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.hotspot.*; +import jdk.vm.ci.inittimer.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; +import jdk.vm.ci.service.*; + +@ServiceProvider(HotSpotJVMCIBackendFactory.class) +public class AMD64HotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFactory { + + protected EnumSet computeFeatures(HotSpotVMConfig config) { + // Configure the feature set using the HotSpot flag settings. + EnumSet features = EnumSet.noneOf(AMD64.CPUFeature.class); + if ((config.x86CPUFeatures & config.cpu3DNOWPREFETCH) != 0) { + features.add(AMD64.CPUFeature.AMD_3DNOW_PREFETCH); + } + assert config.useSSE >= 2 : "minimum config for x64"; + features.add(AMD64.CPUFeature.SSE); + features.add(AMD64.CPUFeature.SSE2); + if ((config.x86CPUFeatures & config.cpuSSE3) != 0) { + features.add(AMD64.CPUFeature.SSE3); + } + if ((config.x86CPUFeatures & config.cpuSSSE3) != 0) { + features.add(AMD64.CPUFeature.SSSE3); + } + if ((config.x86CPUFeatures & config.cpuSSE4A) != 0) { + features.add(AMD64.CPUFeature.SSE4A); + } + if ((config.x86CPUFeatures & config.cpuSSE41) != 0) { + features.add(AMD64.CPUFeature.SSE4_1); + } + if ((config.x86CPUFeatures & config.cpuSSE42) != 0) { + features.add(AMD64.CPUFeature.SSE4_2); + } + if ((config.x86CPUFeatures & config.cpuPOPCNT) != 0) { + features.add(AMD64.CPUFeature.POPCNT); + } + if ((config.x86CPUFeatures & config.cpuLZCNT) != 0) { + features.add(AMD64.CPUFeature.LZCNT); + } + if ((config.x86CPUFeatures & config.cpuAVX) != 0) { + features.add(AMD64.CPUFeature.AVX); + } + if ((config.x86CPUFeatures & config.cpuAVX2) != 0) { + features.add(AMD64.CPUFeature.AVX2); + } + if ((config.x86CPUFeatures & config.cpuAES) != 0) { + features.add(AMD64.CPUFeature.AES); + } + if ((config.x86CPUFeatures & config.cpuERMS) != 0) { + features.add(AMD64.CPUFeature.ERMS); + } + if ((config.x86CPUFeatures & config.cpuBMI1) != 0) { + features.add(AMD64.CPUFeature.BMI1); + } + return features; + } + + protected EnumSet computeFlags(HotSpotVMConfig config) { + EnumSet flags = EnumSet.noneOf(AMD64.Flag.class); + if (config.useCountLeadingZerosInstruction) { + flags.add(AMD64.Flag.UseCountLeadingZerosInstruction); + } + if (config.useCountTrailingZerosInstruction) { + flags.add(AMD64.Flag.UseCountTrailingZerosInstruction); + } + return flags; + } + + protected TargetDescription createTarget(HotSpotVMConfig config, CompilerFactory compilerFactory) { + final int stackFrameAlignment = 16; + final int implicitNullCheckLimit = 4096; + final boolean inlineObjects = true; + Architecture arch = new AMD64(computeFeatures(config), computeFlags(config)); + return new TargetDescription(compilerFactory.initializeArchitecture(arch), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + } + + protected HotSpotConstantReflectionProvider createConstantReflection(HotSpotJVMCIRuntimeProvider runtime) { + return new HotSpotConstantReflectionProvider(runtime); + } + + protected RegisterConfig createRegisterConfig(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target) { + return new AMD64HotSpotRegisterConfig(target.arch, runtime.getConfig()); + } + + protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { + return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); + } + + protected HotSpotMetaAccessProvider createMetaAccess(HotSpotJVMCIRuntimeProvider runtime) { + return new HotSpotMetaAccessProvider(runtime); + } + + @Override + public String getArchitecture() { + return "AMD64"; + } + + @Override + public String toString() { + return "JVMCIBackend:" + getArchitecture(); + } + + @SuppressWarnings("try") + public JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, CompilerFactory compilerFactory, JVMCIBackend host) { + + assert host == null; + TargetDescription target = createTarget(runtime.getConfig(), compilerFactory); + + RegisterConfig regConfig; + HotSpotCodeCacheProvider codeCache; + ConstantReflectionProvider constantReflection; + HotSpotMetaAccessProvider metaAccess; + try (InitTimer t = timer("create providers")) { + try (InitTimer rt = timer("create MetaAccess provider")) { + metaAccess = createMetaAccess(runtime); + } + try (InitTimer rt = timer("create RegisterConfig")) { + regConfig = createRegisterConfig(runtime, target); + } + try (InitTimer rt = timer("create CodeCache provider")) { + codeCache = createCodeCache(runtime, target, regConfig); + } + try (InitTimer rt = timer("create ConstantReflection provider")) { + constantReflection = createConstantReflection(runtime); + } + } + try (InitTimer rt = timer("instantiate backend")) { + return createBackend(metaAccess, codeCache, constantReflection); + } + } + + protected JVMCIBackend createBackend(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection) { + return new JVMCIBackend(metaAccess, codeCache, constantReflection); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot.amd64; + +import static jdk.vm.ci.amd64.AMD64.*; + +import java.util.*; + +import jdk.vm.ci.amd64.*; +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.CallingConvention.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.hotspot.*; +import jdk.vm.ci.meta.*; + +public class AMD64HotSpotRegisterConfig implements RegisterConfig { + + private final Architecture architecture; + + private final Register[] allocatable; + + private final int maxFrameSize; + + /** + * The caller saved registers always include all parameter registers. + */ + private final Register[] callerSaved; + + private final boolean allAllocatableAreCallerSaved; + + private final RegisterAttributes[] attributesMap; + + public int getMaximumFrameSize() { + return maxFrameSize; + } + + @Override + public Register[] getAllocatableRegisters() { + return allocatable.clone(); + } + + public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { + ArrayList list = new ArrayList<>(); + for (Register reg : registers) { + if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { + list.add(reg); + } + } + + Register[] ret = list.toArray(new Register[list.size()]); + return ret; + } + + @Override + public RegisterAttributes[] getAttributesMap() { + return attributesMap.clone(); + } + + private final Register[] javaGeneralParameterRegisters; + private final Register[] nativeGeneralParameterRegisters; + private final Register[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7}; + + /* + * Some ABIs (e.g. Windows) require a so-called "home space", that is a save area on the stack + * to store the argument registers + */ + private final boolean needsNativeStackHomeSpace; + + private static Register[] initAllocatable(boolean reserveForHeapBase) { + Register[] registers = null; + // @formatter:off + if (reserveForHeapBase) { + registers = new Register[] { + rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, /*r12,*/ r13, r14, /*r15, */ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + } else { + registers = new Register[] { + rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, /*r15, */ + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, + xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 + }; + } + // @formatter:on + return registers; + } + + public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config) { + this(architecture, config, initAllocatable(config.useCompressedOops)); + assert callerSaved.length >= allocatable.length; + } + + public AMD64HotSpotRegisterConfig(Architecture architecture, HotSpotVMConfig config, Register[] allocatable) { + this.architecture = architecture; + this.maxFrameSize = config.maxFrameSize; + + if (config.windowsOs) { + javaGeneralParameterRegisters = new Register[]{rdx, r8, r9, rdi, rsi, rcx}; + nativeGeneralParameterRegisters = new Register[]{rcx, rdx, r8, r9}; + this.needsNativeStackHomeSpace = true; + } else { + javaGeneralParameterRegisters = new Register[]{rsi, rdx, rcx, r8, r9, rdi}; + nativeGeneralParameterRegisters = new Register[]{rdi, rsi, rdx, rcx, r8, r9}; + this.needsNativeStackHomeSpace = false; + } + + this.allocatable = allocatable.clone(); + Set callerSaveSet = new HashSet<>(); + Collections.addAll(callerSaveSet, allocatable); + Collections.addAll(callerSaveSet, xmmParameterRegisters); + Collections.addAll(callerSaveSet, javaGeneralParameterRegisters); + Collections.addAll(callerSaveSet, nativeGeneralParameterRegisters); + callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]); + + allAllocatableAreCallerSaved = true; + attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters); + } + + @Override + public Register[] getCallerSaveRegisters() { + return callerSaved; + } + + public Register[] getCalleeSaveRegisters() { + return null; + } + + @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return allAllocatableAreCallerSaved; + } + + @Override + public Register getRegisterForRole(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { + if (type == Type.NativeCall) { + return callingConvention(nativeGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + // On x64, parameter locations are the same whether viewed + // from the caller or callee perspective + return callingConvention(javaGeneralParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + + public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Short: + case Char: + case Int: + case Long: + case Object: + return type == Type.NativeCall ? nativeGeneralParameterRegisters : javaGeneralParameterRegisters; + case Float: + case Double: + return xmmParameterRegisters; + default: + throw JVMCIError.shouldNotReachHere(); + } + } + + private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { + AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; + + int currentGeneral = 0; + int currentXMM = 0; + int currentStackOffset = type == Type.NativeCall && needsNativeStackHomeSpace ? generalParameterRegisters.length * target.wordSize : 0; + + for (int i = 0; i < parameterTypes.length; i++) { + final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + if (!stackOnly && currentGeneral < generalParameterRegisters.length) { + Register register = generalParameterRegisters[currentGeneral++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Float: + case Double: + if (!stackOnly && currentXMM < xmmParameterRegisters.length) { + Register register = xmmParameterRegisters[currentXMM++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + default: + throw JVMCIError.shouldNotReachHere(); + } + + if (locations[i] == null) { + LIRKind lirKind = target.getLIRKind(kind); + locations[i] = StackSlot.get(lirKind, currentStackOffset, !type.out); + currentStackOffset += Math.max(target.getSizeInBytes(lirKind.getPlatformKind()), target.wordSize); + } + } + + JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); + AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind).asValue(target.getLIRKind(returnKind.getStackKind())); + return new CallingConvention(currentStackOffset, returnLocation, locations); + } + + @Override + public Register getReturnRegister(JavaKind kind) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return rax; + case Float: + case Double: + return xmm0; + case Void: + case Illegal: + return null; + default: + throw new UnsupportedOperationException("no return register for type " + kind); + } + } + + @Override + public Register getFrameRegister() { + return rsp; + } + + @Override + public String toString() { + return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot.sparc; + +import static jdk.vm.ci.inittimer.InitTimer.*; + +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.hotspot.*; +import jdk.vm.ci.inittimer.*; +import jdk.vm.ci.runtime.*; +import jdk.vm.ci.service.*; +import jdk.vm.ci.sparc.*; +import jdk.vm.ci.sparc.SPARC.CPUFeature; + +@ServiceProvider(HotSpotJVMCIBackendFactory.class) +public class SPARCHotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFactory { + + protected TargetDescription createTarget(HotSpotVMConfig config, CompilerFactory compilerFactory) { + final int stackFrameAlignment = 16; + final int implicitNullCheckLimit = 4096; + final boolean inlineObjects = false; + Architecture arch = new SPARC(computeFeatures(config)); + return new TargetDescription(compilerFactory.initializeArchitecture(arch), true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); + } + + protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntimeProvider runtime, TargetDescription target, RegisterConfig regConfig) { + return new HotSpotCodeCacheProvider(runtime, runtime.getConfig(), target, regConfig); + } + + protected EnumSet computeFeatures(HotSpotVMConfig config) { + EnumSet features = EnumSet.noneOf(CPUFeature.class); + if ((config.sparcFeatures & config.vis1Instructions) != 0) { + features.add(CPUFeature.VIS1); + } + if ((config.sparcFeatures & config.vis2Instructions) != 0) { + features.add(CPUFeature.VIS2); + } + if ((config.sparcFeatures & config.vis3Instructions) != 0) { + features.add(CPUFeature.VIS3); + } + if ((config.sparcFeatures & config.cbcondInstructions) != 0) { + features.add(CPUFeature.CBCOND); + } + if (config.useBlockZeroing) { + features.add(CPUFeature.BLOCK_ZEROING); + } + return features; + } + + @Override + public String getArchitecture() { + return "SPARC"; + } + + @Override + public String toString() { + return "JVMCIBackend:" + getArchitecture(); + } + + @SuppressWarnings("try") + public JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, CompilerFactory compilerFactory, JVMCIBackend host) { + assert host == null; + TargetDescription target = createTarget(runtime.getConfig(), compilerFactory); + + HotSpotMetaAccessProvider metaAccess = new HotSpotMetaAccessProvider(runtime); + RegisterConfig regConfig = new SPARCHotSpotRegisterConfig(target, runtime.getConfig()); + HotSpotCodeCacheProvider codeCache = createCodeCache(runtime, target, regConfig); + HotSpotConstantReflectionProvider constantReflection = new HotSpotConstantReflectionProvider(runtime); + try (InitTimer rt = timer("instantiate backend")) { + return createBackend(metaAccess, codeCache, constantReflection); + } + } + + protected JVMCIBackend createBackend(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, HotSpotConstantReflectionProvider constantReflection) { + return new JVMCIBackend(metaAccess, codeCache, constantReflection); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot.sparc; + +import static jdk.vm.ci.sparc.SPARC.*; + +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.CallingConvention.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.hotspot.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.sparc.*; + +public class SPARCHotSpotRegisterConfig implements RegisterConfig { + + private final Architecture architecture; + + private final Register[] allocatable; + + private final RegisterAttributes[] attributesMap; + + @Override + public Register[] getAllocatableRegisters() { + return allocatable.clone(); + } + + public Register[] filterAllocatableRegisters(PlatformKind kind, Register[] registers) { + ArrayList list = new ArrayList<>(); + for (Register reg : registers) { + if (architecture.canStoreValue(reg.getRegisterCategory(), kind)) { + // Special treatment for double precision + // TODO: This is wasteful it uses only half of the registers as float. + if (kind == JavaKind.Double) { + if (reg.getRegisterCategory().equals(FPUd)) { + list.add(reg); + } + } else if (kind == JavaKind.Float) { + if (reg.getRegisterCategory().equals(FPUs)) { + list.add(reg); + } + } else { + list.add(reg); + } + } + } + + Register[] ret = list.toArray(new Register[list.size()]); + return ret; + } + + @Override + public RegisterAttributes[] getAttributesMap() { + return attributesMap.clone(); + } + + private final Register[] cpuCallerParameterRegisters = {o0, o1, o2, o3, o4, o5}; + private final Register[] cpuCalleeParameterRegisters = {i0, i1, i2, i3, i4, i5}; + + private final Register[] fpuParameterRegisters = {f0, f1, f2, f3, f4, f5, f6, f7}; + private final Register[] fpuDoubleParameterRegisters = {d0, null, d2, null, d4, null, d6, null}; + // @formatter:off + private final Register[] callerSaveRegisters = + {g1, g2, g3, g4, g5, g6, g7, + o0, o1, o2, o3, o4, o5, o7, + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62}; + // @formatter:on + + /** + * Registers saved by the callee. This lists all L and I registers which are saved in the + * register window. + */ + private final Register[] calleeSaveRegisters = {l0, l1, l2, l3, l4, l5, l6, l7, i0, i1, i2, i3, i4, i5, i6, i7}; + + private static Register[] initAllocatable(boolean reserveForHeapBase) { + Register[] registers = null; + if (reserveForHeapBase) { + // @formatter:off + registers = new Register[]{ + // TODO this is not complete + // o7 cannot be used as register because it is always overwritten on call + // and the current register handler would ignore this fact if the called + // method still does not modify registers, in fact o7 is modified by the Call instruction + // There would be some extra handlin necessary to be able to handle the o7 properly for local usage + g1, g4, g5, + o0, o1, o2, o3, o4, o5, /*o6,o7,*/ + l0, l1, l2, l3, l4, l5, l6, l7, + i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ + //f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + } else { + // @formatter:off + registers = new Register[]{ + // TODO this is not complete + g1, g4, g5, + o0, o1, o2, o3, o4, o5, /*o6, o7,*/ + l0, l1, l2, l3, l4, l5, l6, l7, + i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ +// f0, f1, f2, f3, f4, f5, f6, f7 + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + } + + return registers; + } + + public SPARCHotSpotRegisterConfig(TargetDescription target, HotSpotVMConfig config) { + this(target, initAllocatable(config.useCompressedOops)); + } + + public SPARCHotSpotRegisterConfig(TargetDescription target, Register[] allocatable) { + this.architecture = target.arch; + this.allocatable = allocatable.clone(); + attributesMap = RegisterAttributes.createMap(this, SPARC.allRegisters); + } + + @Override + public Register[] getCallerSaveRegisters() { + return callerSaveRegisters; + } + + public Register[] getCalleeSaveRegisters() { + return calleeSaveRegisters; + } + + @Override + public boolean areAllAllocatableRegistersCallerSaved() { + return false; + } + + @Override + public Register getRegisterForRole(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, TargetDescription target, boolean stackOnly) { + if (type == Type.JavaCall || type == Type.NativeCall) { + return callingConvention(cpuCallerParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + if (type == Type.JavaCallee) { + return callingConvention(cpuCalleeParameterRegisters, returnType, parameterTypes, type, target, stackOnly); + } + throw JVMCIError.shouldNotReachHere(); + } + + public Register[] getCallingConventionRegisters(Type type, JavaKind kind) { + if (architecture.canStoreValue(FPUs, kind) || architecture.canStoreValue(FPUd, kind)) { + return fpuParameterRegisters; + } + assert architecture.canStoreValue(CPU, kind); + return type == Type.JavaCallee ? cpuCalleeParameterRegisters : cpuCallerParameterRegisters; + } + + private CallingConvention callingConvention(Register[] generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, Type type, TargetDescription target, boolean stackOnly) { + AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; + + int currentGeneral = 0; + int currentFloating = 0; + int currentStackOffset = 0; + + for (int i = 0; i < parameterTypes.length; i++) { + final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); + + switch (kind) { + case Byte: + case Boolean: + case Short: + case Char: + case Int: + case Long: + case Object: + if (!stackOnly && currentGeneral < generalParameterRegisters.length) { + Register register = generalParameterRegisters[currentGeneral++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Double: + if (!stackOnly && currentFloating < fpuParameterRegisters.length) { + if (currentFloating % 2 != 0) { + // Make register number even to be a double reg + currentFloating++; + } + Register register = fpuDoubleParameterRegisters[currentFloating]; + currentFloating += 2; // Only every second is a double register + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + case Float: + if (!stackOnly && currentFloating < fpuParameterRegisters.length) { + Register register = fpuParameterRegisters[currentFloating++]; + locations[i] = register.asValue(target.getLIRKind(kind)); + } + break; + default: + throw JVMCIError.shouldNotReachHere(); + } + + if (locations[i] == null) { + // Stack slot is always aligned to its size in bytes but minimum wordsize + int typeSize = SPARC.spillSlotSize(target, kind); + currentStackOffset = roundUp(currentStackOffset, typeSize); + int slotOffset = currentStackOffset + SPARC.REGISTER_SAFE_AREA_SIZE; + locations[i] = StackSlot.get(target.getLIRKind(kind.getStackKind()), slotOffset, !type.out); + currentStackOffset += typeSize; + } + } + + JavaKind returnKind = returnType == null ? JavaKind.Void : returnType.getJavaKind(); + AllocatableValue returnLocation = returnKind == JavaKind.Void ? Value.ILLEGAL : getReturnRegister(returnKind, type).asValue(target.getLIRKind(returnKind.getStackKind())); + // Space where callee may spill outgoing parameters o0...o5 + int lowerOutgoingSpace = Math.min(locations.length, 6) * target.wordSize; + return new CallingConvention(currentStackOffset + lowerOutgoingSpace, returnLocation, locations); + } + + private static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + @Override + public Register getReturnRegister(JavaKind kind) { + return getReturnRegister(kind, Type.JavaCallee); + } + + private static Register getReturnRegister(JavaKind kind, Type type) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + case Object: + return type == Type.JavaCallee ? i0 : o0; + case Float: + return f0; + case Double: + return d0; + case Void: + case Illegal: + return null; + default: + throw new UnsupportedOperationException("no return register for type " + kind); + } + } + + @Override + public Register getFrameRegister() { + return sp; + } + + @Override + public String toString() { + return String.format("Allocatable: " + Arrays.toString(getAllocatableRegisters()) + "%n" + "CallerSave: " + Arrays.toString(getCallerSaveRegisters()) + "%n"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,574 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.inittimer.InitTimer.timer; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.hotspotvmconfig.HotSpotVMField; +import jdk.vm.ci.inittimer.InitTimer; +import jdk.vm.ci.meta.JavaType; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.SpeculationLog; +import sun.misc.Unsafe; + +/** + * Calls from Java into HotSpot. The behavior of all the methods in this class that take a native + * pointer as an argument (e.g., {@link #getSymbol(long)}) is undefined if the argument does not + * denote a valid native object. + */ +public final class CompilerToVM { + /** + * Initializes the native part of the JVMCI runtime. + */ + private static native void registerNatives(); + + static { + initialize(); + } + + @SuppressWarnings("try") + private static void initialize() { + try (InitTimer t = timer("CompilerToVM.registerNatives")) { + registerNatives(); + } + } + + /** + * Copies the original bytecode of {@code method} into a new byte array and returns it. + * + * @return a new byte array containing the original bytecode of {@code method} + */ + native byte[] getBytecode(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the number of entries in {@code method}'s exception handler table or 0 if it has not + * exception handler table. + */ + native int getExceptionTableLength(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the address of the first entry in {@code method}'s exception handler table. + * + * Each entry is a native object described by these fields: + * + *
    + *
  • {@link HotSpotVMConfig#exceptionTableElementSize}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementStartPcOffset}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementEndPcOffset}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementHandlerPcOffset}
  • + *
  • {@link HotSpotVMConfig#exceptionTableElementCatchTypeIndexOffset} + *
+ * + * @return 0 if {@code method} has no exception handlers (i.e. + * {@code getExceptionTableLength(method) == 0}) + */ + native long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if {@code method} can be inlined. A method may not be inlinable for a number of + * reasons such as: + *
    + *
  • a CompileOracle directive may prevent inlining or compilation of methods
  • + *
  • the method may have a bytecode breakpoint set
  • + *
  • the method may have other bytecode features that require special handling by the VM
  • + *
+ */ + native boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if {@code method} should be inlined at any cost. This could be because: + *
    + *
  • a CompileOracle directive may forces inlining of this methods
  • + *
  • an annotation forces inlining of this method
  • + *
+ */ + native boolean shouldInlineMethod(HotSpotResolvedJavaMethodImpl method); + + /** + * Used to implement {@link ResolvedJavaType#findUniqueConcreteMethod(ResolvedJavaMethod)}. + * + * @param method the method on which to base the search + * @param actualHolderType the best known type of receiver + * @return the method result or 0 is there is no unique concrete method for {@code method} + */ + native HotSpotResolvedJavaMethodImpl findUniqueConcreteMethod(HotSpotResolvedObjectTypeImpl actualHolderType, HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the implementor for the interface class {@code type}. + * + * @return the implementor if there is a single implementor, 0 if there is no implementor, or + * {@code type} itself if there is more than one implementor + */ + native HotSpotResolvedObjectTypeImpl getImplementor(HotSpotResolvedObjectTypeImpl type); + + /** + * Determines if {@code method} is ignored by security stack walks. + */ + native boolean methodIsIgnoredBySecurityStackWalk(HotSpotResolvedJavaMethodImpl method); + + /** + * Converts a name to a type. + * + * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format + * @param accessingClass the context of resolution (must not be null) + * @param resolve force resolution to a {@link ResolvedJavaType}. If true, this method will + * either return a {@link ResolvedJavaType} or throw an exception + * @return the type for {@code name} or 0 if resolution failed and {@code resolve == false} + * @throws LinkageError if {@code resolve == true} and the resolution failed + */ + native HotSpotResolvedObjectTypeImpl lookupType(String name, Class accessingClass, boolean resolve); + + /** + * Resolves the entry at index {@code cpi} in {@code constantPool} to an object. + * + * The behavior of this method is undefined if {@code cpi} does not denote one of the following + * entry types: {@code JVM_CONSTANT_MethodHandle}, {@code JVM_CONSTANT_MethodHandleInError}, + * {@code JVM_CONSTANT_MethodType} and {@code JVM_CONSTANT_MethodTypeInError}. + */ + native Object resolveConstantInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Resolves the entry at index {@code cpi} in {@code constantPool} to an object, looking in the + * constant pool cache first. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_String} entry. + */ + native Object resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} index from the entry at index {@code cpi} in + * {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry containing a + * {@code JVM_CONSTANT_NameAndType} index. + */ + native int lookupNameAndTypeRefIndexInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the name of the {@code JVM_CONSTANT_NameAndType} entry referenced by another entry + * denoted by {@code which} in {@code constantPool}. + * + * The behavior of this method is undefined if {@code which} does not denote a entry that + * references a {@code JVM_CONSTANT_NameAndType} entry. + */ + native String lookupNameInPool(HotSpotConstantPool constantPool, int which); + + /** + * Gets the signature of the {@code JVM_CONSTANT_NameAndType} entry referenced by another entry + * denoted by {@code which} in {@code constantPool}. + * + * The behavior of this method is undefined if {@code which} does not denote a entry that + * references a {@code JVM_CONSTANT_NameAndType} entry. + */ + native String lookupSignatureInPool(HotSpotConstantPool constantPool, int which); + + /** + * Gets the {@code JVM_CONSTANT_Class} index from the entry at index {@code cpi} in + * {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry containing a + * {@code JVM_CONSTANT_Class} index. + */ + native int lookupKlassRefIndexInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Looks up a class denoted by the {@code JVM_CONSTANT_Class} entry at index {@code cpi} in + * {@code constantPool}. This method does not perform any resolution. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_Class} entry. + * + * @return the resolved class entry or a String otherwise + */ + native Object lookupKlassInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Looks up a method denoted by the entry at index {@code cpi} in {@code constantPool}. This + * method does not perform any resolution. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a method. + * + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1}. If non-negative, then resolution checks specific to the bytecode it + * denotes are performed if the method is already resolved. Should any of these + * checks fail, 0 is returned. + * @return the resolved method entry, 0 otherwise + */ + native HotSpotResolvedJavaMethodImpl lookupMethodInPool(HotSpotConstantPool constantPool, int cpi, byte opcode); + + /** + * Ensures that the type referenced by the specified {@code JVM_CONSTANT_InvokeDynamic} entry at + * index {@code cpi} in {@code constantPool} is loaded and initialized. + * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_InvokeDynamic} entry. + */ + native void resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Ensures that the type referenced by the entry for a signature + * polymorphic method at index {@code cpi} in {@code constantPool} is loaded and + * initialized. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a signature polymorphic method. + */ + native void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Gets the resolved type denoted by the entry at index {@code cpi} in {@code constantPool}. + * + * The behavior of this method is undefined if {@code cpi} does not denote an entry representing + * a class. + * + * @throws LinkageError if resolution failed + */ + native HotSpotResolvedObjectTypeImpl resolveTypeInPool(HotSpotConstantPool constantPool, int cpi) throws LinkageError; + + /** + * Looks up and attempts to resolve the {@code JVM_CONSTANT_Field} entry at index {@code cpi} in + * {@code constantPool}. The values returned in {@code info} are: + * + *
+     *     [(int) flags,   // only valid if field is resolved
+     *      (int) offset]  // only valid if field is resolved
+     * 
+ * + * The behavior of this method is undefined if {@code cpi} does not denote a + * {@code JVM_CONSTANT_Field} entry. + * + * @param info an array in which the details of the field are returned + * @return the type defining the field if resolution is successful, 0 otherwise + */ + native HotSpotResolvedObjectTypeImpl resolveFieldInPool(HotSpotConstantPool constantPool, int cpi, byte opcode, long[] info); + + /** + * Converts {@code cpci} from an index into the cache for {@code constantPool} to an index + * directly into {@code constantPool}. + * + * The behavior of this method is undefined if {@code ccpi} is an invalid constant pool cache + * index. + */ + native int constantPoolRemapInstructionOperandFromCache(HotSpotConstantPool constantPool, int cpci); + + /** + * Gets the appendix object (if any) associated with the entry at index {@code cpi} in + * {@code constantPool}. + */ + native Object lookupAppendixInPool(HotSpotConstantPool constantPool, int cpi); + + /** + * Installs the result of a compilation into the code cache. + * + * @param target the target where this code should be installed + * @param compiledCode the result of a compilation + * @param code the details of the installed CodeBlob are written to this object + * @return the outcome of the installation which will be one of + * {@link HotSpotVMConfig#codeInstallResultOk}, + * {@link HotSpotVMConfig#codeInstallResultCacheFull}, + * {@link HotSpotVMConfig#codeInstallResultCodeTooLarge}, + * {@link HotSpotVMConfig#codeInstallResultDependenciesFailed} or + * {@link HotSpotVMConfig#codeInstallResultDependenciesInvalid}. + */ + public native int installCode(TargetDescription target, HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog); + + public native int getMetadata(TargetDescription target, HotSpotCompiledCode compiledCode, HotSpotMetaData metaData); + + /** + * Notifies the VM of statistics for a completed compilation. + * + * @param id the identifier of the compilation + * @param method the method compiled + * @param osr specifies if the compilation was for on-stack-replacement + * @param processedBytecodes the number of bytecodes processed during the compilation, including + * the bytecodes of all inlined methods + * @param time the amount time spent compiling {@code method} + * @param timeUnitsPerSecond the granularity of the units for the {@code time} value + * @param installedCode the nmethod installed as a result of the compilation + */ + public synchronized native void notifyCompilationStatistics(int id, HotSpotResolvedJavaMethodImpl method, boolean osr, int processedBytecodes, long time, long timeUnitsPerSecond, + InstalledCode installedCode); + + /** + * Resets all compilation statistics. + */ + public native void resetCompilationStatistics(); + + /** + * Initializes the fields of {@code config}. + */ + native long initializeConfiguration(); + + /** + * Resolves the implementation of {@code method} for virtual dispatches on objects of dynamic + * type {@code exactReceiver}. This resolution process only searches "up" the class hierarchy of + * {@code exactReceiver}. + * + * @param caller the caller or context type used to perform access checks + * @return the link-time resolved method (might be abstract) or {@code 0} if it can not be + * linked + */ + native HotSpotResolvedJavaMethodImpl resolveMethod(HotSpotResolvedObjectTypeImpl exactReceiver, HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl caller); + + /** + * Gets the static initializer of {@code type}. + * + * @return 0 if {@code type} has no static initializer + */ + native HotSpotResolvedJavaMethodImpl getClassInitializer(HotSpotResolvedObjectTypeImpl type); + + /** + * Determines if {@code type} or any of its currently loaded subclasses overrides + * {@code Object.finalize()}. + */ + native boolean hasFinalizableSubclass(HotSpotResolvedObjectTypeImpl type); + + /** + * Gets the method corresponding to {@code holder} and slot number {@code slot} (i.e. + * {@link Method#slot} or {@link Constructor#slot}). + */ + native HotSpotResolvedJavaMethodImpl getResolvedJavaMethodAtSlot(Class holder, int slot); + + /** + * Gets the maximum absolute offset of a PC relative call to {@code address} from any position + * in the code cache. + * + * @param address an address that may be called from any code in the code cache + * @return -1 if {@code address == 0} + */ + public native long getMaxCallTargetOffset(long address); + + /** + * Gets a textual disassembly of {@code codeBlob}. + * + * @return a non-zero length string containing a disassembly of {@code codeBlob} or null if + * {@code codeBlob} could not be disassembled for some reason + */ + // The HotSpot disassembler seems not to be thread safe so it's better to synchronize its usage + public synchronized native String disassembleCodeBlob(long codeBlob); + + /** + * Gets a stack trace element for {@code method} at bytecode index {@code bci}. + */ + native StackTraceElement getStackTraceElement(HotSpotResolvedJavaMethodImpl method, int bci); + + /** + * Executes some {@code installedCode} with arguments {@code args}. + * + * @return the result of executing {@code installedCode} + * @throws InvalidInstalledCodeException if {@code installedCode} has been invalidated + */ + native Object executeInstalledCode(Object[] args, InstalledCode installedCode) throws InvalidInstalledCodeException; + + /** + * Gets the line number table for {@code method}. The line number table is encoded as (bci, + * source line number) pairs. + * + * @return the line number table for {@code method} or null if it doesn't have one + */ + native long[] getLineNumberTable(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the number of entries in the local variable table for {@code method}. + * + * @return the number of entries in the local variable table for {@code method} + */ + native int getLocalVariableTableLength(HotSpotResolvedJavaMethodImpl method); + + /** + * Gets the address of the first entry in the local variable table for {@code method}. + * + * Each entry is a native object described by these fields: + * + *
    + *
  • {@link HotSpotVMConfig#localVariableTableElementSize}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementLengthOffset}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementNameCpIndexOffset}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementDescriptorCpIndexOffset}
  • + *
  • {@link HotSpotVMConfig#localVariableTableElementSignatureCpIndexOffset} + *
  • {@link HotSpotVMConfig#localVariableTableElementSlotOffset} + *
  • {@link HotSpotVMConfig#localVariableTableElementStartBciOffset} + *
+ * + * @return 0 if {@code method} does not have a local variable table + */ + native long getLocalVariableTableStart(HotSpotResolvedJavaMethodImpl method); + + /** + * Reads an object pointer within a VM data structure. That is, any {@link HotSpotVMField} whose + * {@link HotSpotVMField#type() type} is {@code "oop"} (e.g., + * {@code ArrayKlass::_component_mirror}, {@code Klass::_java_mirror}, + * {@code JavaThread::_threadObj}). + * + * Note that {@link Unsafe#getObject(Object, long)} cannot be used for this since it does a + * {@code narrowOop} read if the VM is using compressed oops whereas oops within VM data + * structures are (currently) always uncompressed. + * + * @param address address of an oop field within a VM data structure + */ + native Object readUncompressedOop(long address); + + /** + * Determines if {@code method} should not be inlined or compiled. + */ + native void doNotInlineOrCompile(HotSpotResolvedJavaMethodImpl method); + + /** + * Invalidates the profiling information for {@code method} and (re)initializes it such that + * profiling restarts upon its next invocation. + */ + native void reprofile(HotSpotResolvedJavaMethodImpl method); + + /** + * Invalidates {@code installedCode} such that {@link InvalidInstalledCodeException} will be + * raised the next time {@code installedCode} is executed. + */ + public native void invalidateInstalledCode(InstalledCode installedCode); + + /** + * Collects the current values of all JVMCI benchmark counters, summed up over all threads. + */ + public native long[] collectCounters(); + + /** + * Determines if {@code metaspaceMethodData} is mature. + */ + native boolean isMature(long metaspaceMethodData); + + /** + * Generate a unique id to identify the result of the compile. + */ + native int allocateCompileId(HotSpotResolvedJavaMethodImpl method, int entryBCI); + + /** + * Determines if {@code method} has OSR compiled code identified by {@code entryBCI} for + * compilation level {@code level}. + */ + native boolean hasCompiledCodeForOSR(HotSpotResolvedJavaMethodImpl method, int entryBCI, int level); + + /** + * Gets the value of {@code metaspaceSymbol} as a String. + */ + native String getSymbol(long metaspaceSymbol); + + /** + * Looks for the next Java stack frame matching an entry in {@code methods}. + * + * @param frame the starting point of the search, where {@code null} refers to the topmost frame + * @param methods the methods to look for, where {@code null} means that any frame is returned + * @return the frame, or {@code null} if the end of the stack was reached during the search + */ + public native HotSpotStackFrameReference getNextStackFrame(HotSpotStackFrameReference frame, HotSpotResolvedJavaMethodImpl[] methods, int initialSkip); + + /** + * Materializes all virtual objects within {@code stackFrame} updates its locals. + * + * @param invalidate if {@code true}, the compiled method for the stack frame will be + * invalidated. + */ + native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate); + + /** + * Gets the v-table index for interface method {@code method} in the receiver {@code type} or + * {@link HotSpotVMConfig#invalidVtableIndex} if {@code method} is not in {@code type}'s + * v-table. + * + * @throws InternalError if {@code type} is an interface or {@code method} is not held by an + * interface or class represented by {@code type} is not initialized + */ + native int getVtableIndexForInterfaceMethod(HotSpotResolvedObjectTypeImpl type, HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if debug info should also be emitted at non-safepoint locations. + */ + public native boolean shouldDebugNonSafepoints(); + + /** + * Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to the + * HotSpot's log stream. + * + * @exception NullPointerException if bytes is null. + * @exception IndexOutOfBoundsException if copying would cause access of data outside array + * bounds. + */ + public native void writeDebugOutput(byte[] bytes, int offset, int length); + + /** + * Flush HotSpot's log stream. + */ + public native void flushDebugOutput(); + + /** + * Read a value representing a metaspace Method* and return the + * {@link HotSpotResolvedJavaMethodImpl} wrapping it. This method does no checking that the + * location actually contains a valid Method*. If the {@code base} object is a + * {@link HotSpotResolvedJavaMethodImpl}, {@link HotSpotConstantPool} or + * {@link HotSpotResolvedObjectTypeImpl} then the metaspace pointer is fetched from that object + * and used as the base. Otherwise the object itself is used as the base. + * + * @param base an object to read from or null + * @param displacement + * @return null or the resolved method for this location + */ + native HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(Object base, long displacement); + + /** + * Read a value representing a metaspace ConstantPool* and return the + * {@link HotSpotConstantPool} wrapping it. This method does no checking that the location + * actually contains a valid ConstantPool*. If the {@code base} object is a + * {@link HotSpotResolvedJavaMethodImpl}, {@link HotSpotConstantPool} or + * {@link HotSpotResolvedObjectTypeImpl} then the metaspace pointer is fetched from that object + * and used as the base. Otherwise the object itself is used as the base. + * + * @param base an object to read from or null + * @param displacement + * @return null or the resolved method for this location + */ + native HotSpotConstantPool getConstantPool(Object base, long displacement); + + /** + * Read a value representing a metaspace Klass* and return the + * {@link HotSpotResolvedObjectTypeImpl} wrapping it. The method does no checking that the + * location actually contains a valid Klass*. If the {@code base} object is a + * {@link HotSpotResolvedJavaMethodImpl}, {@link HotSpotConstantPool} or + * {@link HotSpotResolvedObjectTypeImpl} then the metaspace pointer is fetched from that object + * and used as the base. Otherwise the object itself is used as the base. + * + * @param base an object to read from or null + * @param displacement + * @param compressed true if the location contains a compressed Klass* + * @return null or the resolved method for this location + */ + native HotSpotResolvedObjectTypeImpl getResolvedJavaType(Object base, long displacement, boolean compressed); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.*; + +import java.lang.reflect.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.CompilationResult.*; +import jdk.vm.ci.code.DataSection.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +/** + * HotSpot implementation of {@link CodeCacheProvider}. + */ +public class HotSpotCodeCacheProvider implements CodeCacheProvider { + + protected final HotSpotJVMCIRuntimeProvider runtime; + public final HotSpotVMConfig config; + protected final TargetDescription target; + protected final RegisterConfig regConfig; + + public HotSpotCodeCacheProvider(HotSpotJVMCIRuntimeProvider runtime, HotSpotVMConfig config, TargetDescription target, RegisterConfig regConfig) { + this.runtime = runtime; + this.config = config; + this.target = target; + this.regConfig = regConfig; + } + + @Override + public String getMarkName(Mark mark) { + int markId = (int) mark.id; + Field[] fields = runtime.getConfig().getClass().getDeclaredFields(); + for (Field f : fields) { + if (f.getName().startsWith("MARKID_")) { + f.setAccessible(true); + try { + if (f.getInt(runtime.getConfig()) == markId) { + return f.getName(); + } + } catch (Exception e) { + } + } + } + return CodeCacheProvider.super.getMarkName(mark); + } + + /** + * Decodes a call target to a mnemonic if possible. + */ + @Override + public String getTargetName(Call call) { + Field[] fields = runtime.getConfig().getClass().getDeclaredFields(); + for (Field f : fields) { + if (f.getName().endsWith("Stub")) { + f.setAccessible(true); + try { + Object address = f.get(runtime.getConfig()); + if (address.equals(call.target)) { + return f.getName() + ":0x" + Long.toHexString((Long) address); + } + } catch (Exception e) { + } + } + } + return CodeCacheProvider.super.getTargetName(call); + } + + @Override + public RegisterConfig getRegisterConfig() { + return regConfig; + } + + @Override + public int getMinimumOutgoingSize() { + return runtime.getConfig().runtimeCallStackSize; + } + + public InstalledCode logOrDump(InstalledCode installedCode, CompilationResult compResult) { + HotSpotJVMCIRuntime.runtime().notifyInstall(this, installedCode, compResult); + return installedCode; + } + + private InstalledCode installCode(CompilationResult compResult, HotSpotCompiledNmethod compiledCode, InstalledCode installedCode, SpeculationLog log) { + int result = runtime.getCompilerToVM().installCode(target, compiledCode, installedCode, log); + if (result != config.codeInstallResultOk) { + String msg = compiledCode.getInstallationFailureMessage(); + String resultDesc = config.getCodeInstallResultDescription(result); + if (msg != null) { + msg = String.format("Code installation failed: %s%n%s", resultDesc, msg); + } else { + msg = String.format("Code installation failed: %s", resultDesc); + } + if (result == config.codeInstallResultDependenciesInvalid) { + throw new AssertionError(resultDesc + " " + msg); + } + throw new BailoutException(result != config.codeInstallResultDependenciesFailed, msg); + } + return logOrDump(installedCode, compResult); + } + + public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long jvmciEnv, boolean isDefault) { + if (compResult.getId() == -1) { + compResult.setId(method.allocateCompileId(compResult.getEntryBCI())); + } + HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), isDefault); + HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(method, compResult, jvmciEnv); + return installCode(compResult, compiledCode, installedCode, method.getSpeculationLog()); + } + + @Override + public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, SpeculationLog log, InstalledCode predefinedInstalledCode) { + HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; + if (compResult.getId() == -1) { + compResult.setId(hotspotMethod.allocateCompileId(compResult.getEntryBCI())); + } + InstalledCode installedCode = predefinedInstalledCode; + if (installedCode == null) { + HotSpotInstalledCode code = new HotSpotNmethod(hotspotMethod, compResult.getName(), false); + installedCode = code; + } + HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(hotspotMethod, compResult); + return installCode(compResult, compiledCode, installedCode, log); + } + + @Override + public InstalledCode setDefaultMethod(ResolvedJavaMethod method, CompilationResult compResult) { + HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method; + return installMethod(hotspotMethod, compResult, 0L, true); + } + + public HotSpotNmethod addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) method; + if (compResult.getId() == -1) { + compResult.setId(javaMethod.allocateCompileId(compResult.getEntryBCI())); + } + HotSpotNmethod code = new HotSpotNmethod(javaMethod, compResult.getName(), false, true); + HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(javaMethod, compResult); + CompilerToVM vm = runtime.getCompilerToVM(); + int result = vm.installCode(target, compiled, code, null); + if (result != runtime.getConfig().codeInstallResultOk) { + return null; + } + return code; + } + + public boolean needsDataPatch(JavaConstant constant) { + return constant instanceof HotSpotMetaspaceConstant; + } + + private Data createSingleDataItem(Constant constant) { + int size; + DataBuilder builder; + if (constant instanceof VMConstant) { + VMConstant vmConstant = (VMConstant) constant; + boolean compressed; + long raw; + if (constant instanceof HotSpotObjectConstant) { + HotSpotObjectConstant c = (HotSpotObjectConstant) vmConstant; + compressed = c.isCompressed(); + raw = 0xDEADDEADDEADDEADL; + } else if (constant instanceof HotSpotMetaspaceConstant) { + HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) constant; + compressed = meta.isCompressed(); + raw = meta.rawValue(); + } else { + throw new JVMCIError(String.valueOf(constant)); + } + + size = target.getSizeInBytes(compressed ? JavaKind.Int : target.wordKind); + if (size == 4) { + builder = (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant))); + buffer.putInt((int) raw); + }; + } else { + assert size == 8; + builder = (buffer, patch) -> { + patch.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant))); + buffer.putLong(raw); + }; + } + } else if (JavaConstant.isNull(constant)) { + boolean compressed = COMPRESSED_NULL.equals(constant); + size = target.getSizeInBytes(compressed ? JavaKind.Int : target.wordKind); + builder = DataBuilder.zero(size); + } else if (constant instanceof SerializableConstant) { + SerializableConstant s = (SerializableConstant) constant; + size = s.getSerializedSize(); + builder = DataBuilder.serializable(s); + } else { + throw new JVMCIError(String.valueOf(constant)); + } + + return new Data(size, size, builder); + } + + public Data createDataItem(Constant... constants) { + assert constants.length > 0; + if (constants.length == 1) { + return createSingleDataItem(constants[0]); + } else { + DataBuilder[] builders = new DataBuilder[constants.length]; + int size = 0; + int alignment = 1; + for (int i = 0; i < constants.length; i++) { + Data data = createSingleDataItem(constants[i]); + + assert size % data.getAlignment() == 0 : "invalid alignment in packed constants"; + alignment = DataSection.lcm(alignment, data.getAlignment()); + + builders[i] = data.getBuilder(); + size += data.getSize(); + } + DataBuilder ret = (buffer, patches) -> { + for (DataBuilder b : builders) { + b.emit(buffer, patches); + } + }; + return new Data(alignment, size, ret); + } + } + + @Override + public TargetDescription getTarget() { + return target; + } + + public String disassemble(InstalledCode code) { + if (code.isValid()) { + long codeBlob = code.getAddress(); + return runtime.getCompilerToVM().disassembleCodeBlob(codeBlob); + } + return null; + } + + public SpeculationLog createSpeculationLog() { + return new HotSpotSpeculationLog(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import java.nio.*; +import java.util.*; +import java.util.stream.*; +import java.util.stream.Stream.Builder; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.CompilationResult.CodeAnnotation; +import jdk.vm.ci.code.CompilationResult.CodeComment; +import jdk.vm.ci.code.CompilationResult.DataPatch; +import jdk.vm.ci.code.CompilationResult.ExceptionHandler; +import jdk.vm.ci.code.CompilationResult.Infopoint; +import jdk.vm.ci.code.CompilationResult.JumpTable; +import jdk.vm.ci.code.CompilationResult.Mark; +import jdk.vm.ci.code.CompilationResult.Site; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.Assumption; + +/** + * A {@link CompilationResult} with additional HotSpot-specific information required for installing + * the code in HotSpot's code cache. + */ +public abstract class HotSpotCompiledCode { + + public final String name; + public final Site[] sites; + public final ExceptionHandler[] exceptionHandlers; + public final Comment[] comments; + public final Assumption[] assumptions; + + public final byte[] targetCode; + public final int targetCodeSize; + + public final byte[] dataSection; + public final int dataSectionAlignment; + public final DataPatch[] dataSectionPatches; + public final boolean isImmutablePIC; + + public final int totalFrameSize; + public final int customStackAreaOffset; + + /** + * The list of the methods whose bytecodes were used as input to the compilation. If + * {@code null}, then the compilation did not record method dependencies. Otherwise, the first + * element of this array is the root method of the compilation. + */ + public final ResolvedJavaMethod[] methods; + + public static class Comment { + + public final String text; + public final int pcOffset; + + public Comment(int pcOffset, String text) { + this.text = text; + this.pcOffset = pcOffset; + } + } + + public HotSpotCompiledCode(CompilationResult compResult) { + name = compResult.getName(); + sites = getSortedSites(compResult); + if (compResult.getExceptionHandlers().isEmpty()) { + exceptionHandlers = null; + } else { + exceptionHandlers = compResult.getExceptionHandlers().toArray(new ExceptionHandler[compResult.getExceptionHandlers().size()]); + } + List annotations = compResult.getAnnotations(); + comments = new Comment[annotations.size()]; + if (!annotations.isEmpty()) { + for (int i = 0; i < comments.length; i++) { + CodeAnnotation annotation = annotations.get(i); + String text; + if (annotation instanceof CodeComment) { + CodeComment codeComment = (CodeComment) annotation; + text = codeComment.value; + } else if (annotation instanceof JumpTable) { + JumpTable jumpTable = (JumpTable) annotation; + text = "JumpTable [" + jumpTable.low + " .. " + jumpTable.high + "]"; + } else { + text = annotation.toString(); + } + comments[i] = new Comment(annotation.position, text); + } + } + assumptions = compResult.getAssumptions(); + assert validateFrames(); + + targetCode = compResult.getTargetCode(); + targetCodeSize = compResult.getTargetCodeSize(); + + DataSection data = compResult.getDataSection(); + if (!data.isFinalized()) { + data.finalizeLayout(); + } + dataSection = new byte[data.getSectionSize()]; + + ByteBuffer buffer = ByteBuffer.wrap(dataSection).order(ByteOrder.nativeOrder()); + Builder patchBuilder = Stream.builder(); + data.buildDataSection(buffer, patchBuilder); + + dataSectionAlignment = data.getSectionAlignment(); + dataSectionPatches = patchBuilder.build().toArray(len -> new DataPatch[len]); + + isImmutablePIC = compResult.isImmutablePIC(); + + totalFrameSize = compResult.getTotalFrameSize(); + customStackAreaOffset = compResult.getCustomStackAreaOffset(); + + methods = compResult.getMethods(); + } + + /** + * Ensure that all the frames passed into HotSpot are properly formatted with an empty or + * illegal slot following double word slots. + */ + private boolean validateFrames() { + for (Site site : sites) { + if (site instanceof Infopoint) { + Infopoint info = (Infopoint) site; + if (info.debugInfo != null) { + BytecodeFrame frame = info.debugInfo.frame(); + assert frame == null || frame.validateFormat(); + } + } + } + return true; + } + + static class SiteComparator implements Comparator { + + public int compare(Site s1, Site s2) { + if (s1.pcOffset == s2.pcOffset && (s1 instanceof Mark ^ s2 instanceof Mark)) { + return s1 instanceof Mark ? -1 : 1; + } + return s1.pcOffset - s2.pcOffset; + } + } + + private static Site[] getSortedSites(CompilationResult target) { + List[] lists = new List[]{target.getInfopoints(), target.getDataPatches(), target.getMarks()}; + int count = 0; + for (List list : lists) { + count += list.size(); + } + Site[] result = new Site[count]; + int pos = 0; + for (List list : lists) { + for (Object elem : list) { + result[pos++] = (Site) elem; + } + } + Arrays.sort(result, new SiteComparator()); + return result; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.inittimer.*; + +/** + * {@link HotSpotCompiledCode} destined for installation as an nmethod. + */ +public final class HotSpotCompiledNmethod extends HotSpotCompiledCode { + + public final HotSpotResolvedJavaMethod method; + public final int entryBCI; + public final int id; + public final long jvmciEnv; + public final boolean hasUnsafeAccess; + + /** + * May be set by VM if code installation fails. It will describe in more detail why installation + * failed (e.g., exactly which dependency failed). + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "set by the VM") private String installationFailureMessage; + + public HotSpotCompiledNmethod(HotSpotResolvedJavaMethod method, CompilationResult compResult) { + this(method, compResult, 0L); + } + + public HotSpotCompiledNmethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long jvmciEnv) { + super(compResult); + this.method = method; + this.entryBCI = compResult.getEntryBCI(); + this.id = compResult.getId(); + this.jvmciEnv = jvmciEnv; + this.hasUnsafeAccess = compResult.hasUnsafeAccess(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + id + ":" + method.format("%H.%n(%p)%r@") + entryBCI + "]"; + } + + public String getInstallationFailureMessage() { + return installationFailureMessage; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * The compressed representation of the {@link JavaConstant#NULL_POINTER null constant}. + */ +public final class HotSpotCompressedNullConstant implements JavaConstant, HotSpotConstant { + + public static final JavaConstant COMPRESSED_NULL = new HotSpotCompressedNullConstant(); + + private HotSpotCompressedNullConstant() { + } + + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean isCompressed() { + return true; + } + + @Override + public boolean isDefaultForKind() { + return true; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return JavaConstant.toString(this); + } + + @Override + public String toValueString() { + return "null"; + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object o) { + return o instanceof HotSpotCompressedNullConstant; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Marker interface for hotspot specific constants. + */ +public interface HotSpotConstant extends Constant { + + boolean isCompressed(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,716 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.invoke.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link ConstantPool} for HotSpot. + */ +public final class HotSpotConstantPool implements ConstantPool, HotSpotProxified, MetaspaceWrapperObject { + + /** + * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. + */ + public static class Bytecodes { + public static final int LDC = 18; // 0x12 + public static final int LDC_W = 19; // 0x13 + public static final int LDC2_W = 20; // 0x14 + public static final int GETSTATIC = 178; // 0xB2 + public static final int PUTSTATIC = 179; // 0xB3 + public static final int GETFIELD = 180; // 0xB4 + public static final int PUTFIELD = 181; // 0xB5 + public static final int INVOKEVIRTUAL = 182; // 0xB6 + public static final int INVOKESPECIAL = 183; // 0xB7 + public static final int INVOKESTATIC = 184; // 0xB8 + public static final int INVOKEINTERFACE = 185; // 0xB9 + public static final int INVOKEDYNAMIC = 186; // 0xBA + public static final int NEW = 187; // 0xBB + public static final int NEWARRAY = 188; // 0xBC + public static final int ANEWARRAY = 189; // 0xBD + public static final int CHECKCAST = 192; // 0xC0 + public static final int INSTANCEOF = 193; // 0xC1 + public static final int MULTIANEWARRAY = 197; // 0xC5 + + static boolean isInvoke(int opcode) { + switch (opcode) { + case INVOKEVIRTUAL: + case INVOKESPECIAL: + case INVOKESTATIC: + case INVOKEINTERFACE: + case INVOKEDYNAMIC: + return true; + default: + return false; + } + } + + /** + * See: {@code Rewriter::maybe_rewrite_invokehandle}. + */ + static boolean isInvokeHandleAlias(int opcode) { + switch (opcode) { + case INVOKEVIRTUAL: + case INVOKESPECIAL: + return true; + default: + return false; + } + } + } + + /** + * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and + * internal ones. + */ + private enum JVM_CONSTANT { + // @formatter:off + Utf8(config().jvmConstantUtf8), + Integer(config().jvmConstantInteger), + Long(config().jvmConstantLong), + Float(config().jvmConstantFloat), + Double(config().jvmConstantDouble), + Class(config().jvmConstantClass), + UnresolvedClass(config().jvmConstantUnresolvedClass), + UnresolvedClassInError(config().jvmConstantUnresolvedClassInError), + String(config().jvmConstantString), + Fieldref(config().jvmConstantFieldref), + MethodRef(config().jvmConstantMethodref), + InterfaceMethodref(config().jvmConstantInterfaceMethodref), + NameAndType(config().jvmConstantNameAndType), + MethodHandle(config().jvmConstantMethodHandle), + MethodHandleInError(config().jvmConstantMethodHandleInError), + MethodType(config().jvmConstantMethodType), + MethodTypeInError(config().jvmConstantMethodTypeInError), + InvokeDynamic(config().jvmConstantInvokeDynamic); + // @formatter:on + + private final int tag; + + private static final int ExternalMax = config().jvmConstantExternalMax; + private static final int InternalMin = config().jvmConstantInternalMin; + private static final int InternalMax = config().jvmConstantInternalMax; + + private JVM_CONSTANT(int tag) { + this.tag = tag; + } + + private static HotSpotVMConfig config() { + return runtime().getConfig(); + } + + /** + * Maps JVM_CONSTANT tags to {@link JVM_CONSTANT} values. Using a separate class for lazy + * initialization. + */ + static class TagValueMap { + private static final JVM_CONSTANT[] table = new JVM_CONSTANT[ExternalMax + 1 + (InternalMax - InternalMin) + 1]; + + static { + assert InternalMin > ExternalMax; + for (JVM_CONSTANT e : values()) { + table[indexOf(e.tag)] = e; + } + } + + private static int indexOf(int tag) { + if (tag >= InternalMin) { + return tag - InternalMin + ExternalMax + 1; + } else { + assert tag <= ExternalMax; + } + return tag; + } + + static JVM_CONSTANT get(int tag) { + JVM_CONSTANT res = table[indexOf(tag)]; + if (res != null) { + return res; + } + throw new JVMCIError("Unknown JVM_CONSTANT tag %s", tag); + } + } + + public static JVM_CONSTANT getEnum(int tag) { + return TagValueMap.get(tag); + } + } + + private static class LookupTypeCacheElement { + int lastCpi = Integer.MIN_VALUE; + JavaType javaType; + + public LookupTypeCacheElement(int lastCpi, JavaType javaType) { + super(); + this.lastCpi = lastCpi; + this.javaType = javaType; + } + } + + /** + * Reference to the C++ ConstantPool object. + */ + private final long metaspaceConstantPool; + private volatile LookupTypeCacheElement lastLookupType; + + /** + * Gets the JVMCI mirror from a HotSpot constant pool.The VM is responsible for ensuring that + * the ConstantPool is kept alive for the duration of this call and the + * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. + * + * Called from the VM. + * + * @param metaspaceConstantPool a metaspace ConstantPool object + * @return the {@link HotSpotConstantPool} corresponding to {@code metaspaceConstantPool} + */ + @SuppressWarnings("unused") + private static HotSpotConstantPool fromMetaspace(long metaspaceConstantPool) { + return new HotSpotConstantPool(metaspaceConstantPool); + } + + private HotSpotConstantPool(long metaspaceConstantPool) { + this.metaspaceConstantPool = metaspaceConstantPool; + } + + /** + * Gets the holder for this constant pool as {@link HotSpotResolvedObjectTypeImpl}. + * + * @return holder for this constant pool + */ + private HotSpotResolvedObjectType getHolder() { + return runtime().getCompilerToVM().getResolvedJavaType(this, runtime().getConfig().constantPoolHolderOffset, false); + } + + /** + * Converts a raw index from the bytecodes to a constant pool index by adding a + * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}. + * + * @param rawIndex index from the bytecode + * @param opcode bytecode to convert the index for + * @return constant pool index + */ + private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) { + int index; + if (opcode == Bytecodes.INVOKEDYNAMIC) { + index = rawIndex; + // See: ConstantPool::is_invokedynamic_index + assert index < 0 : "not an invokedynamic constant pool index " + index; + } else { + assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE || + opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + opcode; + index = rawIndex + runtime().getConfig().constantPoolCpCacheIndexTag; + } + return index; + } + + /** + * Decode a constant pool cache index to a constant pool index. + * + * See {@code ConstantPool::decode_cpcache_index}. + * + * @param index constant pool cache index + * @return decoded index + */ + private static int decodeConstantPoolCacheIndex(int index) { + if (isInvokedynamicIndex(index)) { + return decodeInvokedynamicIndex(index); + } else { + return index - runtime().getConfig().constantPoolCpCacheIndexTag; + } + } + + /** + * See {@code ConstantPool::is_invokedynamic_index}. + */ + private static boolean isInvokedynamicIndex(int index) { + return index < 0; + } + + /** + * See {@code ConstantPool::decode_invokedynamic_index}. + */ + private static int decodeInvokedynamicIndex(int i) { + assert isInvokedynamicIndex(i) : i; + return ~i; + } + + public long getMetaspaceConstantPool() { + return metaspaceConstantPool; + } + + public long getMetaspacePointer() { + return getMetaspaceConstantPool(); + } + + /** + * Gets the constant pool tag at index {@code index}. + * + * @param index constant pool index + * @return constant pool tag + */ + private JVM_CONSTANT getTagAt(int index) { + assertBounds(index); + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset); + final int tag = UNSAFE.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index); + if (tag == 0) { + return null; + } + return JVM_CONSTANT.getEnum(tag); + } + + /** + * Gets the constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return constant pool entry + */ + private long getEntryAt(int index) { + assertBounds(index); + return UNSAFE.getAddress(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the integer constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return integer constant pool entry at index + */ + private int getIntAt(int index) { + assertTag(index, JVM_CONSTANT.Integer); + return UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the long constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return long constant pool entry + */ + private long getLongAt(int index) { + assertTag(index, JVM_CONSTANT.Long); + return UNSAFE.getLong(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the float constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return float constant pool entry + */ + private float getFloatAt(int index) { + assertTag(index, JVM_CONSTANT.Float); + return UNSAFE.getFloat(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the double constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return float constant pool entry + */ + private double getDoubleAt(int index) { + assertTag(index, JVM_CONSTANT.Double); + return UNSAFE.getDouble(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return {@code JVM_CONSTANT_NameAndType} constant pool entry + */ + private int getNameAndTypeAt(int index) { + assertTag(index, JVM_CONSTANT.NameAndType); + return UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + } + + /** + * Gets the {@code JVM_CONSTANT_NameAndType} reference index constant pool entry at index + * {@code index}. + * + * @param index constant pool index + * @return {@code JVM_CONSTANT_NameAndType} reference constant pool entry + */ + private int getNameAndTypeRefIndexAt(int index) { + return runtime().getCompilerToVM().lookupNameAndTypeRefIndexInPool(this, index); + } + + /** + * Gets the name of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by another + * entry denoted by {@code which}. + * + * @param which constant pool index or constant pool cache index + * @return name as {@link String} + */ + private String getNameOf(int which) { + return runtime().getCompilerToVM().lookupNameInPool(this, which); + } + + /** + * Gets the name reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry at + * index {@code index}. + * + * @param index constant pool index + * @return name reference index + */ + private int getNameRefIndexAt(int index) { + final int refIndex = getNameAndTypeAt(index); + // name ref index is in the low 16-bits. + return refIndex & 0xFFFF; + } + + /** + * Gets the signature of a {@code JVM_CONSTANT_NameAndType} constant pool entry referenced by + * another entry denoted by {@code which}. + * + * @param which constant pool index or constant pool cache index + * @return signature as {@link String} + */ + private String getSignatureOf(int which) { + return runtime().getCompilerToVM().lookupSignatureInPool(this, which); + } + + /** + * Gets the signature reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry + * at index {@code index}. + * + * @param index constant pool index + * @return signature reference index + */ + private int getSignatureRefIndexAt(int index) { + final int refIndex = getNameAndTypeAt(index); + // signature ref index is in the high 16-bits. + return refIndex >>> 16; + } + + /** + * Gets the klass reference index constant pool entry at index {@code index}. + * + * @param index constant pool index + * @return klass reference index + */ + private int getKlassRefIndexAt(int index) { + return runtime().getCompilerToVM().lookupKlassRefIndexInPool(this, index); + } + + /** + * Gets the uncached klass reference index constant pool entry at index {@code index}. See: + * {@code ConstantPool::uncached_klass_ref_index_at}. + * + * @param index constant pool index + * @return klass reference index + */ + private int getUncachedKlassRefIndexAt(int index, JVM_CONSTANT tag) { + int resultIndex; + if (tag == JVM_CONSTANT.MethodRef || tag == JVM_CONSTANT.Fieldref || tag == JVM_CONSTANT.InterfaceMethodref) { + assertTagIsFieldOrMethod(index); + final int refIndex = UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); + // klass ref index is in the low 16-bits. + resultIndex = refIndex & 0xFFFF; + } else { + resultIndex = index; + } + + // Read the tag only once because it could change between multiple reads. + final JVM_CONSTANT klassTag = getTagAt(resultIndex); + assert klassTag == JVM_CONSTANT.Class || klassTag == JVM_CONSTANT.UnresolvedClass || klassTag == JVM_CONSTANT.UnresolvedClassInError : klassTag; + + return resultIndex; + } + + /** + * Asserts that the constant pool index {@code index} is in the bounds of the constant pool. + * + * @param index constant pool index + */ + private void assertBounds(int index) { + assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length(); + } + + /** + * Asserts that the constant pool tag at index {@code index} is equal to {@code tag}. + * + * @param index constant pool index + * @param tag expected tag + */ + private void assertTag(int index, JVM_CONSTANT tag) { + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; + } + + /** + * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref}, + * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}. + * + * @param index constant pool index + */ + private void assertTagIsFieldOrMethod(int index) { + final JVM_CONSTANT tagAt = getTagAt(index); + assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt; + } + + @Override + public int length() { + return UNSAFE.getInt(getMetaspaceConstantPool() + runtime().getConfig().constantPoolLengthOffset); + } + + @Override + public Object lookupConstant(int cpi) { + assert cpi != 0; + final JVM_CONSTANT tag = getTagAt(cpi); + switch (tag) { + case Integer: + return JavaConstant.forInt(getIntAt(cpi)); + case Long: + return JavaConstant.forLong(getLongAt(cpi)); + case Float: + return JavaConstant.forFloat(getFloatAt(cpi)); + case Double: + return JavaConstant.forDouble(getDoubleAt(cpi)); + case Class: + case UnresolvedClass: + case UnresolvedClassInError: + final int opcode = -1; // opcode is not used + return lookupType(cpi, opcode); + case String: + /* + * Normally, we would expect a String here, but anonymous classes can have + * "pseudo strings" (arbitrary live objects) patched into a String entry. Such + * entries do not have a symbol in the constant pool slot. + */ + Object string = runtime().getCompilerToVM().resolvePossiblyCachedConstantInPool(this, cpi); + return HotSpotObjectConstantImpl.forObject(string); + case MethodHandle: + case MethodHandleInError: + case MethodType: + case MethodTypeInError: + Object obj = runtime().getCompilerToVM().resolveConstantInPool(this, cpi); + return HotSpotObjectConstantImpl.forObject(obj); + default: + throw new JVMCIError("Unknown constant pool tag %s", tag); + } + } + + @Override + public String lookupUtf8(int cpi) { + assertTag(cpi, JVM_CONSTANT.Utf8); + return runtime().getCompilerToVM().getSymbol(getEntryAt(cpi)); + } + + @Override + public Signature lookupSignature(int cpi) { + return new HotSpotSignature(runtime(), lookupUtf8(cpi)); + } + + @Override + public JavaConstant lookupAppendix(int cpi, int opcode) { + assert Bytecodes.isInvoke(opcode); + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + Object appendix = runtime().getCompilerToVM().lookupAppendixInPool(this, index); + if (appendix == null) { + return null; + } else { + return HotSpotObjectConstantImpl.forObject(appendix); + } + } + + /** + * Gets a {@link JavaType} corresponding a given resolved or unresolved type. + * + * @param type either a ResolvedJavaType or a String naming a unresolved type. + */ + private static JavaType getJavaType(final Object type) { + if (type instanceof String) { + String name = (String) type; + return HotSpotUnresolvedJavaType.create(runtime(), "L" + name + ";"); + } else { + return (JavaType) type; + } + } + + @Override + public JavaMethod lookupMethod(int cpi, int opcode) { + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final HotSpotResolvedJavaMethod method = runtime().getCompilerToVM().lookupMethodInPool(this, index, (byte) opcode); + if (method != null) { + return method; + } else { + // Get the method's name and signature. + String name = getNameOf(index); + HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureOf(index)); + if (opcode == Bytecodes.INVOKEDYNAMIC) { + HotSpotResolvedObjectType holder = HotSpotResolvedObjectTypeImpl.fromObjectClass(MethodHandle.class); + return new HotSpotMethodUnresolved(name, signature, holder); + } else { + final int klassIndex = getKlassRefIndexAt(index); + final Object type = runtime().getCompilerToVM().lookupKlassInPool(this, klassIndex); + JavaType holder = getJavaType(type); + return new HotSpotMethodUnresolved(name, signature, holder); + } + } + } + + @Override + public JavaType lookupType(int cpi, int opcode) { + final LookupTypeCacheElement elem = this.lastLookupType; + if (elem != null && elem.lastCpi == cpi) { + return elem.javaType; + } else { + final Object type = runtime().getCompilerToVM().lookupKlassInPool(this, cpi); + JavaType result = getJavaType(type); + if (result instanceof ResolvedJavaType) { + this.lastLookupType = new LookupTypeCacheElement(cpi, result); + } + return result; + } + } + + @Override + public JavaField lookupField(int cpi, int opcode) { + final int index = rawIndexToConstantPoolIndex(cpi, opcode); + final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index); + final int nameIndex = getNameRefIndexAt(nameAndTypeIndex); + String name = lookupUtf8(nameIndex); + final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex); + String typeName = lookupUtf8(typeIndex); + JavaType type = runtime().lookupType(typeName, getHolder(), false); + + final int holderIndex = getKlassRefIndexAt(index); + JavaType holder = lookupType(holderIndex, opcode); + + if (holder instanceof HotSpotResolvedObjectTypeImpl) { + long[] info = new long[2]; + HotSpotResolvedObjectTypeImpl resolvedHolder; + try { + resolvedHolder = runtime().getCompilerToVM().resolveFieldInPool(this, index, (byte) opcode, info); + } catch (Throwable t) { + /* + * If there was an exception resolving the field we give up and return an unresolved + * field. + */ + return new HotSpotUnresolvedField(holder, name, type); + } + final int flags = (int) info[0]; + final long offset = info[1]; + HotSpotResolvedJavaField result = resolvedHolder.createField(name, type, offset, flags); + return result; + } else { + return new HotSpotUnresolvedField(holder, name, type); + } + } + + @Override + @SuppressWarnings("fallthrough") + public void loadReferencedType(int cpi, int opcode) { + int index; + switch (opcode) { + case Bytecodes.CHECKCAST: + case Bytecodes.INSTANCEOF: + case Bytecodes.NEW: + case Bytecodes.ANEWARRAY: + case Bytecodes.MULTIANEWARRAY: + case Bytecodes.LDC: + case Bytecodes.LDC_W: + case Bytecodes.LDC2_W: + index = cpi; + break; + case Bytecodes.INVOKEDYNAMIC: { + // invokedynamic instructions point to a constant pool cache entry. + index = decodeConstantPoolCacheIndex(cpi) + runtime().getConfig().constantPoolCpCacheIndexTag; + index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); + break; + } + case Bytecodes.GETSTATIC: + case Bytecodes.PUTSTATIC: + case Bytecodes.GETFIELD: + case Bytecodes.PUTFIELD: + case Bytecodes.INVOKEVIRTUAL: + case Bytecodes.INVOKESPECIAL: + case Bytecodes.INVOKESTATIC: + case Bytecodes.INVOKEINTERFACE: { + // invoke and field instructions point to a constant pool cache entry. + index = rawIndexToConstantPoolIndex(cpi, opcode); + index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(this, index); + break; + } + default: + throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); + } + + final JVM_CONSTANT tag = getTagAt(index); + if (tag == null) { + assert getTagAt(index - 1) == JVM_CONSTANT.Double || getTagAt(index - 1) == JVM_CONSTANT.Long; + return; + } + switch (tag) { + case MethodRef: + case Fieldref: + case InterfaceMethodref: + case Class: + case UnresolvedClass: + case UnresolvedClassInError: + index = getUncachedKlassRefIndexAt(index, tag); + final HotSpotResolvedObjectTypeImpl type = runtime().getCompilerToVM().resolveTypeInPool(this, index); + Class klass = type.mirror(); + if (!klass.isPrimitive() && !klass.isArray()) { + UNSAFE.ensureClassInitialized(klass); + } + switch (tag) { + case MethodRef: + if (Bytecodes.isInvokeHandleAlias(opcode)) { + final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode); + if (isInvokeHandle(methodRefCacheIndex, type)) { + runtime().getCompilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex); + } + } + } + break; + case InvokeDynamic: + if (isInvokedynamicIndex(cpi)) { + runtime().getCompilerToVM().resolveInvokeDynamicInPool(this, cpi); + } + break; + default: + // nothing + break; + } + } + + private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) { + assertTag(runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); + return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameOf(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess()); + } + + @Override + public String toString() { + HotSpotResolvedObjectType holder = getHolder(); + return "HotSpotConstantPool<" + holder.toJavaName() + ">"; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider.Options.*; + +import java.lang.reflect.*; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.options.*; + +/** + * HotSpot implementation of {@link ConstantReflectionProvider}. + */ +public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified { + + static class Options { + //@formatter:off + @Option(help = "Constant fold final fields with default values.", type = OptionType.Debug) + public static final OptionValue TrustFinalDefaultFields = new OptionValue<>(true); + //@formatter:on + } + + protected final HotSpotJVMCIRuntimeProvider runtime; + protected final HotSpotMethodHandleAccessProvider methodHandleAccess; + protected final HotSpotMemoryAccessProviderImpl memoryAccess; + + public HotSpotConstantReflectionProvider(HotSpotJVMCIRuntimeProvider runtime) { + this.runtime = runtime; + this.methodHandleAccess = new HotSpotMethodHandleAccessProvider(this); + this.memoryAccess = new HotSpotMemoryAccessProviderImpl(runtime); + } + + public MethodHandleAccessProvider getMethodHandleAccess() { + return methodHandleAccess; + } + + @Override + public MemoryAccessProvider getMemoryAccessProvider() { + return memoryAccess; + } + + @Override + public boolean isEmbeddable(Constant constant) { + return true; + } + + @Override + public Boolean constantEquals(Constant x, Constant y) { + if (x == y) { + return true; + } else if (x instanceof HotSpotObjectConstantImpl) { + return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).object() == ((HotSpotObjectConstantImpl) y).object(); + } else { + return x.equals(y); + } + } + + @Override + public Integer readArrayLength(JavaConstant array) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return null; + } + + Object arrayObject = ((HotSpotObjectConstantImpl) array).object(); + if (!arrayObject.getClass().isArray()) { + return null; + } + return Array.getLength(arrayObject); + } + + public JavaConstant readConstantArrayElement(JavaConstant array, int index) { + if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) { + JavaConstant element = readArrayElement(array, index); + if (element != null && (((HotSpotObjectConstantImpl) array).isDefaultStable() || !element.isDefaultForKind())) { + return element; + } + } + return null; + } + + /** + * Try to convert {@code offset} into an an index into {@code array}. + * + * @return the computed index or -1 if the offset isn't within the array + */ + private int indexForOffset(JavaConstant array, long offset) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return -1; + } + Class componentType = ((HotSpotObjectConstantImpl) array).object().getClass().getComponentType(); + JavaKind kind = runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(componentType).getJavaKind(); + int arraybase = runtime.getArrayBaseOffset(kind); + int scale = runtime.getArrayIndexScale(kind); + if (offset < arraybase) { + return -1; + } + long index = offset - arraybase; + if (index % scale != 0) { + return -1; + } + long result = index / scale; + if (result >= Integer.MAX_VALUE) { + return -1; + } + return (int) result; + } + + public JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset) { + if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) { + return readConstantArrayElement(array, indexForOffset(array, offset)); + } + return null; + } + + @Override + public JavaConstant readArrayElement(JavaConstant array, int index) { + if (array.getJavaKind() != JavaKind.Object || array.isNull()) { + return null; + } + Object a = ((HotSpotObjectConstantImpl) array).object(); + + if (index < 0 || index >= Array.getLength(a)) { + return null; + } + + if (a instanceof Object[]) { + Object element = ((Object[]) a)[index]; + if (((HotSpotObjectConstantImpl) array).getStableDimension() > 1) { + return HotSpotObjectConstantImpl.forStableArray(element, ((HotSpotObjectConstantImpl) array).getStableDimension() - 1, ((HotSpotObjectConstantImpl) array).isDefaultStable()); + } else { + return HotSpotObjectConstantImpl.forObject(element); + } + } else { + return JavaConstant.forBoxedPrimitive(Array.get(a, index)); + } + } + + /** + * Check if the constant is a boxed value that is guaranteed to be cached by the platform. + * Otherwise the generated code might be the only reference to the boxed value and since object + * references from nmethods are weak this can cause GC problems. + * + * @param source + * @return true if the box is cached + */ + private static boolean isBoxCached(JavaConstant source) { + switch (source.getJavaKind()) { + case Boolean: + return true; + case Char: + return source.asInt() <= 127; + case Byte: + case Short: + case Int: + return source.asInt() >= -128 && source.asInt() <= 127; + case Long: + return source.asLong() >= -128 && source.asLong() <= 127; + case Float: + case Double: + return false; + default: + throw new IllegalArgumentException("unexpected kind " + source.getJavaKind()); + } + } + + @Override + public JavaConstant boxPrimitive(JavaConstant source) { + if (!source.getJavaKind().isPrimitive() || !isBoxCached(source)) { + return null; + } + return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive()); + } + + @Override + public JavaConstant unboxPrimitive(JavaConstant source) { + if (!source.getJavaKind().isObject()) { + return null; + } + if (source.isNull()) { + return null; + } + return JavaConstant.forBoxedPrimitive(((HotSpotObjectConstantImpl) source).object()); + } + + public JavaConstant forString(String value) { + return HotSpotObjectConstantImpl.forObject(value); + } + + @Override + public ResolvedJavaType asJavaType(Constant constant) { + if (constant instanceof HotSpotObjectConstant) { + Object obj = ((HotSpotObjectConstantImpl) constant).object(); + if (obj instanceof Class) { + return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType((Class) obj); + } + } + if (constant instanceof HotSpotMetaspaceConstant) { + Object obj = HotSpotMetaspaceConstantImpl.getMetaspaceObject(constant); + if (obj instanceof HotSpotResolvedObjectTypeImpl) { + return (ResolvedJavaType) obj; + } + } + return null; + } + + private static final String SystemClassName = "Ljava/lang/System;"; + + /** + * Determines if a static field is constant for the purpose of + * {@link #readConstantFieldValue(JavaField, JavaConstant)}. + */ + protected boolean isStaticFieldConstant(HotSpotResolvedJavaField staticField) { + if (staticField.isFinal() || staticField.isStable()) { + ResolvedJavaType holder = staticField.getDeclaringClass(); + if (holder.isInitialized() && !holder.getName().equals(SystemClassName)) { + return true; + } + } + return false; + } + + /** + * Determines if a value read from a {@code final} instance field is considered constant. The + * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is + * not the {@link JavaConstant#isDefaultForKind default value} for its kind or if + * {@link Options#TrustFinalDefaultFields} is true. + * + * @param value a value read from a {@code final} instance field + * @param receiverClass the {@link Object#getClass() class} of object from which the + * {@code value} was read + */ + protected boolean isFinalInstanceFieldValueConstant(JavaConstant value, Class receiverClass) { + return !value.isDefaultForKind() || TrustFinalDefaultFields.getValue(); + } + + /** + * Determines if a value read from a {@link Stable} instance field is considered constant. The + * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is + * not the {@link JavaConstant#isDefaultForKind default value} for its kind. + * + * @param value a value read from a {@link Stable} field + * @param receiverClass the {@link Object#getClass() class} of object from which the + * {@code value} was read + */ + protected boolean isStableInstanceFieldValueConstant(JavaConstant value, Class receiverClass) { + return !value.isDefaultForKind(); + } + + /** + * {@inheritDoc} + *

+ * The {@code value} field in {@link OptionValue} is considered constant if the type of + * {@code receiver} is (assignable to) {@link StableOptionValue}. + */ + public JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + + if (hotspotField.isStatic()) { + if (isStaticFieldConstant(hotspotField)) { + JavaConstant value = readFieldValue(field, receiver); + if (hotspotField.isFinal() || !value.isDefaultForKind()) { + return value; + } + } + } else { + /* + * for non-static final fields, we must assume that they are only initialized if they + * have a non-default value. + */ + Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object(); + + // Canonicalization may attempt to process an unsafe read before + // processing a guard (e.g. a null check or a type check) for this read + // so we need to check the object being read + if (object != null) { + if (hotspotField.isFinal()) { + if (hotspotField.isInObject(object)) { + JavaConstant value = readFieldValue(field, receiver); + if (isFinalInstanceFieldValueConstant(value, object.getClass())) { + return value; + } + } + } else if (hotspotField.isStable()) { + if (hotspotField.isInObject(object)) { + JavaConstant value = readFieldValue(field, receiver); + if (isStableInstanceFieldValueConstant(value, object.getClass())) { + return value; + } + } + } else { + Class clazz = object.getClass(); + if (StableOptionValue.class.isAssignableFrom(clazz)) { + if (hotspotField.isInObject(object) && hotspotField.getName().equals("value")) { + StableOptionValue option = (StableOptionValue) object; + return HotSpotObjectConstantImpl.forObject(option.getValue()); + } + } + } + } + } + return null; + } + + public JavaConstant readFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + if (!hotspotField.isStable()) { + return readNonStableFieldValue(field, receiver); + } else { + return readStableFieldValue(field, receiver, false); + } + } + + private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) { + HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field; + if (hotspotField.isStatic()) { + HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass(); + if (holder.isInitialized()) { + return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset()); + } + } else { + if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) { + return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), receiver, hotspotField.offset()); + } + } + return null; + } + + public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) { + JavaConstant fieldValue = readNonStableFieldValue(field, receiver); + if (fieldValue.isNonNull()) { + JavaType declaredType = field.getType(); + if (declaredType.getComponentType() != null) { + int stableDimension = getArrayDimension(declaredType); + return HotSpotObjectConstantImpl.forStableArray(((HotSpotObjectConstantImpl) fieldValue).object(), stableDimension, isDefaultStable); + } + } + return fieldValue; + } + + private static int getArrayDimension(JavaType type) { + int dimensions = 0; + JavaType componentType = type; + while ((componentType = componentType.getComponentType()) != null) { + dimensions++; + } + return dimensions; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +public class HotSpotForeignCallTarget { + + /** + * The entry point address of this call's target. + */ + protected long address; + + public HotSpotForeignCallTarget(long address) { + this.address = address; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.inittimer.SuppressFBWarnings; +import sun.misc.Unsafe; + +/** + * Implementation of {@link InstalledCode} for HotSpot. + */ +public abstract class HotSpotInstalledCode extends InstalledCode { + + /** + * Total size of the code blob. + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int size; + + /** + * Start address of the code. + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private long codeStart; + + /** + * Size of the code. + */ + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int codeSize; + + public HotSpotInstalledCode(String name) { + super(name); + } + + /** + * @return the total size of this code blob + */ + public int getSize() { + return size; + } + + /** + * @return a copy of this code blob if it is {@linkplain #isValid() valid}, null otherwise. + */ + public byte[] getBlob() { + if (!isValid()) { + return null; + } + byte[] blob = new byte[size]; + UNSAFE.copyMemory(null, getAddress(), blob, Unsafe.ARRAY_BYTE_BASE_OFFSET, size); + return blob; + } + + @Override + public abstract String toString(); + + @Override + public long getStart() { + return codeStart; + } + + @Override + public long getCodeSize() { + return codeSize; + } + + @Override + public byte[] getCode() { + if (!isValid()) { + return null; + } + byte[] code = new byte[codeSize]; + UNSAFE.copyMemory(null, codeStart, code, Unsafe.ARRAY_BYTE_BASE_OFFSET, codeSize); + return code; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.runtime.*; + +public interface HotSpotJVMCIBackendFactory { + + JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntimeProvider runtime, CompilerFactory compilerFactory, JVMCIBackend host); + + /** + * Gets the CPU architecture of this backend. + */ + String getArchitecture(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.compiler.Compiler; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; +import jdk.vm.ci.service.*; + +final class HotSpotJVMCICompilerConfig { + + private static class DummyCompilerFactory implements CompilerFactory, Compiler { + + public void compileMethod(ResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { + throw new JVMCIError("no JVMCI compiler selected"); + } + + public String getCompilerName() { + return ""; + } + + public Architecture initializeArchitecture(Architecture arch) { + return arch; + } + + public Compiler createCompiler(JVMCIRuntime runtime) { + return this; + } + } + + private static CompilerFactory compilerFactory; + + /** + * Selects the system compiler. + * + * Called from VM. This method has an object return type to allow it to be called with a VM + * utility function used to call other static initialization methods. + */ + static Boolean selectCompiler(String compilerName) { + assert compilerFactory == null; + for (CompilerFactory factory : Services.load(CompilerFactory.class)) { + if (factory.getCompilerName().equals(compilerName)) { + compilerFactory = factory; + return Boolean.TRUE; + } + } + + throw new JVMCIError("JVMCI compiler '%s' not found", compilerName); + } + + static CompilerFactory getCompilerFactory() { + if (compilerFactory == null) { + compilerFactory = new DummyCompilerFactory(); + } + return compilerFactory; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import java.lang.ref.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * This class manages the set of metadata roots that must be scanned during garbage collection. + * Because of class redefinition Method* and ConstantPool* can be freed if they don't appear to be + * in use so they must be tracked when there are live references to them from Java. + * + * The general theory of operation is that all {@link MetaspaceWrapperObject}s are created by + * calling into the VM which calls back out to actually create the wrapper instance. During the call + * the VM keeps the metadata reference alive through the use of metadata handles. Once the call + * completes the wrapper object is registered here and will be scanned during metadata scanning. The + * weakness of the reference to the wrapper object allows them to be reclaimed when they are no + * longer used. + * + */ +public class HotSpotJVMCIMetaAccessContext implements JVMCIMetaAccessContext { + + /** + * The set of currently live contexts used for tracking of live metadata. Examined from the VM + * during garbage collection. + */ + private static WeakReference[] allContexts = new WeakReference[0]; + + /** + * This is a chunked list of metadata roots. It can be read from VM native code so it's been + * marked volatile to ensure the order of updates are respected. + */ + private volatile Object[] metadataRoots; + + private ChunkedList> list = new ChunkedList<>(); + + /** + * The number of weak references freed since the last time the list was shrunk. + */ + private int freed; + + /** + * The {@link ReferenceQueue} tracking the weak references created by this context. + */ + private final ReferenceQueue queue = new ReferenceQueue<>(); + + static synchronized void add(HotSpotJVMCIMetaAccessContext context) { + for (int i = 0; i < allContexts.length; i++) { + if (allContexts[i] == null || allContexts[i].get() == null) { + allContexts[i] = new WeakReference<>(context); + return; + } + } + int index = allContexts.length; + allContexts = Arrays.copyOf(allContexts, index + 2); + allContexts[index] = new WeakReference<>(context); + } + + HotSpotJVMCIMetaAccessContext() { + add(this); + } + + /** + * Periodically trim the list of tracked metadata. A new list is created to replace the old to + * avoid concurrent scanning issues. + */ + private void clean() { + Reference ref = queue.poll(); + if (ref == null) { + return; + } + while (ref != null) { + freed++; + ref = queue.poll(); + } + if (freed > list.size() / 2) { + ChunkedList> newList = new ChunkedList<>(); + for (WeakReference element : list) { + /* + * The referent could become null anywhere in here but it doesn't matter. It will + * get cleaned up next time. + */ + if (element != null && element.get() != null) { + newList.add(element); + } + } + list = newList; + metadataRoots = list.getHead(); + freed = 0; + } + } + + /** + * Add a {@link MetaspaceWrapperObject} to tracked by the GC. It's assumed that the caller is + * responsible for keeping the reference alive for the duration of the call. Once registration + * is complete then the VM will ensure it's kept alive. + * + * @param metaspaceObject + */ + + public synchronized void add(MetaspaceWrapperObject metaspaceObject) { + clean(); + list.add(new WeakReference<>(metaspaceObject, queue)); + if (list.getHead() != metadataRoots) { + /* + * The list enlarged so update the head. + */ + metadataRoots = list.getHead(); + } + } + + protected ResolvedJavaType createClass(Class javaClass) { + if (javaClass.isPrimitive()) { + JavaKind kind = JavaKind.fromJavaClass(javaClass); + return new HotSpotResolvedPrimitiveType(kind); + } else { + return new HotSpotResolvedObjectTypeImpl(javaClass, this); + } + } + + private final Map, WeakReference> typeMap = new WeakHashMap<>(); + + @Override + public synchronized ResolvedJavaType fromClass(Class javaClass) { + WeakReference typeRef = typeMap.get(javaClass); + ResolvedJavaType type = typeRef != null ? typeRef.get() : null; + if (type == null) { + type = createClass(javaClass); + typeMap.put(javaClass, new WeakReference<>(type)); + } + return type; + } + + /** + * A very simple append only chunked list implementation. + */ + static class ChunkedList implements Iterable { + private static final int CHUNK_SIZE = 32; + + private static final int NEXT_CHUNK_INDEX = CHUNK_SIZE - 1; + + private Object[] head; + private int index; + private int size; + + ChunkedList() { + head = new Object[CHUNK_SIZE]; + index = 0; + } + + void add(T element) { + if (index == NEXT_CHUNK_INDEX) { + Object[] newHead = new Object[CHUNK_SIZE]; + newHead[index] = head; + head = newHead; + index = 0; + } + head[index++] = element; + size++; + } + + Object[] getHead() { + return head; + } + + public Iterator iterator() { + return new ChunkIterator<>(); + } + + int size() { + return size; + } + + class ChunkIterator implements Iterator { + + ChunkIterator() { + currentChunk = head; + currentIndex = -1; + findNext(); + } + + Object[] currentChunk; + int currentIndex; + V next; + + @SuppressWarnings("unchecked") + V findNext() { + V result; + do { + currentIndex++; + if (currentIndex == NEXT_CHUNK_INDEX) { + currentChunk = (Object[]) currentChunk[currentIndex]; + currentIndex = 0; + if (currentChunk == null) { + return null; + } + } + result = (V) currentChunk[currentIndex]; + } while (result == null); + return result; + } + + public boolean hasNext() { + return next != null; + } + + public V next() { + V result = next; + next = findNext(); + return result; + } + + } + + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.inittimer.InitTimer.*; + +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.compiler.*; +import jdk.vm.ci.compiler.Compiler; +import jdk.vm.ci.inittimer.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; +import jdk.vm.ci.service.*; + +//JaCoCo Exclude + +public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, HotSpotProxified { + + /** + * The proper initialization of this class is complex because it's tangled up with the + * initialization of the JVMCI and really should only ever be triggered through + * {@link JVMCI#getRuntime}. However since {@link #runtime} can also be called directly it + * should also trigger proper initialization. To ensure proper ordering, the static initializer + * of this class initializes {@link JVMCI} and then access to {@link DelayedInit#instance} + * triggers the final initialization of the {@link HotSpotJVMCIRuntime}. + */ + static { + JVMCI.initialize(); + } + + @SuppressWarnings("try") + static class DelayedInit { + private static final HotSpotJVMCIRuntime instance; + + static { + try (InitTimer t0 = timer("HotSpotJVMCIRuntime.")) { + try (InitTimer t = timer("StartupEventListener.beforeJVMCIStartup")) { + for (StartupEventListener l : Services.load(StartupEventListener.class)) { + l.beforeJVMCIStartup(); + } + } + + try (InitTimer t = timer("HotSpotJVMCIRuntime.")) { + instance = new HotSpotJVMCIRuntime(); + } + + try (InitTimer t = timer("HotSpotJVMCIRuntime.completeInitialization")) { + instance.completeInitialization(); + } + } + } + } + + /** + * Gets the singleton {@link HotSpotJVMCIRuntime} object. + */ + public static HotSpotJVMCIRuntime runtime() { + assert DelayedInit.instance != null; + return DelayedInit.instance; + } + + /** + * Do deferred initialization. + */ + public void completeInitialization() { + compiler = HotSpotJVMCICompilerConfig.getCompilerFactory().createCompiler(this); + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + vmEventListener.completeInitialization(this); + } + } + + public static HotSpotJVMCIBackendFactory findFactory(String architecture) { + for (HotSpotJVMCIBackendFactory factory : Services.load(HotSpotJVMCIBackendFactory.class)) { + if (factory.getArchitecture().equalsIgnoreCase(architecture)) { + return factory; + } + } + + throw new JVMCIError("No JVMCI runtime available for the %s architecture", architecture); + } + + /** + * Gets the kind of a word value on the {@linkplain #getHostJVMCIBackend() host} backend. + */ + public static JavaKind getHostWordKind() { + return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordKind; + } + + protected final CompilerToVM compilerToVm; + + protected final HotSpotVMConfig config; + private final JVMCIBackend hostBackend; + + private Compiler compiler; + protected final JVMCIMetaAccessContext metaAccessContext; + + private final Map, JVMCIBackend> backends = new HashMap<>(); + + private final Iterable vmEventListeners; + + @SuppressWarnings("try") + private HotSpotJVMCIRuntime() { + compilerToVm = new CompilerToVM(); + try (InitTimer t = timer("HotSpotVMConfig")) { + config = new HotSpotVMConfig(compilerToVm); + } + + String hostArchitecture = config.getHostArchitectureName(); + + HotSpotJVMCIBackendFactory factory; + try (InitTimer t = timer("find factory:", hostArchitecture)) { + factory = findFactory(hostArchitecture); + } + + CompilerFactory compilerFactory = HotSpotJVMCICompilerConfig.getCompilerFactory(); + + try (InitTimer t = timer("create JVMCI backend:", hostArchitecture)) { + hostBackend = registerBackend(factory.createJVMCIBackend(this, compilerFactory, null)); + } + + vmEventListeners = Services.load(HotSpotVMEventListener.class); + + JVMCIMetaAccessContext context = null; + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + context = vmEventListener.createMetaAccessContext(this); + if (context != null) { + break; + } + } + if (context == null) { + context = new HotSpotJVMCIMetaAccessContext(); + } + metaAccessContext = context; + } + + private JVMCIBackend registerBackend(JVMCIBackend backend) { + Class arch = backend.getCodeCache().getTarget().arch.getClass(); + JVMCIBackend oldValue = backends.put(arch, backend); + assert oldValue == null : "cannot overwrite existing backend for architecture " + arch.getSimpleName(); + return backend; + } + + public ResolvedJavaType fromClass(Class javaClass) { + return metaAccessContext.fromClass(javaClass); + } + + public HotSpotVMConfig getConfig() { + return config; + } + + public CompilerToVM getCompilerToVM() { + return compilerToVm; + } + + public JVMCIMetaAccessContext getMetaAccessContext() { + return metaAccessContext; + } + + public Compiler getCompiler() { + return compiler; + } + + public JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve) { + Objects.requireNonNull(accessingType, "cannot resolve type without an accessing class"); + // If the name represents a primitive type we can short-circuit the lookup. + if (name.length() == 1) { + JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); + return fromClass(kind.toJavaClass()); + } + + // Resolve non-primitive types in the VM. + HotSpotResolvedObjectTypeImpl hsAccessingType = (HotSpotResolvedObjectTypeImpl) accessingType; + final HotSpotResolvedObjectTypeImpl klass = compilerToVm.lookupType(name, hsAccessingType.mirror(), resolve); + + if (klass == null) { + assert resolve == false; + return HotSpotUnresolvedJavaType.create(this, name); + } + return klass; + } + + public JVMCIBackend getHostJVMCIBackend() { + return hostBackend; + } + + public JVMCIBackend getJVMCIBackend(Class arch) { + assert arch != Architecture.class; + return backends.get(arch); + } + + public Map, JVMCIBackend> getBackends() { + return Collections.unmodifiableMap(backends); + } + + /** + * Called from the VM. + */ + @SuppressWarnings({"unused"}) + private void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long jvmciEnv, int id) { + compiler.compileMethod(method, entryBCI, jvmciEnv, id); + } + + /** + * Shuts down the runtime. + * + * Called from the VM. + */ + @SuppressWarnings({"unused"}) + private void shutdown() throws Exception { + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + vmEventListener.notifyShutdown(); + } + } + + /** + * Notify on successful install into the CodeCache. + * + * @param hotSpotCodeCacheProvider + * @param installedCode + * @param compResult + */ + void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) { + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { + vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compResult); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntimeProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntimeProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.compiler.Compiler; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; +import sun.misc.*; + +//JaCoCo Exclude + +/** + * Configuration information for the HotSpot JVMCI runtime. + */ +public interface HotSpotJVMCIRuntimeProvider extends JVMCIRuntime { + + HotSpotVMConfig getConfig(); + + CompilerToVM getCompilerToVM(); + + Compiler getCompiler(); + + /** + * Converts a name to a Java type. This method attempts to resolve {@code name} to a + * {@link ResolvedJavaType}. + * + * @param name a well formed Java type in {@linkplain JavaType#getName() internal} format + * @param accessingType the context of resolution which must be non-null + * @param resolve specifies whether resolution failure results in an unresolved type being + * return or a {@link LinkageError} being thrown + * @return a Java type for {@code name} which is guaranteed to be of type + * {@link ResolvedJavaType} if {@code resolve == true} + * @throws LinkageError if {@code resolve == true} and the resolution failed + * @throws NullPointerException if {@code accessingClass} is {@code null} + */ + JavaType lookupType(String name, HotSpotResolvedObjectType accessingType, boolean resolve); + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + ResolvedJavaType fromClass(Class clazz); + + JVMCIMetaAccessContext getMetaAccessContext(); + + /** + * The offset from the origin of an array to the first element. + * + * @return the offset in bytes + */ + default int getArrayBaseOffset(JavaKind kind) { + switch (kind) { + case Boolean: + return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; + case Byte: + return Unsafe.ARRAY_BYTE_BASE_OFFSET; + case Char: + return Unsafe.ARRAY_CHAR_BASE_OFFSET; + case Short: + return Unsafe.ARRAY_SHORT_BASE_OFFSET; + case Int: + return Unsafe.ARRAY_INT_BASE_OFFSET; + case Long: + return Unsafe.ARRAY_LONG_BASE_OFFSET; + case Float: + return Unsafe.ARRAY_FLOAT_BASE_OFFSET; + case Double: + return Unsafe.ARRAY_DOUBLE_BASE_OFFSET; + case Object: + return Unsafe.ARRAY_OBJECT_BASE_OFFSET; + default: + throw new JVMCIError("%s", kind); + } + } + + /** + * The scale used for the index when accessing elements of an array of this kind. + * + * @return the scale in order to convert the index into a byte offset + */ + default int getArrayIndexScale(JavaKind kind) { + switch (kind) { + case Boolean: + return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; + case Byte: + return Unsafe.ARRAY_BYTE_INDEX_SCALE; + case Char: + return Unsafe.ARRAY_CHAR_INDEX_SCALE; + case Short: + return Unsafe.ARRAY_SHORT_INDEX_SCALE; + case Int: + return Unsafe.ARRAY_INT_INDEX_SCALE; + case Long: + return Unsafe.ARRAY_LONG_INDEX_SCALE; + case Float: + return Unsafe.ARRAY_FLOAT_INDEX_SCALE; + case Double: + return Unsafe.ARRAY_DOUBLE_INDEX_SCALE; + case Object: + return Unsafe.ARRAY_OBJECT_INDEX_SCALE; + default: + throw new JVMCIError("%s", kind); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJavaType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJavaType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Common base class for all HotSpot {@link JavaType} implementations. + */ +public abstract class HotSpotJavaType implements JavaType { + + private final String name; + + public HotSpotJavaType(String name) { + this.name = name; + } + + @Override + public final String getName() { + return name; + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.hotspot.HotSpotVMConfig.*; +import jdk.vm.ci.meta.*; + +/** + * HotSpot specific extension of {@link MemoryAccessProvider}. + */ +public interface HotSpotMemoryAccessProvider extends MemoryAccessProvider { + + JavaConstant readNarrowOopConstant(Constant base, long displacement, CompressEncoding encoding); + + Constant readKlassPointerConstant(Constant base, long displacement); + + Constant readNarrowKlassPointerConstant(Constant base, long displacement, CompressEncoding encoding); + + Constant readMethodPointerConstant(Constant base, long displacement); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.common.JVMCIError; +import jdk.vm.ci.hotspot.HotSpotVMConfig.CompressEncoding; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MemoryAccessProvider; +import jdk.vm.ci.meta.PrimitiveConstant; + +/** + * HotSpot implementation of {@link MemoryAccessProvider}. + */ +public class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider, HotSpotProxified { + + protected final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotMemoryAccessProviderImpl(HotSpotJVMCIRuntimeProvider runtime) { + this.runtime = runtime; + } + + private static Object asObject(Constant base) { + if (base instanceof HotSpotObjectConstantImpl) { + return ((HotSpotObjectConstantImpl) base).object(); + } else { + return null; + } + } + + private boolean isValidObjectFieldDisplacement(Constant base, long displacement) { + if (base instanceof HotSpotMetaspaceConstant) { + Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { + if (displacement == runtime.getConfig().classMirrorOffset) { + // Klass::_java_mirror is valid for all Klass* values + return true; + } + } else { + throw new JVMCIError("%s", metaspaceObject); + } + } + return false; + } + + private static long asRawPointer(Constant base) { + if (base instanceof HotSpotMetaspaceConstant) { + return ((HotSpotMetaspaceConstant) base).rawValue(); + } else if (base instanceof PrimitiveConstant) { + PrimitiveConstant prim = (PrimitiveConstant) base; + if (prim.getJavaKind().isNumericInteger()) { + return prim.asLong(); + } + } + throw new JVMCIError("%s", base); + } + + private static long readRawValue(Constant baseConstant, long displacement, int bits) { + Object base = asObject(baseConstant); + if (base != null) { + switch (bits) { + case 8: + return UNSAFE.getByte(base, displacement); + case 16: + return UNSAFE.getShort(base, displacement); + case 32: + return UNSAFE.getInt(base, displacement); + case 64: + return UNSAFE.getLong(base, displacement); + default: + throw new JVMCIError("%d", bits); + } + } else { + long pointer = asRawPointer(baseConstant); + switch (bits) { + case 8: + return UNSAFE.getByte(pointer + displacement); + case 16: + return UNSAFE.getShort(pointer + displacement); + case 32: + return UNSAFE.getInt(pointer + displacement); + case 64: + return UNSAFE.getLong(pointer + displacement); + default: + throw new JVMCIError("%d", bits); + } + } + } + + private boolean verifyReadRawObject(Object expected, Constant base, long displacement, boolean compressed) { + if (compressed == runtime.getConfig().useCompressedOops) { + Object obj = asObject(base); + if (obj != null) { + assert expected == UNSAFE.getObject(obj, displacement) : "readUnsafeOop doesn't agree with unsafe.getObject"; + } + } + if (base instanceof HotSpotMetaspaceConstant) { + Object metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); + if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { + if (displacement == runtime.getConfig().classMirrorOffset) { + assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror(); + } + } + } + return true; + } + + private Object readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) { + long displacement = initialDisplacement; + + Object ret; + Object base = asObject(baseConstant); + if (base == null) { + assert !compressed; + displacement += asRawPointer(baseConstant); + ret = runtime.getCompilerToVM().readUncompressedOop(displacement); + } else { + assert runtime.getConfig().useCompressedOops == compressed; + ret = UNSAFE.getObject(base, displacement); + } + assert verifyReadRawObject(ret, baseConstant, initialDisplacement, compressed); + return ret; + } + + @Override + public JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant baseConstant, long displacement) { + if (kind == JavaKind.Object) { + Object o = readRawObject(baseConstant, displacement, runtime.getConfig().useCompressedOops); + return HotSpotObjectConstantImpl.forObject(o); + } else { + return readPrimitiveConstant(kind, baseConstant, displacement, kind.getByteCount() * 8); + } + } + + @Override + public JavaConstant readPrimitiveConstant(JavaKind kind, Constant baseConstant, long initialDisplacement, int bits) { + try { + long rawValue = readRawValue(baseConstant, initialDisplacement, bits); + switch (kind) { + case Boolean: + return JavaConstant.forBoolean(rawValue != 0); + case Byte: + return JavaConstant.forByte((byte) rawValue); + case Char: + return JavaConstant.forChar((char) rawValue); + case Short: + return JavaConstant.forShort((short) rawValue); + case Int: + return JavaConstant.forInt((int) rawValue); + case Long: + return JavaConstant.forLong(rawValue); + case Float: + return JavaConstant.forFloat(Float.intBitsToFloat((int) rawValue)); + case Double: + return JavaConstant.forDouble(Double.longBitsToDouble(rawValue)); + default: + throw new JVMCIError("Unsupported kind: %s", kind); + } + } catch (NullPointerException e) { + return null; + } + } + + @Override + public JavaConstant readObjectConstant(Constant base, long displacement) { + if (!isValidObjectFieldDisplacement(base, displacement)) { + return null; + } + return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, false)); + } + + @Override + public JavaConstant readNarrowOopConstant(Constant base, long displacement, CompressEncoding encoding) { + assert encoding.equals(runtime.getConfig().getOopEncoding()) : "unexpected oop encoding: " + encoding + " != " + runtime.getConfig().getOopEncoding(); + return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, true), true); + } + + private HotSpotResolvedObjectTypeImpl readKlass(Constant base, long displacement, boolean compressed) { + assert (base instanceof HotSpotMetaspaceConstantImpl) || (base instanceof HotSpotObjectConstantImpl) : base.getClass(); + Object baseObject = (base instanceof HotSpotMetaspaceConstantImpl) ? ((HotSpotMetaspaceConstantImpl) base).asResolvedJavaType() : ((HotSpotObjectConstantImpl) base).object(); + return runtime.getCompilerToVM().getResolvedJavaType(baseObject, displacement, compressed); + } + + @Override + public Constant readKlassPointerConstant(Constant base, long displacement) { + HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, false); + if (klass == null) { + return JavaConstant.NULL_POINTER; + } + TargetDescription target = runtime.getHostJVMCIBackend().getCodeCache().getTarget(); + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(target.wordKind, klass.getMetaspaceKlass(), klass, false); + } + + @Override + public Constant readNarrowKlassPointerConstant(Constant base, long displacement, CompressEncoding encoding) { + HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, true); + if (klass == null) { + return HotSpotCompressedNullConstant.COMPRESSED_NULL; + } + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(JavaKind.Int, encoding.compress(klass.getMetaspaceKlass()), klass, true); + } + + @Override + public Constant readMethodPointerConstant(Constant base, long displacement) { + TargetDescription target = runtime.getHostJVMCIBackend().getCodeCache().getTarget(); + assert (base instanceof HotSpotObjectConstantImpl); + Object baseObject = ((HotSpotObjectConstantImpl) base).object(); + HotSpotResolvedJavaMethodImpl method = runtime.getCompilerToVM().getResolvedJavaMethod(baseObject, displacement); + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(target.wordKind, method.getMetaspaceMethod(), method, false); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.reflect.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +// JaCoCo Exclude + +/** + * HotSpot implementation of {@link MetaAccessProvider}. + */ +public class HotSpotMetaAccessProvider implements MetaAccessProvider, HotSpotProxified { + + protected final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotMetaAccessProvider(HotSpotJVMCIRuntimeProvider runtime) { + this.runtime = runtime; + } + + public ResolvedJavaType lookupJavaType(Class clazz) { + if (clazz == null) { + throw new IllegalArgumentException("Class parameter was null"); + } + return runtime.fromClass(clazz); + } + + public HotSpotResolvedObjectType lookupJavaType(JavaConstant constant) { + if (constant.isNull() || !(constant instanceof HotSpotObjectConstant)) { + return null; + } + return ((HotSpotObjectConstant) constant).getType(); + } + + public Signature parseMethodDescriptor(String signature) { + return new HotSpotSignature(runtime, signature); + } + + /** + * {@link Field} object of {@link Method#slot}. + */ + private Field reflectionMethodSlot = getReflectionSlotField(Method.class); + + /** + * {@link Field} object of {@link Constructor#slot}. + */ + private Field reflectionConstructorSlot = getReflectionSlotField(Constructor.class); + + private static Field getReflectionSlotField(Class reflectionClass) { + try { + Field field = reflectionClass.getDeclaredField("slot"); + field.setAccessible(true); + return field; + } catch (NoSuchFieldException | SecurityException e) { + throw new JVMCIError(e); + } + } + + public ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod) { + try { + Class holder = reflectionMethod.getDeclaringClass(); + Field slotField = reflectionMethod instanceof Constructor ? reflectionConstructorSlot : reflectionMethodSlot; + final int slot = slotField.getInt(reflectionMethod); + return runtime.getCompilerToVM().getResolvedJavaMethodAtSlot(holder, slot); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new JVMCIError(e); + } + } + + public ResolvedJavaField lookupJavaField(Field reflectionField) { + String name = reflectionField.getName(); + Class fieldHolder = reflectionField.getDeclaringClass(); + Class fieldType = reflectionField.getType(); + // java.lang.reflect.Field's modifiers should be enough here since VM internal modifier bits + // are not used (yet). + final int modifiers = reflectionField.getModifiers(); + final long offset = Modifier.isStatic(modifiers) ? UNSAFE.staticFieldOffset(reflectionField) : UNSAFE.objectFieldOffset(reflectionField); + + HotSpotResolvedObjectType holder = fromObjectClass(fieldHolder); + JavaType type = runtime.fromClass(fieldType); + + if (offset != -1) { + HotSpotResolvedObjectType resolved = holder; + return resolved.createField(name, type, offset, modifiers); + } else { + throw new JVMCIError("unresolved field %s", reflectionField); + } + } + + private static int intMaskRight(int n) { + assert n <= 32; + return n == 32 ? -1 : (1 << n) - 1; + } + + @Override + public JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId) { + HotSpotVMConfig config = runtime.getConfig(); + int actionValue = convertDeoptAction(action); + int reasonValue = convertDeoptReason(reason); + int debugValue = debugId & intMaskRight(config.deoptimizationDebugIdBits); + JavaConstant c = JavaConstant.forInt(~((debugValue << config.deoptimizationDebugIdShift) | (reasonValue << config.deoptimizationReasonShift) | (actionValue << config.deoptimizationActionShift))); + assert c.asInt() < 0; + return c; + } + + public DeoptimizationReason decodeDeoptReason(JavaConstant constant) { + HotSpotVMConfig config = runtime.getConfig(); + int reasonValue = ((~constant.asInt()) >> config.deoptimizationReasonShift) & intMaskRight(config.deoptimizationReasonBits); + DeoptimizationReason reason = convertDeoptReason(reasonValue); + return reason; + } + + public DeoptimizationAction decodeDeoptAction(JavaConstant constant) { + HotSpotVMConfig config = runtime.getConfig(); + int actionValue = ((~constant.asInt()) >> config.deoptimizationActionShift) & intMaskRight(config.deoptimizationActionBits); + DeoptimizationAction action = convertDeoptAction(actionValue); + return action; + } + + public int decodeDebugId(JavaConstant constant) { + HotSpotVMConfig config = runtime.getConfig(); + return ((~constant.asInt()) >> config.deoptimizationDebugIdShift) & intMaskRight(config.deoptimizationDebugIdBits); + } + + public int convertDeoptAction(DeoptimizationAction action) { + HotSpotVMConfig config = runtime.getConfig(); + switch (action) { + case None: + return config.deoptActionNone; + case RecompileIfTooManyDeopts: + return config.deoptActionMaybeRecompile; + case InvalidateReprofile: + return config.deoptActionReinterpret; + case InvalidateRecompile: + return config.deoptActionMakeNotEntrant; + case InvalidateStopCompiling: + return config.deoptActionMakeNotCompilable; + default: + throw new JVMCIError("%s", action); + } + } + + public DeoptimizationAction convertDeoptAction(int action) { + HotSpotVMConfig config = runtime.getConfig(); + if (action == config.deoptActionNone) { + return DeoptimizationAction.None; + } + if (action == config.deoptActionMaybeRecompile) { + return DeoptimizationAction.RecompileIfTooManyDeopts; + } + if (action == config.deoptActionReinterpret) { + return DeoptimizationAction.InvalidateReprofile; + } + if (action == config.deoptActionMakeNotEntrant) { + return DeoptimizationAction.InvalidateRecompile; + } + if (action == config.deoptActionMakeNotCompilable) { + return DeoptimizationAction.InvalidateStopCompiling; + } + throw new JVMCIError("%d", action); + } + + public int convertDeoptReason(DeoptimizationReason reason) { + HotSpotVMConfig config = runtime.getConfig(); + switch (reason) { + case None: + return config.deoptReasonNone; + case NullCheckException: + return config.deoptReasonNullCheck; + case BoundsCheckException: + return config.deoptReasonRangeCheck; + case ClassCastException: + return config.deoptReasonClassCheck; + case ArrayStoreException: + return config.deoptReasonArrayCheck; + case UnreachedCode: + return config.deoptReasonUnreached0; + case TypeCheckedInliningViolated: + return config.deoptReasonTypeCheckInlining; + case OptimizedTypeCheckViolated: + return config.deoptReasonOptimizedTypeCheck; + case NotCompiledExceptionHandler: + return config.deoptReasonNotCompiledExceptionHandler; + case Unresolved: + return config.deoptReasonUnresolved; + case JavaSubroutineMismatch: + return config.deoptReasonJsrMismatch; + case ArithmeticException: + return config.deoptReasonDiv0Check; + case RuntimeConstraint: + return config.deoptReasonConstraint; + case LoopLimitCheck: + return config.deoptReasonLoopLimitCheck; + case Aliasing: + return config.deoptReasonAliasing; + case TransferToInterpreter: + return config.deoptReasonTransferToInterpreter; + default: + throw new JVMCIError("%s", reason); + } + } + + public DeoptimizationReason convertDeoptReason(int reason) { + HotSpotVMConfig config = runtime.getConfig(); + if (reason == config.deoptReasonNone) { + return DeoptimizationReason.None; + } + if (reason == config.deoptReasonNullCheck) { + return DeoptimizationReason.NullCheckException; + } + if (reason == config.deoptReasonRangeCheck) { + return DeoptimizationReason.BoundsCheckException; + } + if (reason == config.deoptReasonClassCheck) { + return DeoptimizationReason.ClassCastException; + } + if (reason == config.deoptReasonArrayCheck) { + return DeoptimizationReason.ArrayStoreException; + } + if (reason == config.deoptReasonUnreached0) { + return DeoptimizationReason.UnreachedCode; + } + if (reason == config.deoptReasonTypeCheckInlining) { + return DeoptimizationReason.TypeCheckedInliningViolated; + } + if (reason == config.deoptReasonOptimizedTypeCheck) { + return DeoptimizationReason.OptimizedTypeCheckViolated; + } + if (reason == config.deoptReasonNotCompiledExceptionHandler) { + return DeoptimizationReason.NotCompiledExceptionHandler; + } + if (reason == config.deoptReasonUnresolved) { + return DeoptimizationReason.Unresolved; + } + if (reason == config.deoptReasonJsrMismatch) { + return DeoptimizationReason.JavaSubroutineMismatch; + } + if (reason == config.deoptReasonDiv0Check) { + return DeoptimizationReason.ArithmeticException; + } + if (reason == config.deoptReasonConstraint) { + return DeoptimizationReason.RuntimeConstraint; + } + if (reason == config.deoptReasonLoopLimitCheck) { + return DeoptimizationReason.LoopLimitCheck; + } + if (reason == config.deoptReasonAliasing) { + return DeoptimizationReason.Aliasing; + } + if (reason == config.deoptReasonTransferToInterpreter) { + return DeoptimizationReason.TransferToInterpreter; + } + throw new JVMCIError("%x", reason); + } + + @Override + public long getMemorySize(JavaConstant constant) { + if (constant.getJavaKind() == JavaKind.Object) { + HotSpotResolvedObjectType lookupJavaType = lookupJavaType(constant); + + if (lookupJavaType == null) { + return 0; + } else { + if (lookupJavaType.isArray()) { + // TODO(tw): Add compressed pointer support. + int length = Array.getLength(((HotSpotObjectConstantImpl) constant).object()); + ResolvedJavaType elementType = lookupJavaType.getComponentType(); + JavaKind elementKind = elementType.getJavaKind(); + final int headerSize = runtime.getArrayBaseOffset(elementKind); + TargetDescription target = runtime.getHostJVMCIBackend().getTarget(); + int sizeOfElement = target.getSizeInBytes(elementKind); + int alignment = target.wordSize; + int log2ElementSize = CodeUtil.log2(sizeOfElement); + return computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize); + } + return lookupJavaType.instanceSize(); + } + } else { + return constant.getJavaKind().getByteCount(); + } + } + + /** + * Computes the size of the memory chunk allocated for an array. This size accounts for the + * array header size, body size and any padding after the last element to satisfy object + * alignment requirements. + * + * @param length the number of elements in the array + * @param alignment the object alignment requirement + * @param headerSize the size of the array header + * @param log2ElementSize log2 of the size of an element in the array + */ + public static int computeArrayAllocationSize(int length, int alignment, int headerSize, int log2ElementSize) { + int size = (length << log2ElementSize) + headerSize + (alignment - 1); + int mask = ~(alignment - 1); + return size & mask; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +public class HotSpotMetaData { + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] pcDescBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] scopesDescBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] relocBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] exceptionBytes; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] oopMaps; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private String[] metadata; + + public byte[] pcDescBytes() { + return pcDescBytes != null ? pcDescBytes : new byte[0]; + } + + public byte[] scopesDescBytes() { + return scopesDescBytes != null ? scopesDescBytes : new byte[0]; + } + + public byte[] relocBytes() { + return relocBytes != null ? relocBytes : new byte[0]; + } + + public byte[] exceptionBytes() { + return exceptionBytes != null ? exceptionBytes : new byte[0]; + } + + public byte[] oopMaps() { + return oopMaps != null ? oopMaps : new byte[0]; + } + + public String[] metadataEntries() { + return metadata != null ? metadata : new String[0]; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.hotspot.HotSpotVMConfig.*; +import jdk.vm.ci.meta.*; + +public interface HotSpotMetaspaceConstant extends HotSpotConstant, VMConstant { + + Constant compress(CompressEncoding encoding); + + Constant uncompress(CompressEncoding encoding); + + HotSpotResolvedObjectType asResolvedJavaType(); + + HotSpotResolvedJavaMethod asResolvedJavaMethod(); + + long rawValue(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import java.util.*; + +import jdk.vm.ci.hotspot.HotSpotVMConfig.*; +import jdk.vm.ci.meta.*; + +public final class HotSpotMetaspaceConstantImpl extends PrimitiveConstant implements HotSpotMetaspaceConstant, VMConstant, HotSpotProxified { + + static HotSpotMetaspaceConstantImpl forMetaspaceObject(JavaKind kind, long primitive, Object metaspaceObject, boolean compressed) { + return new HotSpotMetaspaceConstantImpl(kind, primitive, metaspaceObject, compressed); + } + + static Object getMetaspaceObject(Constant constant) { + return ((HotSpotMetaspaceConstantImpl) constant).metaspaceObject; + } + + private final Object metaspaceObject; + private final boolean compressed; + + private HotSpotMetaspaceConstantImpl(JavaKind kind, long primitive, Object metaspaceObject, boolean compressed) { + super(kind, primitive); + this.metaspaceObject = metaspaceObject; + this.compressed = compressed; + } + + @Override + public int hashCode() { + return super.hashCode() ^ System.identityHashCode(metaspaceObject); + } + + @Override + public boolean equals(Object o) { + return o == this || (o instanceof HotSpotMetaspaceConstantImpl && super.equals(o) && Objects.equals(metaspaceObject, ((HotSpotMetaspaceConstantImpl) o).metaspaceObject)); + } + + @Override + public String toString() { + return super.toString() + "{" + metaspaceObject + (compressed ? ";compressed}" : "}"); + } + + public boolean isCompressed() { + return compressed; + } + + public JavaConstant compress(CompressEncoding encoding) { + assert !isCompressed(); + HotSpotMetaspaceConstantImpl res = HotSpotMetaspaceConstantImpl.forMetaspaceObject(JavaKind.Int, encoding.compress(asLong()), metaspaceObject, true); + assert res.isCompressed(); + return res; + } + + public JavaConstant uncompress(CompressEncoding encoding) { + assert isCompressed(); + HotSpotMetaspaceConstantImpl res = HotSpotMetaspaceConstantImpl.forMetaspaceObject(JavaKind.Long, encoding.uncompress(asInt()), metaspaceObject, false); + assert !res.isCompressed(); + return res; + } + + public HotSpotResolvedObjectType asResolvedJavaType() { + if (metaspaceObject instanceof HotSpotResolvedObjectType) { + return (HotSpotResolvedObjectType) metaspaceObject; + } + return null; + } + + public HotSpotResolvedJavaMethod asResolvedJavaMethod() { + if (metaspaceObject instanceof HotSpotResolvedJavaMethod) { + return (HotSpotResolvedJavaMethod) metaspaceObject; + } + return null; + } + + public long rawValue() { + return asLong(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static java.util.FormattableFlags.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +public abstract class HotSpotMethod implements JavaMethod, Formattable /* , JavaMethodContex */{ + + public static String applyFormattingFlagsAndWidth(String s, int flags, int width) { + if (flags == 0 && width < 0) { + return s; + } + StringBuilder sb = new StringBuilder(s); + + // apply width and justification + int len = sb.length(); + if (len < width) { + for (int i = 0; i < width - len; i++) { + if ((flags & LEFT_JUSTIFY) == LEFT_JUSTIFY) { + sb.append(' '); + } else { + sb.insert(0, ' '); + } + } + } + + String res = sb.toString(); + if ((flags & UPPERCASE) == UPPERCASE) { + res = res.toUpperCase(); + } + return res; + } + + protected String name; + + /** + * Controls whether {@link #toString()} includes the qualified or simple name of the class in + * which the method is declared. + */ + public static final boolean FULLY_QUALIFIED_METHOD_NAME = false; + + protected HotSpotMethod(String name) { + this.name = name; + } + + @Override + public final String getName() { + return name; + } + + @Override + public final String toString() { + char h = FULLY_QUALIFIED_METHOD_NAME ? 'H' : 'h'; + String suffix = this instanceof ResolvedJavaMethod ? "" : ", unresolved"; + String fmt = String.format("HotSpotMethod<%%%c.%%n(%%p)%s>", h, suffix); + return format(fmt); + } + + public void formatTo(Formatter formatter, int flags, int width, int precision) { + String base = (flags & ALTERNATE) == ALTERNATE ? getName() : toString(); + formatter.format(applyFormattingFlagsAndWidth(base, flags & ~ALTERNATE, width)); + } + + public JavaMethod asJavaMethod() { + return this; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,864 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static java.lang.String.*; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.util.*; + +import jdk.vm.ci.hotspot.HotSpotMethodDataAccessor.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.JavaMethodProfile.*; +import jdk.vm.ci.meta.JavaTypeProfile.*; +import sun.misc.*; + +/** + * Access to a HotSpot MethodData structure (defined in methodData.hpp). + */ +public final class HotSpotMethodData { + + private static final HotSpotVMConfig config = runtime().getConfig(); + private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(TriState.FALSE); + private static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR = new NoMethodData(TriState.UNKNOWN); + + // sorted by tag + // @formatter:off + private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = { + null, + new BitData(), + new CounterData(), + new JumpData(), + new TypeCheckData(), + new VirtualCallData(), + new RetData(), + new BranchData(), + new MultiBranchData(), + new ArgInfoData(), + null, // call_type_data_tag + null, // virtual_call_type_data_tag + null, // parameters_type_data_tag + null, // speculative_trap_data_tag + }; + // @formatter:on + + /** + * Reference to the C++ MethodData object. + */ + private final long metaspaceMethodData; + @SuppressWarnings("unused") private final HotSpotResolvedJavaMethodImpl method; + + public HotSpotMethodData(long metaspaceMethodData, HotSpotResolvedJavaMethodImpl method) { + this.metaspaceMethodData = metaspaceMethodData; + this.method = method; + } + + /** + * @return value of the MethodData::_data_size field + */ + private int normalDataSize() { + return UNSAFE.getInt(metaspaceMethodData + config.methodDataDataSize); + } + + /** + * Returns the size of the extra data records. This method does the same calculation as + * MethodData::extra_data_size(). + * + * @return size of extra data records + */ + private int extraDataSize() { + final int extraDataBase = config.methodDataOopDataOffset + normalDataSize(); + final int extraDataLimit = UNSAFE.getInt(metaspaceMethodData + config.methodDataSize); + return extraDataLimit - extraDataBase; + } + + public boolean hasNormalData() { + return normalDataSize() > 0; + } + + public boolean hasExtraData() { + return extraDataSize() > 0; + } + + public int getExtraDataBeginOffset() { + return normalDataSize(); + } + + public boolean isWithin(int position) { + return position >= 0 && position < normalDataSize() + extraDataSize(); + } + + public int getDeoptimizationCount(DeoptimizationReason reason) { + HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); + int reasonIndex = metaAccess.convertDeoptReason(reason); + return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; + } + + public int getOSRDeoptimizationCount(DeoptimizationReason reason) { + HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); + int reasonIndex = metaAccess.convertDeoptReason(reason); + return UNSAFE.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + config.deoptReasonOSROffset + reasonIndex) & 0xFF; + } + + public HotSpotMethodDataAccessor getNormalData(int position) { + if (position >= normalDataSize()) { + return null; + } + + HotSpotMethodDataAccessor result = getData(position); + assert result != null : "NO_DATA tag is not allowed"; + return result; + } + + public HotSpotMethodDataAccessor getExtraData(int position) { + if (position >= normalDataSize() + extraDataSize()) { + return null; + } + HotSpotMethodDataAccessor data = getData(position); + if (data != null) { + return data; + } + return data; + } + + public static HotSpotMethodDataAccessor getNoDataAccessor(boolean exceptionPossiblyNotRecorded) { + if (exceptionPossiblyNotRecorded) { + return NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR; + } else { + return NO_DATA_NO_EXCEPTION_ACCESSOR; + } + } + + private HotSpotMethodDataAccessor getData(int position) { + assert position >= 0 : "out of bounds"; + final Tag tag = AbstractMethodData.readTag(this, position); + HotSpotMethodDataAccessor accessor = PROFILE_DATA_ACCESSORS[tag.getValue()]; + assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag; + return accessor; + } + + private int readUnsignedByte(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return UNSAFE.getByte(metaspaceMethodData + fullOffsetInBytes) & 0xFF; + } + + private int readUnsignedShort(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return UNSAFE.getShort(metaspaceMethodData + fullOffsetInBytes) & 0xFFFF; + } + + /** + * Since the values are stored in cells (platform words) this method uses + * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. + */ + private long readUnsignedInt(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes) & 0xFFFFFFFFL; + } + + private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) { + long value = readUnsignedInt(position, offsetInBytes); + return truncateLongToInt(value); + } + + /** + * Since the values are stored in cells (platform words) this method uses + * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. + */ + private int readInt(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return (int) UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes); + } + + private HotSpotResolvedJavaMethod readMethod(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return runtime().compilerToVm.getResolvedJavaMethod(null, metaspaceMethodData + fullOffsetInBytes); + } + + private HotSpotResolvedObjectTypeImpl readKlass(int position, int offsetInBytes) { + long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); + return runtime().compilerToVm.getResolvedJavaType(null, metaspaceMethodData + fullOffsetInBytes, false); + } + + private static int truncateLongToInt(long value) { + return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value; + } + + private static int computeFullOffset(int position, int offsetInBytes) { + return config.methodDataOopDataOffset + position + offsetInBytes; + } + + private static int cellIndexToOffset(int cells) { + return config.dataLayoutHeaderSize + cellsToBytes(cells); + } + + private static int cellsToBytes(int cells) { + return cells * config.dataLayoutCellSize; + } + + /** + * Returns whether profiling ran long enough that the profile information is mature. Other + * informational data will still be valid even if the profile isn't mature. + */ + public boolean isProfileMature() { + return runtime().getCompilerToVM().isMature(metaspaceMethodData); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + String nl = String.format("%n"); + String nlIndent = String.format("%n%38s", ""); + if (hasNormalData()) { + int pos = 0; + HotSpotMethodDataAccessor data; + while ((data = getNormalData(pos)) != null) { + if (pos != 0) { + sb.append(nl); + } + int bci = data.getBCI(this, pos); + sb.append(String.format("%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); + sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); + pos = pos + data.getSize(this, pos); + } + } + + if (hasExtraData()) { + int pos = getExtraDataBeginOffset(); + HotSpotMethodDataAccessor data; + while ((data = getExtraData(pos)) != null) { + if (pos == getExtraDataBeginOffset()) { + sb.append(nl).append("--- Extra data:"); + } + int bci = data.getBCI(this, pos); + sb.append(String.format("%n%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); + sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); + pos = pos + data.getSize(this, pos); + } + + } + return sb.toString(); + } + + private abstract static class AbstractMethodData implements HotSpotMethodDataAccessor { + + /** + * Corresponds to {@code exception_seen_flag}. + */ + private static final int EXCEPTIONS_MASK = 0x2; + + private final Tag tag; + private final int staticSize; + + protected AbstractMethodData(Tag tag, int staticSize) { + this.tag = tag; + this.staticSize = staticSize; + } + + public Tag getTag() { + return tag; + } + + public static Tag readTag(HotSpotMethodData data, int position) { + final int tag = data.readUnsignedByte(position, config.dataLayoutTagOffset); + return Tag.getEnum(tag); + } + + @Override + public int getBCI(HotSpotMethodData data, int position) { + return data.readUnsignedShort(position, config.dataLayoutBCIOffset); + } + + @Override + public int getSize(HotSpotMethodData data, int position) { + return staticSize + getDynamicSize(data, position); + } + + @Override + public TriState getExceptionSeen(HotSpotMethodData data, int position) { + return TriState.get((getFlags(data, position) & EXCEPTIONS_MASK) != 0); + } + + @Override + public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { + return null; + } + + @Override + public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { + return null; + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { + return null; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public TriState getNullSeen(HotSpotMethodData data, int position) { + return TriState.UNKNOWN; + } + + protected int getFlags(HotSpotMethodData data, int position) { + return data.readUnsignedByte(position, config.dataLayoutFlagsOffset); + } + + /** + * @param data + * @param position + */ + protected int getDynamicSize(HotSpotMethodData data, int position) { + return 0; + } + + public abstract StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos); + } + + private static class NoMethodData extends AbstractMethodData { + + private static final int NO_DATA_SIZE = cellIndexToOffset(0); + + private final TriState exceptionSeen; + + protected NoMethodData(TriState exceptionSeen) { + super(Tag.No, NO_DATA_SIZE); + this.exceptionSeen = exceptionSeen; + } + + @Override + public int getBCI(HotSpotMethodData data, int position) { + return -1; + } + + @Override + public TriState getExceptionSeen(HotSpotMethodData data, int position) { + return exceptionSeen; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb; + } + } + + private static class BitData extends AbstractMethodData { + + private static final int BIT_DATA_SIZE = cellIndexToOffset(0); + private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01; + + private BitData() { + super(Tag.BitData, BIT_DATA_SIZE); + } + + protected BitData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public TriState getNullSeen(HotSpotMethodData data, int position) { + return TriState.get((getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("exception_seen(%s)", getExceptionSeen(data, pos))); + } + } + + private static class CounterData extends BitData { + + private static final int COUNTER_DATA_SIZE = cellIndexToOffset(1); + private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0); + + public CounterData() { + super(Tag.CounterData, COUNTER_DATA_SIZE); + } + + protected CounterData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return getCounterValue(data, position); + } + + protected int getCounterValue(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, COUNTER_DATA_COUNT_OFFSET); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("count(%d) null_seen(%s) exception_seen(%s)", getCounterValue(data, pos), getNullSeen(data, pos), getExceptionSeen(data, pos))); + } + } + + private static class JumpData extends AbstractMethodData { + + private static final int JUMP_DATA_SIZE = cellIndexToOffset(2); + protected static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(0); + protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1); + + public JumpData() { + super(Tag.JumpData, JUMP_DATA_SIZE); + } + + protected JumpData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + return getExecutionCount(data, position) != 0 ? 1 : 0; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET); + } + + public int getTakenDisplacement(HotSpotMethodData data, int position) { + return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("taken(%d) displacement(%d)", getExecutionCount(data, pos), getTakenDisplacement(data, pos))); + } + } + + static class RawItemProfile { + final int entries; + final T[] items; + final long[] counts; + final long totalCount; + + public RawItemProfile(int entries, T[] items, long[] counts, long totalCount) { + this.entries = entries; + this.items = items; + this.counts = counts; + this.totalCount = totalCount; + } + } + + private abstract static class AbstractTypeData extends CounterData { + + protected static final int TYPE_DATA_ROW_SIZE = cellsToBytes(2); + + protected static final int NONPROFILED_COUNT_OFFSET = cellIndexToOffset(1); + protected static final int TYPE_DATA_FIRST_TYPE_OFFSET = cellIndexToOffset(2); + protected static final int TYPE_DATA_FIRST_TYPE_COUNT_OFFSET = cellIndexToOffset(3); + + protected AbstractTypeData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { + return createTypeProfile(getNullSeen(data, position), getRawTypeProfile(data, position)); + } + + private RawItemProfile getRawTypeProfile(HotSpotMethodData data, int position) { + int typeProfileWidth = config.typeProfileWidth; + + ResolvedJavaType[] types = new ResolvedJavaType[typeProfileWidth]; + long[] counts = new long[typeProfileWidth]; + long totalCount = 0; + int entries = 0; + + outer: for (int i = 0; i < typeProfileWidth; i++) { + HotSpotResolvedObjectTypeImpl receiverKlass = data.readKlass(position, getTypeOffset(i)); + if (receiverKlass != null) { + HotSpotResolvedObjectTypeImpl klass = receiverKlass; + long count = data.readUnsignedInt(position, getTypeCountOffset(i)); + /* + * Because of races in the profile collection machinery it's possible for a + * class to appear multiple times so merge them to make the profile look + * rational. + */ + for (int j = 0; j < entries; j++) { + if (types[j].equals(klass)) { + totalCount += count; + counts[j] += count; + continue outer; + } + } + types[entries] = klass; + totalCount += count; + counts[entries] = count; + entries++; + } + } + + totalCount += getTypesNotRecordedExecutionCount(data, position); + return new RawItemProfile<>(entries, types, counts, totalCount); + } + + protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); + + private static JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile profile) { + if (profile.entries <= 0 || profile.totalCount <= 0) { + return null; + } + + ProfiledType[] ptypes = new ProfiledType[profile.entries]; + double totalProbability = 0.0; + for (int i = 0; i < profile.entries; i++) { + double p = profile.counts[i]; + p = p / profile.totalCount; + totalProbability += p; + ptypes[i] = new ProfiledType(profile.items[i], p); + } + + Arrays.sort(ptypes); + + double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); + assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth; + return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); + } + + private static int getTypeOffset(int row) { + return TYPE_DATA_FIRST_TYPE_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + protected static int getTypeCountOffset(int row) { + return TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + RawItemProfile profile = getRawTypeProfile(data, pos); + TriState nullSeen = getNullSeen(data, pos); + TriState exceptionSeen = getExceptionSeen(data, pos); + sb.append(format("count(%d) null_seen(%s) exception_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen, + getTypesNotRecordedExecutionCount(data, pos), profile.entries)); + for (int i = 0; i < profile.entries; i++) { + long count = profile.counts[i]; + sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount)); + } + return sb; + } + } + + private static class TypeCheckData extends AbstractTypeData { + + private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + + public TypeCheckData() { + super(Tag.ReceiverTypeData, TYPE_CHECK_DATA_SIZE); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + return -1; + } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); + } + } + + private static class VirtualCallData extends AbstractTypeData { + + private static final int VIRTUAL_CALL_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * (config.typeProfileWidth + config.methodProfileWidth); + private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET = TYPE_DATA_FIRST_TYPE_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; + + public VirtualCallData() { + super(Tag.VirtualCallData, VIRTUAL_CALL_DATA_SIZE); + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + final int typeProfileWidth = config.typeProfileWidth; + + long total = 0; + for (int i = 0; i < typeProfileWidth; i++) { + total += data.readUnsignedInt(position, getTypeCountOffset(i)); + } + + total += getCounterValue(data, position); + return truncateLongToInt(total); + } + + @Override + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return getCounterValue(data, position); + } + + private static long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) { + return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); + } + + @Override + public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { + return createMethodProfile(getRawMethodProfile(data, position)); + } + + private static RawItemProfile getRawMethodProfile(HotSpotMethodData data, int position) { + int profileWidth = config.methodProfileWidth; + + ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth]; + long[] counts = new long[profileWidth]; + long totalCount = 0; + int entries = 0; + + for (int i = 0; i < profileWidth; i++) { + HotSpotResolvedJavaMethod method = data.readMethod(position, getMethodOffset(i)); + if (method != null) { + methods[entries] = method; + long count = data.readUnsignedInt(position, getMethodCountOffset(i)); + totalCount += count; + counts[entries] = count; + + entries++; + } + } + + totalCount += getMethodsNotRecordedExecutionCount(data, position); + return new RawItemProfile<>(entries, methods, counts, totalCount); + } + + private static JavaMethodProfile createMethodProfile(RawItemProfile profile) { + if (profile.entries <= 0 || profile.totalCount <= 0) { + return null; + } + + ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries]; + double totalProbability = 0.0; + for (int i = 0; i < profile.entries; i++) { + double p = profile.counts[i]; + p = p / profile.totalCount; + totalProbability += p; + pmethods[i] = new ProfiledMethod(profile.items[i], p); + } + + Arrays.sort(pmethods); + + double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); + assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth; + return new JavaMethodProfile(notRecordedMethodProbability, pmethods); + } + + private static int getMethodOffset(int row) { + return VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + private static int getMethodCountOffset(int row) { + return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + RawItemProfile profile = getRawMethodProfile(data, pos); + super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries)); + for (int i = 0; i < profile.entries; i++) { + long count = profile.counts[i]; + sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount)); + } + return sb; + } + } + + private static class RetData extends CounterData { + + private static final int RET_DATA_ROW_SIZE = cellsToBytes(3); + private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth; + + public RetData() { + super(Tag.RetData, RET_DATA_SIZE); + } + } + + private static class BranchData extends JumpData { + + private static final int BRANCH_DATA_SIZE = cellIndexToOffset(3); + private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2); + + public BranchData() { + super(Tag.BranchData, BRANCH_DATA_SIZE); + } + + @Override + public double getBranchTakenProbability(HotSpotMethodData data, int position) { + long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET); + long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); + long total = takenCount + notTakenCount; + + return total <= 0 ? -1 : takenCount / (double) total; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); + return truncateLongToInt(count); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + long taken = data.readUnsignedInt(pos, TAKEN_COUNT_OFFSET); + long notTaken = data.readUnsignedInt(pos, NOT_TAKEN_COUNT_OFFSET); + double takenProbability = getBranchTakenProbability(data, pos); + return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); + } + } + + private static class ArrayData extends AbstractMethodData { + + private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(0); + protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(1); + + public ArrayData(Tag tag, int staticSize) { + super(tag, staticSize); + } + + @Override + protected int getDynamicSize(HotSpotMethodData data, int position) { + return cellsToBytes(getLength(data, position)); + } + + protected static int getLength(HotSpotMethodData data, int position) { + return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET); + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + return sb.append(format("length(%d)", getLength(data, pos))); + } + } + + private static class MultiBranchData extends ArrayData { + + private static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1); + private static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = 2; + private static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS); + private static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0); + private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1); + + public MultiBranchData() { + super(Tag.MultiBranchData, MULTI_BRANCH_DATA_SIZE); + } + + @Override + public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { + int arrayLength = getLength(data, position); + assert arrayLength > 0 : "switch must have at least the default case"; + assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + + int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + long totalCount = 0; + double[] result = new double[length]; + + // default case is first in HotSpot but last for the compiler + long count = readCount(data, position, 0); + totalCount += count; + result[length - 1] = count; + + for (int i = 1; i < length; i++) { + count = readCount(data, position, i); + totalCount += count; + result[i - 1] = count; + } + + if (totalCount <= 0) { + return null; + } else { + for (int i = 0; i < length; i++) { + result[i] = result[i] / totalCount; + } + return result; + } + } + + private static long readCount(HotSpotMethodData data, int position, int i) { + int offset; + long count; + offset = getCountOffset(i); + count = data.readUnsignedInt(position, offset); + return count; + } + + @Override + public int getExecutionCount(HotSpotMethodData data, int position) { + int arrayLength = getLength(data, position); + assert arrayLength > 0 : "switch must have at least the default case"; + assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; + + int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + long totalCount = 0; + for (int i = 0; i < length; i++) { + int offset = getCountOffset(i); + totalCount += data.readUnsignedInt(position, offset); + } + + return truncateLongToInt(totalCount); + } + + private static int getCountOffset(int index) { + return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + } + + private static int getDisplacementOffset(int index) { + return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; + } + + @Override + public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { + int entries = getLength(data, pos) / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; + sb.append(format("entries(%d)", entries)); + for (int i = 0; i < entries; i++) { + sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i)))); + } + return sb; + } + } + + private static class ArgInfoData extends ArrayData { + + private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1); + + public ArgInfoData() { + super(Tag.ArgInfoData, ARG_INFO_DATA_SIZE); + } + } + + public void setCompiledIRSize(int size) { + UNSAFE.putInt(metaspaceMethodData + config.methodDataIRSizeOffset, size); + } + + public int getCompiledIRSize() { + return UNSAFE.getInt(metaspaceMethodData + config.methodDataIRSizeOffset); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; + +import jdk.vm.ci.meta.*; + +/** + * Interface for accessor objects that encapsulate the logic for accessing the different kinds of + * data in a HotSpot methodDataOop. This interface is similar to the interface {@link ProfilingInfo} + * , but most methods require a MethodDataObject and the exact position within the methodData. + */ +public interface HotSpotMethodDataAccessor { + + /** + * {@code DataLayout} tag values. + */ + enum Tag { + No(config().dataLayoutNoTag), + BitData(config().dataLayoutBitDataTag), + CounterData(config().dataLayoutCounterDataTag), + JumpData(config().dataLayoutJumpDataTag), + ReceiverTypeData(config().dataLayoutReceiverTypeDataTag), + VirtualCallData(config().dataLayoutVirtualCallDataTag), + RetData(config().dataLayoutRetDataTag), + BranchData(config().dataLayoutBranchDataTag), + MultiBranchData(config().dataLayoutMultiBranchDataTag), + ArgInfoData(config().dataLayoutArgInfoDataTag), + CallTypeData(config().dataLayoutCallTypeDataTag), + VirtualCallTypeData(config().dataLayoutVirtualCallTypeDataTag), + ParametersTypeData(config().dataLayoutParametersTypeDataTag), + SpeculativeTrapData(config().dataLayoutSpeculativeTrapDataTag); + + private final int value; + + private Tag(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + private static HotSpotVMConfig config() { + return runtime().getConfig(); + } + + public static Tag getEnum(int value) { + Tag result = values()[value]; + assert value == result.value; + return result; + } + } + + /** + * Returns the {@link Tag} stored in the LayoutData header. + * + * @return tag stored in the LayoutData header + */ + Tag getTag(); + + /** + * Returns the BCI stored in the LayoutData header. + * + * @return An integer ≥ 0 and ≤ Short.MAX_VALUE, or -1 if not supported. + */ + int getBCI(HotSpotMethodData data, int position); + + /** + * Computes the size for the specific data at the given position. + * + * @return An integer > 0. + */ + int getSize(HotSpotMethodData data, int position); + + JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position); + + JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position); + + double getBranchTakenProbability(HotSpotMethodData data, int position); + + double[] getSwitchProbabilities(HotSpotMethodData data, int position); + + TriState getExceptionSeen(HotSpotMethodData data, int position); + + TriState getNullSeen(HotSpotMethodData data, int position); + + int getExecutionCount(HotSpotMethodData data, int position); + + StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +public class HotSpotMethodHandleAccessProvider implements MethodHandleAccessProvider, HotSpotProxified { + + private final ConstantReflectionProvider constantReflection; + + public HotSpotMethodHandleAccessProvider(ConstantReflectionProvider constantReflection) { + this.constantReflection = constantReflection; + } + + /** + * Lazy initialization to break class initialization cycle. Field and method lookup is only + * possible after the {@link HotSpotJVMCIRuntime} is fully initialized. + */ + static class LazyInitialization { + static final ResolvedJavaField methodHandleFormField; + static final ResolvedJavaField lambdaFormVmentryField; + static final ResolvedJavaMethod lambdaFormCompileToBytecodeMethod; + static final HotSpotResolvedJavaField memberNameVmtargetField; + + /** + * Search for an instance field with the given name in a class. + * + * @param className name of the class to search in + * @param fieldName name of the field to be searched + * @return resolved java field + * @throws ClassNotFoundException + */ + private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException { + Class clazz = Class.forName(className); + ResolvedJavaType type = runtime().fromClass(clazz); + ResolvedJavaField[] fields = type.getInstanceFields(false); + for (ResolvedJavaField field : fields) { + if (field.getName().equals(fieldName)) { + return field; + } + } + return null; + } + + private static ResolvedJavaMethod findMethodInClass(String className, String methodName) throws ClassNotFoundException { + Class clazz = Class.forName(className); + HotSpotResolvedObjectTypeImpl type = fromObjectClass(clazz); + ResolvedJavaMethod result = null; + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + assert result == null : "more than one method found: " + className + "." + methodName; + result = method; + } + } + assert result != null : "method not found: " + className + "." + methodName; + return result; + } + + static { + try { + methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form"); + lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry"); + lambdaFormCompileToBytecodeMethod = findMethodInClass("java.lang.invoke.LambdaForm", "compileToBytecode"); + memberNameVmtargetField = (HotSpotResolvedJavaField) findFieldInClass("java.lang.invoke.MemberName", "vmtarget"); + } catch (Throwable ex) { + throw new JVMCIError(ex); + } + } + } + + @Override + public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) { + int intrinsicId = ((HotSpotResolvedJavaMethodImpl) method).intrinsicId(); + if (intrinsicId != 0) { + return getMethodHandleIntrinsic(intrinsicId); + } + return null; + } + + public static IntrinsicMethod getMethodHandleIntrinsic(int intrinsicId) { + HotSpotVMConfig config = runtime().getConfig(); + if (intrinsicId == config.vmIntrinsicInvokeBasic) { + return IntrinsicMethod.INVOKE_BASIC; + } else if (intrinsicId == config.vmIntrinsicLinkToInterface) { + return IntrinsicMethod.LINK_TO_INTERFACE; + } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) { + return IntrinsicMethod.LINK_TO_SPECIAL; + } else if (intrinsicId == config.vmIntrinsicLinkToStatic) { + return IntrinsicMethod.LINK_TO_STATIC; + } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) { + return IntrinsicMethod.LINK_TO_VIRTUAL; + } + return null; + } + + @Override + public ResolvedJavaMethod resolveInvokeBasicTarget(JavaConstant methodHandle, boolean forceBytecodeGeneration) { + if (methodHandle.isNull()) { + return null; + } + + /* Load non-public field: LambdaForm MethodHandle.form */ + JavaConstant lambdaForm = constantReflection.readFieldValue(LazyInitialization.methodHandleFormField, methodHandle); + if (lambdaForm.isNull()) { + return null; + } + + JavaConstant memberName; + if (forceBytecodeGeneration) { + /* Invoke non-public method: MemberName LambdaForm.compileToBytecode() */ + memberName = LazyInitialization.lambdaFormCompileToBytecodeMethod.invoke(lambdaForm, new JavaConstant[0]); + } else { + /* Load non-public field: MemberName LambdaForm.vmentry */ + memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm); + } + return getTargetMethod(memberName); + } + + @Override + public ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName) { + return getTargetMethod(memberName); + } + + /** + * Returns the {@link ResolvedJavaMethod} for the vmtarget of a java.lang.invoke.MemberName. + */ + private static ResolvedJavaMethod getTargetMethod(JavaConstant memberName) { + if (memberName.isNull()) { + return null; + } + + Object object = ((HotSpotObjectConstantImpl) memberName).object(); + /* Read the ResolvedJavaMethod from the injected field MemberName.vmtarget */ + return runtime().compilerToVm.getResolvedJavaMethod(object, LazyInitialization.memberNameVmtargetField.offset()); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodUnresolved.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodUnresolved.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link JavaMethod} for unresolved HotSpot methods. + */ +public final class HotSpotMethodUnresolved extends HotSpotMethod { + + private final Signature signature; + protected JavaType holder; + + public HotSpotMethodUnresolved(String name, Signature signature, JavaType holder) { + super(name); + this.holder = holder; + this.signature = signature; + } + + @Override + public Signature getSignature() { + return signature; + } + + @Override + public JavaType getDeclaringClass() { + return holder; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof HotSpotMethodUnresolved)) { + return false; + } + HotSpotMethodUnresolved that = (HotSpotMethodUnresolved) obj; + return this.name.equals(that.name) && this.signature.equals(that.signature) && this.holder.equals(that.holder); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link InstalledCode} for code installed as an nmethod. The nmethod stores a + * weak reference to an instance of this class. This is necessary to keep the nmethod from being + * unloaded while the associated {@link HotSpotNmethod} instance is alive. + *

+ * Note that there is no (current) way for the reference from an nmethod to a {@link HotSpotNmethod} + * instance to be anything but weak. This is due to the fact that HotSpot does not treat nmethods as + * strong GC roots. + */ +public class HotSpotNmethod extends HotSpotInstalledCode { + + /** + * This (indirect) Method* reference is safe since class redefinition preserves all methods + * associated with nmethods in the code cache. + */ + private final HotSpotResolvedJavaMethod method; + + private final boolean isDefault; + private final boolean isExternal; + + public HotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault) { + this(method, name, isDefault, false); + } + + public HotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault, boolean isExternal) { + super(name); + this.method = method; + this.isDefault = isDefault; + this.isExternal = isExternal; + } + + public boolean isDefault() { + return isDefault; + } + + public boolean isExternal() { + return isExternal; + } + + public ResolvedJavaMethod getMethod() { + return method; + } + + @Override + public void invalidate() { + runtime().getCompilerToVM().invalidateInstalledCode(this); + } + + @Override + public String toString() { + return String.format("InstalledNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s]", method, getAddress(), isDefault, name); + } + + protected boolean checkThreeObjectArgs() { + assert method.getSignature().getParameterCount(!method.isStatic()) == 3; + assert method.getSignature().getParameterKind(0) == JavaKind.Object; + assert method.getSignature().getParameterKind(1) == JavaKind.Object; + assert !method.isStatic() || method.getSignature().getParameterKind(2) == JavaKind.Object; + return true; + } + + private boolean checkArgs(Object... args) { + JavaType[] sig = method.toParameterTypes(); + assert args.length == sig.length : method.format("%H.%n(%p): expected ") + sig.length + " args, got " + args.length; + for (int i = 0; i < sig.length; i++) { + Object arg = args[i]; + if (arg == null) { + assert sig[i].getJavaKind() == JavaKind.Object : method.format("%H.%n(%p): expected arg ") + i + " to be Object, not " + sig[i]; + } else if (sig[i].getJavaKind() != JavaKind.Object) { + assert sig[i].getJavaKind().toBoxedJavaClass() == arg.getClass() : method.format("%H.%n(%p): expected arg ") + i + " to be " + sig[i] + ", not " + arg.getClass(); + } + } + return true; + } + + @Override + public Object executeVarargs(Object... args) throws InvalidInstalledCodeException { + assert checkArgs(args); + assert !isExternal(); + return runtime().getCompilerToVM().executeInstalledCode(args, this); + } + + @Override + public long getStart() { + return isValid() ? super.getStart() : 0; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import java.lang.invoke.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Represents a constant non-{@code null} object reference, within the compiler and across the + * compiler/runtime interface. + */ +public interface HotSpotObjectConstant extends JavaConstant, HotSpotConstant, VMConstant { + + JavaConstant compress(); + + JavaConstant uncompress(); + + /** + * Gets the resolved Java type of the object represented by this constant. + */ + HotSpotResolvedObjectType getType(); + + /** + * Gets the result of {@link Class#getClassLoader()} for the {@link Class} object represented by + * this constant. + * + * @return {@code null} if this constant does not represent a {@link Class} object + */ + JavaConstant getClassLoader(); + + /** + * Gets the {@linkplain System#identityHashCode(Object) identity} has code for the object + * represented by this constant. + */ + int getIdentityHashCode(); + + /** + * Gets the result of {@link Class#getComponentType()} for the {@link Class} object represented + * by this constant. + * + * @return {@code null} if this constant does not represent a {@link Class} object + */ + JavaConstant getComponentType(); + + /** + * Gets the result of {@link Class#getSuperclass()} for the {@link Class} object represented by + * this constant. + * + * @return {@code null} if this constant does not represent a {@link Class} object + */ + JavaConstant getSuperclass(); + + /** + * Gets the result of {@link CallSite#getTarget()} for the {@link CallSite} object represented + * by this constant. + * + * @param assumptions used to register an assumption that the {@link CallSite}'s target does not + * change + * @return {@code null} if this constant does not represent a {@link CallSite} object + */ + JavaConstant getCallSiteTarget(Assumptions assumptions); + + /** + * Determines if this constant represents an {@linkplain String#intern() interned} string. + */ + boolean isInternedString(); + + /** + * Gets the object represented by this constant represents if it is of a given type. + * + * @param type the expected type of the object represented by this constant. If the object is + * required to be of this type, then wrap the call to this method in + * {@link Objects#requireNonNull(Object)}. + * @return the object value represented by this constant if it is an + * {@link ResolvedJavaType#isInstance(JavaConstant) instance of} {@code type} otherwise + * {@code null} + */ + T asObject(Class type); + + /** + * Gets the object represented by this constant represents if it is of a given type. + * + * @param type the expected type of the object represented by this constant. If the object is + * required to be of this type, then wrap the call to this method in + * {@link Objects#requireNonNull(Object)}. + * @return the object value represented by this constant if it is an + * {@link ResolvedJavaType#isInstance(JavaConstant) instance of} {@code type} otherwise + * {@code null} + */ + Object asObject(ResolvedJavaType type); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl.*; + +import java.lang.invoke.*; + +import jdk.vm.ci.inittimer.*; +import jdk.vm.ci.meta.*; + +/** + * Represents a constant non-{@code null} object reference, within the compiler and across the + * compiler/runtime interface. + */ +public final class HotSpotObjectConstantImpl implements HotSpotObjectConstant, HotSpotProxified { + + public static JavaConstant forObject(Object object) { + return forObject(object, false); + } + + static JavaConstant forObject(Object object, boolean compressed) { + if (object == null) { + return compressed ? HotSpotCompressedNullConstant.COMPRESSED_NULL : JavaConstant.NULL_POINTER; + } else { + return new HotSpotObjectConstantImpl(object, compressed); + } + } + + static JavaConstant forStableArray(Object object, int stableDimension, boolean isDefaultStable) { + if (object == null) { + return JavaConstant.NULL_POINTER; + } else { + assert object.getClass().isArray(); + return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable); + } + } + + public static JavaConstant forBoxedValue(JavaKind kind, Object value) { + if (kind == JavaKind.Object) { + return HotSpotObjectConstantImpl.forObject(value); + } else { + return JavaConstant.forBoxedPrimitive(value); + } + } + + static Object asBoxedValue(Constant constant) { + if (JavaConstant.isNull(constant)) { + return null; + } else if (constant instanceof HotSpotObjectConstantImpl) { + return ((HotSpotObjectConstantImpl) constant).object; + } else { + return ((JavaConstant) constant).asBoxedPrimitive(); + } + } + + private final Object object; + private final boolean compressed; + private final byte stableDimension; + private final boolean isDefaultStable; + + private HotSpotObjectConstantImpl(Object object, boolean compressed, int stableDimension, boolean isDefaultStable) { + this.object = object; + this.compressed = compressed; + this.stableDimension = (byte) stableDimension; + this.isDefaultStable = isDefaultStable; + assert object != null; + assert stableDimension == 0 || (object != null && object.getClass().isArray()); + assert stableDimension >= 0 && stableDimension <= 255; + assert !isDefaultStable || stableDimension > 0; + } + + private HotSpotObjectConstantImpl(Object object, boolean compressed) { + this(object, compressed, 0, false); + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + /** + * Package-private accessor for the object represented by this constant. + */ + Object object() { + return object; + } + + /** + * Determines if the object represented by this constant is {@link Object#equals(Object) equal} + * to a given object. + */ + public boolean isEqualTo(Object obj) { + return object.equals(obj); + } + + /** + * Gets the class of the object represented by this constant. + */ + public Class getObjectClass() { + return object.getClass(); + } + + public boolean isCompressed() { + return compressed; + } + + public JavaConstant compress() { + assert !compressed; + return new HotSpotObjectConstantImpl(object, true, stableDimension, isDefaultStable); + } + + public JavaConstant uncompress() { + assert compressed; + return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable); + } + + public HotSpotResolvedObjectType getType() { + return fromObjectClass(object.getClass()); + } + + public JavaConstant getClassLoader() { + if (object instanceof Class) { + /* + * This is an intrinsic for getClassLoader0, which occurs after any security checks. We + * can't call that directly so just call getClassLoader. + */ + return HotSpotObjectConstantImpl.forObject(((Class) object).getClassLoader()); + } + return null; + } + + public int getIdentityHashCode() { + return System.identityHashCode(object); + } + + public JavaConstant getComponentType() { + if (object instanceof Class) { + return HotSpotObjectConstantImpl.forObject(((Class) object).getComponentType()); + } + return null; + } + + public JavaConstant getSuperclass() { + if (object instanceof Class) { + return HotSpotObjectConstantImpl.forObject(((Class) object).getSuperclass()); + } + return null; + } + + public JavaConstant getCallSiteTarget(Assumptions assumptions) { + if (object instanceof CallSite) { + CallSite callSite = (CallSite) object; + MethodHandle target = callSite.getTarget(); + if (!(callSite instanceof ConstantCallSite)) { + if (assumptions == null) { + return null; + } + assumptions.record(new Assumptions.CallSiteTargetValue(callSite, target)); + } + return HotSpotObjectConstantImpl.forObject(target); + } + return null; + } + + @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want") + public boolean isInternedString() { + if (object instanceof String) { + String s = (String) object; + return s.intern() == s; + } + return false; + } + + public T asObject(Class type) { + if (type.isInstance(object)) { + return type.cast(object); + } + return null; + } + + public Object asObject(ResolvedJavaType type) { + if (type.isInstance(this)) { + return object; + } + return null; + } + + @Override + public boolean isNull() { + return false; + } + + @Override + public boolean isDefaultForKind() { + return false; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public int hashCode() { + return System.identityHashCode(object); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (o instanceof HotSpotObjectConstantImpl) { + HotSpotObjectConstantImpl other = (HotSpotObjectConstantImpl) o; + return object == other.object && compressed == other.compressed && stableDimension == other.stableDimension && isDefaultStable == other.isDefaultStable; + } + return false; + } + + @Override + public String toValueString() { + if (object instanceof String) { + return "\"" + (String) object + "\""; + } else { + return JavaKind.Object.format(object); + } + } + + @Override + public String toString() { + return (compressed ? "NarrowOop" : getJavaKind().getJavaName()) + "[" + JavaKind.Object.format(object) + "]"; + } + + /** + * Number of stable dimensions if this constant is a stable array. + */ + public int getStableDimension() { + return stableDimension & 0xff; + } + + /** + * Returns {@code true} if this is a stable array constant and its elements should be considered + * as stable regardless of whether they are default values. + */ + public boolean isDefaultStable() { + return isDefaultStable; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotOopMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotOopMap.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +public class HotSpotOopMap { + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int offset; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private int count; + @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private byte[] data; + + public byte[] data() { + return data; + } + + public int count() { + return count; + } + + public int offset() { + return offset; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +public final class HotSpotProfilingInfo implements ProfilingInfo, HotSpotProxified { + + // private static final DebugMetric metricInsufficentSpace = + // Debug.metric("InsufficientSpaceForProfilingData"); + + private final HotSpotMethodData methodData; + private final HotSpotResolvedJavaMethod method; + + private boolean isMature; + private int position; + private int hintPosition; + private int hintBCI; + private HotSpotMethodDataAccessor dataAccessor; + + private boolean includeNormal; + private boolean includeOSR; + + public HotSpotProfilingInfo(HotSpotMethodData methodData, HotSpotResolvedJavaMethod method, boolean includeNormal, boolean includeOSR) { + this.methodData = methodData; + this.method = method; + this.includeNormal = includeNormal; + this.includeOSR = includeOSR; + this.isMature = methodData.isProfileMature(); + hintPosition = 0; + hintBCI = -1; + } + + @Override + public int getCodeSize() { + return method.getCodeSize(); + } + + @Override + public JavaTypeProfile getTypeProfile(int bci) { + if (!isMature) { + return null; + } + findBCI(bci, false); + return dataAccessor.getTypeProfile(methodData, position); + } + + @Override + public JavaMethodProfile getMethodProfile(int bci) { + if (!isMature) { + return null; + } + findBCI(bci, false); + return dataAccessor.getMethodProfile(methodData, position); + } + + @Override + public double getBranchTakenProbability(int bci) { + if (!isMature) { + return -1; + } + findBCI(bci, false); + return dataAccessor.getBranchTakenProbability(methodData, position); + } + + @Override + public double[] getSwitchProbabilities(int bci) { + if (!isMature) { + return null; + } + findBCI(bci, false); + return dataAccessor.getSwitchProbabilities(methodData, position); + } + + @Override + public TriState getExceptionSeen(int bci) { + findBCI(bci, true); + return dataAccessor.getExceptionSeen(methodData, position); + } + + @Override + public TriState getNullSeen(int bci) { + findBCI(bci, false); + return dataAccessor.getNullSeen(methodData, position); + } + + @Override + public int getExecutionCount(int bci) { + if (!isMature) { + return -1; + } + findBCI(bci, false); + return dataAccessor.getExecutionCount(methodData, position); + } + + @Override + public int getDeoptimizationCount(DeoptimizationReason reason) { + int count = 0; + if (includeNormal) { + count += methodData.getDeoptimizationCount(reason); + } + if (includeOSR) { + count += methodData.getOSRDeoptimizationCount(reason); + } + return count; + } + + private void findBCI(int targetBCI, boolean searchExtraData) { + assert targetBCI >= 0 : "invalid BCI"; + + if (methodData.hasNormalData()) { + int currentPosition = targetBCI < hintBCI ? 0 : hintPosition; + HotSpotMethodDataAccessor currentAccessor; + while ((currentAccessor = methodData.getNormalData(currentPosition)) != null) { + int currentBCI = currentAccessor.getBCI(methodData, currentPosition); + if (currentBCI == targetBCI) { + normalDataFound(currentAccessor, currentPosition, currentBCI); + return; + } else if (currentBCI > targetBCI) { + break; + } + currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); + } + } + + boolean exceptionPossiblyNotRecorded = false; + if (searchExtraData && methodData.hasExtraData()) { + int currentPosition = methodData.getExtraDataBeginOffset(); + HotSpotMethodDataAccessor currentAccessor; + while ((currentAccessor = methodData.getExtraData(currentPosition)) != null) { + int currentBCI = currentAccessor.getBCI(methodData, currentPosition); + if (currentBCI == targetBCI) { + extraDataFound(currentAccessor, currentPosition); + return; + } + currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); + } + + if (!methodData.isWithin(currentPosition)) { + exceptionPossiblyNotRecorded = true; + // metricInsufficentSpace.increment(); + } + } + + noDataFound(exceptionPossiblyNotRecorded); + } + + private void normalDataFound(HotSpotMethodDataAccessor data, int pos, int bci) { + setCurrentData(data, pos); + this.hintPosition = position; + this.hintBCI = bci; + } + + private void extraDataFound(HotSpotMethodDataAccessor data, int pos) { + setCurrentData(data, pos); + } + + private void noDataFound(boolean exceptionPossiblyNotRecorded) { + HotSpotMethodDataAccessor accessor = HotSpotMethodData.getNoDataAccessor(exceptionPossiblyNotRecorded); + setCurrentData(accessor, -1); + } + + private void setCurrentData(HotSpotMethodDataAccessor dataAccessor, int position) { + this.dataAccessor = dataAccessor; + this.position = position; + } + + @Override + public boolean isMature() { + return isMature; + } + + public void ignoreMature() { + isMature = true; + } + + @Override + public String toString() { + return "HotSpotProfilingInfo<" + this.toString(null, "; ") + ">"; + } + + @Override + public void setMature() { + isMature = true; + } + + /** + * {@code MethodData::_jvmci_ir_size} (currently) supports at most one JVMCI compiler IR type + * which will be determined by the first JVMCI compiler that calls + * {@link #setCompilerIRSize(Class, int)}. + */ + private static volatile Class supportedCompilerIRType; + + @Override + public boolean setCompilerIRSize(Class irType, int size) { + if (supportedCompilerIRType == null) { + synchronized (HotSpotProfilingInfo.class) { + if (supportedCompilerIRType == null) { + supportedCompilerIRType = irType; + } + } + } + if (supportedCompilerIRType != irType) { + return false; + } + methodData.setCompiledIRSize(size); + return true; + } + + @Override + public int getCompilerIRSize(Class irType) { + if (irType == supportedCompilerIRType) { + return methodData.getCompiledIRSize(); + } + return -1; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProxified.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProxified.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +/** + * Marker interface for classes whose values are proxied during replay compilation capture. + */ +public interface HotSpotProxified { +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotReferenceMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotReferenceMap.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import java.util.*; + +import jdk.vm.ci.code.*; + +public final class HotSpotReferenceMap extends ReferenceMap { + + final Location[] objects; + final Location[] derivedBase; + final int[] sizeInBytes; + final int maxRegisterSize; + + public HotSpotReferenceMap(Location[] objects, Location[] derivedBase, int[] sizeInBytes, int maxRegisterSize) { + this.objects = objects; + this.derivedBase = derivedBase; + this.sizeInBytes = sizeInBytes; + this.maxRegisterSize = maxRegisterSize; + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotReferenceMap) { + HotSpotReferenceMap that = (HotSpotReferenceMap) obj; + if (Arrays.equals(objects, that.objects)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return Arrays.toString(objects); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Represents a field in a HotSpot type. + */ +public interface HotSpotResolvedJavaField extends ResolvedJavaField { + + /** + * Determines if a given object contains this field. + * + * @return true iff this is a non-static field and its declaring class is assignable from + * {@code object}'s class + */ + boolean isInObject(Object object); + + int offset(); + + /** + * Checks if this field has the {@link Stable} annotation. + * + * @return true if field has {@link Stable} annotation, false otherwise + */ + boolean isStable(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.HotSpotResolvedJavaFieldImpl.Options.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.options.*; + +/** + * Represents a field in a HotSpot type. + */ +public class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotProxified { + + static class Options { + //@formatter:off + @Option(help = "Mark well-known stable fields as such.", type = OptionType.Debug) + public static final OptionValue ImplicitStableValues = new OptionValue<>(true); + //@formatter:on + } + + private final HotSpotResolvedObjectTypeImpl holder; + private final String name; + private JavaType type; + private final int offset; + + /** + * This value contains all flags as stored in the VM including internal ones. + */ + private final int modifiers; + private final LocationIdentity locationIdentity = new FieldLocationIdentity(this); + + public static class FieldLocationIdentity extends LocationIdentity { + HotSpotResolvedJavaField inner; + + public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) { + this.inner = inner; + } + + @Override + public boolean isImmutable() { + return false; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof FieldLocationIdentity) { + FieldLocationIdentity fieldLocationIdentity = (FieldLocationIdentity) obj; + return inner.equals(fieldLocationIdentity.inner); + + } + return false; + } + + @Override + public int hashCode() { + return inner.hashCode(); + } + + @Override + public String toString() { + return inner.getName(); + } + } + + public HotSpotResolvedJavaFieldImpl(HotSpotResolvedObjectTypeImpl holder, String name, JavaType type, long offset, int modifiers) { + this.holder = holder; + this.name = name; + this.type = type; + assert offset != -1; + assert offset == (int) offset : "offset larger than int"; + this.offset = (int) offset; + this.modifiers = modifiers; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotResolvedJavaField) { + HotSpotResolvedJavaFieldImpl that = (HotSpotResolvedJavaFieldImpl) obj; + if (that.offset != this.offset || that.isStatic() != this.isStatic()) { + return false; + } else if (this.holder.equals(that.holder)) { + assert this.name.equals(that.name) && this.type.equals(that.type); + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public int getModifiers() { + return modifiers & ModifiersProvider.jvmFieldModifiers(); + } + + @Override + public boolean isInternal() { + return (modifiers & runtime().getConfig().jvmAccFieldInternal) != 0; + } + + /** + * Determines if a given object contains this field. + * + * @return true iff this is a non-static field and its declaring class is assignable from + * {@code object}'s class + */ + public boolean isInObject(Object object) { + if (isStatic()) { + return false; + } + return getDeclaringClass().isAssignableFrom(HotSpotResolvedObjectTypeImpl.fromObjectClass(object.getClass())); + } + + @Override + public HotSpotResolvedObjectTypeImpl getDeclaringClass() { + return holder; + } + + @Override + public String getName() { + return name; + } + + @Override + public JavaType getType() { + // Pull field into local variable to prevent a race causing + // a ClassCastException below + JavaType currentType = type; + if (currentType instanceof HotSpotUnresolvedJavaType) { + // Don't allow unresolved types to hang around forever + HotSpotUnresolvedJavaType unresolvedType = (HotSpotUnresolvedJavaType) currentType; + ResolvedJavaType resolved = unresolvedType.reresolve(holder); + if (resolved != null) { + type = resolved; + } + } + return type; + } + + public int offset() { + return offset; + } + + @Override + public String toString() { + return format("HotSpotField<%H.%n %t:") + offset + ">"; + } + + @Override + public boolean isSynthetic() { + return (runtime().getConfig().syntheticFlag & modifiers) != 0; + } + + /** + * Checks if this field has the {@link Stable} annotation. + * + * @return true if field has {@link Stable} annotation, false otherwise + */ + public boolean isStable() { + if ((runtime().getConfig().jvmAccFieldStable & modifiers) != 0) { + return true; + } + assert getAnnotation(Stable.class) == null; + if (ImplicitStableValues.getValue() && isImplicitStableField()) { + return true; + } + return false; + } + + @Override + public Annotation[] getAnnotations() { + Field javaField = toJava(); + if (javaField != null) { + return javaField.getAnnotations(); + } + return new Annotation[0]; + } + + @Override + public T getAnnotation(Class annotationClass) { + Field javaField = toJava(); + if (javaField != null) { + return javaField.getAnnotation(annotationClass); + } + return null; + } + + private Field toJavaCache; + + private Field toJava() { + if (toJavaCache != null) { + return toJavaCache; + } + + if (isInternal()) { + return null; + } + try { + return toJavaCache = holder.mirror().getDeclaredField(name); + } catch (NoSuchFieldException | NoClassDefFoundError e) { + return null; + } + } + + private boolean isArray() { + JavaType fieldType = getType(); + return fieldType instanceof ResolvedJavaType && ((ResolvedJavaType) fieldType).isArray(); + } + + private boolean isImplicitStableField() { + if (isSynthetic()) { + if (isSyntheticImplicitStableField()) { + return true; + } + } else if (isWellKnownImplicitStableField()) { + return true; + } + return false; + } + + private boolean isSyntheticImplicitStableField() { + assert this.isSynthetic(); + if (isStatic() && isArray()) { + if (isFinal() && name.equals("$VALUES") || name.equals("ENUM$VALUES")) { + // generated int[] field for EnumClass::values() + return true; + } else if (name.startsWith("$SwitchMap$") || name.startsWith("$SWITCH_TABLE$")) { + // javac and ecj generate a static field in an inner class for a switch on an enum + // named $SwitchMap$p$k$g$EnumClass and $SWITCH_TABLE$p$k$g$EnumClass, respectively + return true; + } + } + return false; + } + + private boolean isWellKnownImplicitStableField() { + return WellKnownImplicitStableField.test(this); + } + + static class WellKnownImplicitStableField { + /** + * @return {@code true} if the field is a well-known stable field. + */ + public static boolean test(HotSpotResolvedJavaField field) { + return field.equals(STRING_VALUE_FIELD); + } + + private static final ResolvedJavaField STRING_VALUE_FIELD; + static { + try { + MetaAccessProvider metaAccess = runtime().getHostJVMCIBackend().getMetaAccess(); + STRING_VALUE_FIELD = metaAccess.lookupJavaField(String.class.getDeclaredField("value")); + } catch (SecurityException | NoSuchFieldException e) { + throw new JVMCIError(e); + } + } + } + + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import java.lang.reflect.*; + +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link JavaMethod} for resolved HotSpot methods. + */ +public interface HotSpotResolvedJavaMethod extends ResolvedJavaMethod { + + /** + * Returns true if this method has a {@code CallerSensitive} annotation. + * + * @return true if CallerSensitive annotation present, false otherwise + */ + boolean isCallerSensitive(); + + HotSpotResolvedObjectType getDeclaringClass(); + + /** + * Returns true if this method has a {@code ForceInline} annotation. + * + * @return true if ForceInline annotation present, false otherwise + */ + boolean isForceInline(); + + /** + * Returns true if this method has a {@code DontInline} annotation. + * + * @return true if DontInline annotation present, false otherwise + */ + boolean isDontInline(); + + /** + * Manually adds a DontInline annotation to this method. + */ + void setNotInlineable(); + + /** + * Returns true if this method is one of the special methods that is ignored by security stack + * walks. + * + * @return true if special method ignored by security stack walks, false otherwise + */ + boolean ignoredBySecurityStackWalk(); + + ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver); + + /** + * Returns whether this method has compiled code. + * + * @return true if this method has compiled code, false otherwise + */ + boolean hasCompiledCode(); + + /** + * @param level + * @return true if the currently installed code was generated at {@code level}. + */ + boolean hasCompiledCodeAtLevel(int level); + + default boolean isDefault() { + if (isConstructor()) { + return false; + } + // Copied from java.lang.Method.isDefault() + int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; + return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); + } + + /** + * Returns the offset of this method into the v-table. The method must have a v-table entry as + * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is + * thrown. + * + * @return the offset of this method into the v-table + */ + int vtableEntryOffset(ResolvedJavaType resolved); + + int intrinsicId(); + + /** + * Allocates a compile id for this method by asking the VM for one. + * + * @param entryBCI entry bci + * @return compile id + */ + int allocateCompileId(int entryBCI); + + boolean hasCodeAtLevel(int entryBCI, int level); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl.Options.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.options.*; + +/** + * Implementation of {@link JavaMethod} for resolved HotSpot methods. + */ +public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, MetaspaceWrapperObject { + + public static class Options { + // @formatter:off + @Option(help = "", type = OptionType.Debug) + public static final OptionValue UseProfilingInformation = new OptionValue<>(true); + // @formatter:on + } + + /** + * Reference to metaspace Method object. + */ + private final long metaspaceMethod; + + private final HotSpotResolvedObjectTypeImpl holder; + private final HotSpotConstantPool constantPool; + private final HotSpotSignature signature; + private HotSpotMethodData methodData; + private byte[] code; + private Member toJavaCache; + + /** + * Gets the holder of a HotSpot metaspace method native object. + * + * @param metaspaceMethod a metaspace Method object + * @return the {@link ResolvedJavaType} corresponding to the holder of the + * {@code metaspaceMethod} + */ + private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceMethod) { + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceConstMethod = UNSAFE.getAddress(metaspaceMethod + config.methodConstMethodOffset); + final long metaspaceConstantPool = UNSAFE.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset); + return runtime().getCompilerToVM().getResolvedJavaType(null, metaspaceConstantPool + config.constantPoolHolderOffset, false); + } + + /** + * Gets the JVMCI mirror from a HotSpot method. The VM is responsible for ensuring that the + * Method* is kept alive for the duration of this call and the + * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. + * + * Called from the VM. + * + * @param metaspaceMethod a metaspace Method object + * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod} + */ + @SuppressWarnings("unused") + private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) { + HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceMethod); + return holder.createMethod(metaspaceMethod); + } + + HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceMethod) { + // It would be too much work to get the method name here so we fill it in later. + super(null); + this.metaspaceMethod = metaspaceMethod; + this.holder = holder; + + HotSpotVMConfig config = runtime().getConfig(); + final long constMethod = getConstMethod(); + + /* + * Get the constant pool from the metaspace method. Some methods (e.g. intrinsics for + * signature-polymorphic method handle methods) have their own constant pool instead of the + * one from their holder. + */ + final long metaspaceConstantPool = UNSAFE.getAddress(constMethod + config.constMethodConstantsOffset); + if (metaspaceConstantPool == holder.getConstantPool().getMetaspaceConstantPool()) { + this.constantPool = holder.getConstantPool(); + } else { + this.constantPool = runtime().getCompilerToVM().getConstantPool(null, constMethod + config.constMethodConstantsOffset); + } + + final int nameIndex = UNSAFE.getChar(constMethod + config.constMethodNameIndexOffset); + this.name = constantPool.lookupUtf8(nameIndex); + + final int signatureIndex = UNSAFE.getChar(constMethod + config.constMethodSignatureIndexOffset); + this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex); + } + + /** + * Returns a pointer to this method's constant method data structure ( + * {@code Method::_constMethod}). This pointer isn't wrapped since it should be safe to use it + * within the context of this HotSpotResolvedJavaMethodImpl since the Method* and ConstMethod* + * are kept alive as a pair. + * + * @return pointer to this method's ConstMethod + */ + private long getConstMethod() { + assert metaspaceMethod != 0; + return UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodConstMethodOffset); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotResolvedJavaMethodImpl) { + HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj; + return that.metaspaceMethod == metaspaceMethod; + } + return false; + } + + @Override + public int hashCode() { + return (int) metaspaceMethod; + } + + /** + * Returns this method's flags ({@code Method::_flags}). + * + * @return flags of this method + */ + private int getFlags() { + return UNSAFE.getByte(metaspaceMethod + runtime().getConfig().methodFlagsOffset); + } + + /** + * Returns this method's constant method flags ({@code ConstMethod::_flags}). + * + * @return flags of this method's ConstMethod + */ + private int getConstMethodFlags() { + return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodFlagsOffset); + } + + @Override + public HotSpotResolvedObjectTypeImpl getDeclaringClass() { + return holder; + } + + /** + * Gets the address of the C++ Method object for this method. + */ + public JavaConstant getMetaspaceMethodConstant() { + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(getHostWordKind(), metaspaceMethod, this, false); + } + + public long getMetaspaceMethod() { + return metaspaceMethod; + } + + public long getMetaspacePointer() { + return getMetaspaceMethod(); + } + + @Override + public JavaConstant getEncoding() { + return getMetaspaceMethodConstant(); + } + + /** + * Gets the complete set of modifiers for this method which includes the JVM specification + * modifiers as well as the HotSpot internal modifiers. + */ + public int getAllModifiers() { + return UNSAFE.getInt(metaspaceMethod + runtime().getConfig().methodAccessFlagsOffset); + } + + @Override + public int getModifiers() { + return getAllModifiers() & ModifiersProvider.jvmMethodModifiers(); + } + + @Override + public boolean canBeStaticallyBound() { + return (isFinal() || isPrivate() || isStatic() || holder.isLeaf()) && isConcrete(); + } + + @Override + public byte[] getCode() { + if (getCodeSize() == 0) { + return null; + } + if (code == null && holder.isLinked()) { + code = runtime().getCompilerToVM().getBytecode(this); + assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length; + } + return code; + } + + @Override + public int getCodeSize() { + return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodCodeSizeOffset); + } + + @Override + public ExceptionHandler[] getExceptionHandlers() { + final boolean hasExceptionTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasExceptionTable) != 0; + if (!hasExceptionTable) { + return new ExceptionHandler[0]; + } + + HotSpotVMConfig config = runtime().getConfig(); + final int exceptionTableLength = runtime().getCompilerToVM().getExceptionTableLength(this); + ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength]; + long exceptionTableElement = runtime().getCompilerToVM().getExceptionTableStart(this); + + for (int i = 0; i < exceptionTableLength; i++) { + final int startPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementStartPcOffset); + final int endPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementEndPcOffset); + final int handlerPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementHandlerPcOffset); + int catchTypeIndex = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementCatchTypeIndexOffset); + + JavaType catchType; + if (catchTypeIndex == 0) { + catchType = null; + } else { + final int opcode = -1; // opcode is not used + catchType = constantPool.lookupType(catchTypeIndex, opcode); + + // Check for Throwable which catches everything. + if (catchType instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType; + if (resolvedType.mirror() == Throwable.class) { + catchTypeIndex = 0; + catchType = null; + } + } + } + handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType); + + // Go to the next ExceptionTableElement + exceptionTableElement += config.exceptionTableElementSize; + } + + return handlers; + } + + /** + * Returns true if this method has a {@code CallerSensitive} annotation. + * + * @return true if CallerSensitive annotation present, false otherwise + */ + public boolean isCallerSensitive() { + return (getFlags() & runtime().getConfig().methodFlagsCallerSensitive) != 0; + } + + /** + * Returns true if this method has a {@code ForceInline} annotation. + * + * @return true if ForceInline annotation present, false otherwise + */ + public boolean isForceInline() { + return (getFlags() & runtime().getConfig().methodFlagsForceInline) != 0; + } + + /** + * Returns true if this method has a {@code DontInline} annotation. + * + * @return true if DontInline annotation present, false otherwise + */ + public boolean isDontInline() { + return (getFlags() & runtime().getConfig().methodFlagsDontInline) != 0; + } + + /** + * Manually adds a DontInline annotation to this method. + */ + public void setNotInlineable() { + runtime().getCompilerToVM().doNotInlineOrCompile(this); + } + + /** + * Returns true if this method is one of the special methods that is ignored by security stack + * walks. + * + * @return true if special method ignored by security stack walks, false otherwise + */ + public boolean ignoredBySecurityStackWalk() { + return runtime().getCompilerToVM().methodIsIgnoredBySecurityStackWalk(this); + } + + @Override + public boolean isClassInitializer() { + return "".equals(name) && isStatic(); + } + + @Override + public boolean isConstructor() { + return "".equals(name) && !isStatic(); + } + + @Override + public int getMaxLocals() { + if (isAbstract() || isNative()) { + return 0; + } + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getChar(getConstMethod() + config.methodMaxLocalsOffset); + } + + @Override + public int getMaxStackSize() { + if (isAbstract() || isNative()) { + return 0; + } + HotSpotVMConfig config = runtime().getConfig(); + return config.extraStackEntries + UNSAFE.getChar(getConstMethod() + config.constMethodMaxStackOffset); + } + + @Override + public StackTraceElement asStackTraceElement(int bci) { + if (bci < 0 || bci >= getCodeSize()) { + // HotSpot code can only construct stack trace elements for valid bcis + StackTraceElement ste = runtime().getCompilerToVM().getStackTraceElement(this, 0); + return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1); + } + return runtime().getCompilerToVM().getStackTraceElement(this, bci); + } + + public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) { + if (receiver.isInterface()) { + // Cannot trust interfaces. Because of: + // interface I { void foo(); } + // class A { public void foo() {} } + // class B extends A implements I { } + // class C extends B { public void foo() { } } + // class D extends B { } + // Would lead to identify C.foo() as the unique concrete method for I.foo() without + // seeing A.foo(). + return null; + } + return runtime().getCompilerToVM().findUniqueConcreteMethod(((HotSpotResolvedObjectTypeImpl) receiver), this); + } + + @Override + public HotSpotSignature getSignature() { + return signature; + } + + /** + * Gets the value of {@code Method::_code}. + * + * @return the value of {@code Method::_code} + */ + private long getCompiledCode() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getAddress(metaspaceMethod + config.methodCodeOffset); + } + + /** + * Returns whether this method has compiled code. + * + * @return true if this method has compiled code, false otherwise + */ + public boolean hasCompiledCode() { + return getCompiledCode() != 0L; + } + + /** + * @param level + * @return true if the currently installed code was generated at {@code level}. + */ + public boolean hasCompiledCodeAtLevel(int level) { + long compiledCode = getCompiledCode(); + if (compiledCode != 0) { + return UNSAFE.getInt(compiledCode + runtime().getConfig().nmethodCompLevelOffset) == level; + } + return false; + } + + private static final String TraceMethodDataFilter = System.getProperty("jvmci.traceMethodDataFilter"); + + @Override + public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { + ProfilingInfo info; + + if (UseProfilingInformation.getValue() && methodData == null) { + long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodDataOffset); + if (metaspaceMethodData != 0) { + methodData = new HotSpotMethodData(metaspaceMethodData, this); + if (TraceMethodDataFilter != null && this.format("%H.%n").contains(TraceMethodDataFilter)) { + System.out.println("Raw method data for " + this.format("%H.%n(%p)") + ":"); + System.out.println(methodData.toString()); + } + } + } + + if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) { + // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in + // case of a deoptimization. + info = DefaultProfilingInfo.get(TriState.FALSE); + } else { + info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR); + } + return info; + } + + @Override + public void reprofile() { + runtime().getCompilerToVM().reprofile(this); + } + + @Override + public ConstantPool getConstantPool() { + return constantPool; + } + + @Override + public Annotation[][] getParameterAnnotations() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getParameterAnnotations(); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getParameterAnnotations(); + } + + @Override + public Annotation[] getAnnotations() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? new Annotation[0] : javaConstructor.getAnnotations(); + } + Method javaMethod = toJava(); + return javaMethod == null ? new Annotation[0] : javaMethod.getAnnotations(); + } + + @Override + public T getAnnotation(Class annotationClass) { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getAnnotation(annotationClass); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass); + } + + public boolean isDefault() { + if (isConstructor()) { + return false; + } + // Copied from java.lang.Method.isDefault() + int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; + return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); + } + + @Override + public Type[] getGenericParameterTypes() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getGenericParameterTypes(); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getGenericParameterTypes(); + } + + public Class[] signatureToTypes() { + Signature sig = getSignature(); + int count = sig.getParameterCount(false); + Class[] result = new Class[count]; + for (int i = 0; i < result.length; ++i) { + JavaType parameterType = sig.getParameterType(i, holder); + HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder); + result[i] = resolvedParameterType.mirror(); + } + return result; + } + + private Method toJava() { + if (toJavaCache != null) { + return (Method) toJavaCache; + } + try { + Method result = holder.mirror().getDeclaredMethod(name, signatureToTypes()); + toJavaCache = result; + return result; + } catch (NoSuchMethodException | NoClassDefFoundError e) { + return null; + } + } + + private Constructor toJavaConstructor() { + if (toJavaCache != null) { + return (Constructor) toJavaCache; + } + try { + Constructor result = holder.mirror().getDeclaredConstructor(signatureToTypes()); + toJavaCache = result; + return result; + } catch (NoSuchMethodException | NoClassDefFoundError e) { + return null; + } + } + + @Override + public boolean canBeInlined() { + if (isDontInline()) { + return false; + } + return runtime().getCompilerToVM().canInlineMethod(this); + } + + @Override + public boolean shouldBeInlined() { + if (isForceInline()) { + return true; + } + return runtime().getCompilerToVM().shouldInlineMethod(this); + } + + @Override + public LineNumberTable getLineNumberTable() { + final boolean hasLineNumberTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLineNumberTable) != 0; + if (!hasLineNumberTable) { + return null; + } + + long[] values = runtime().getCompilerToVM().getLineNumberTable(this); + if (values == null || values.length == 0) { + // Empty table so treat is as non-existent + return null; + } + assert values.length % 2 == 0; + int[] bci = new int[values.length / 2]; + int[] line = new int[values.length / 2]; + + for (int i = 0; i < values.length / 2; i++) { + bci[i] = (int) values[i * 2]; + line[i] = (int) values[i * 2 + 1]; + } + + return new LineNumberTableImpl(line, bci); + } + + @Override + public LocalVariableTable getLocalVariableTable() { + final boolean hasLocalVariableTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLocalVariableTable) != 0; + if (!hasLocalVariableTable) { + return null; + } + + HotSpotVMConfig config = runtime().getConfig(); + long localVariableTableElement = runtime().getCompilerToVM().getLocalVariableTableStart(this); + final int localVariableTableLength = runtime().getCompilerToVM().getLocalVariableTableLength(this); + Local[] locals = new Local[localVariableTableLength]; + + for (int i = 0; i < localVariableTableLength; i++) { + final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset); + final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset); + final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset); + final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset); + final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset); + + String localName = getConstantPool().lookupUtf8(nameCpIndex); + String localType = getConstantPool().lookupUtf8(typeCpIndex); + + locals[i] = new LocalImpl(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot); + + // Go to the next LocalVariableTableElement + localVariableTableElement += config.localVariableTableElementSize; + } + + return new LocalVariableTableImpl(locals); + } + + /** + * Returns the offset of this method into the v-table. The method must have a v-table entry as + * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is + * thrown. + * + * @return the offset of this method into the v-table + */ + public int vtableEntryOffset(ResolvedJavaType resolved) { + if (!isInVirtualMethodTable(resolved)) { + throw new JVMCIError("%s does not have a vtable entry in type %s", this, resolved); + } + HotSpotVMConfig config = runtime().getConfig(); + final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved); + return config.instanceKlassVtableStartOffset() + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset; + } + + @Override + public boolean isInVirtualMethodTable(ResolvedJavaType resolved) { + if (resolved instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved; + int vtableIndex = getVtableIndex(hotspotResolved); + return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength(); + } + return false; + } + + private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) { + if (!holder.isLinked()) { + return runtime().getConfig().invalidVtableIndex; + } + if (holder.isInterface()) { + if (resolved.isInterface()) { + return runtime().getConfig().invalidVtableIndex; + } + return getVtableIndexForInterfaceMethod(resolved); + } + return getVtableIndex(); + } + + /** + * Returns this method's virtual table index. + * + * @return virtual table index + */ + private int getVtableIndex() { + assert!holder.isInterface(); + HotSpotVMConfig config = runtime().getConfig(); + int result = UNSAFE.getInt(metaspaceMethod + config.methodVtableIndexOffset); + assert result >= config.nonvirtualVtableIndex : "must be linked"; + return result; + } + + private int getVtableIndexForInterfaceMethod(ResolvedJavaType resolved) { + HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved; + return runtime().getCompilerToVM().getVtableIndexForInterfaceMethod(hotspotType, this); + } + + /** + * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type + * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is + * never moves and b) we never read from it. + *

+ * One implication is that we will preserve {@link SpeculationLog}s for methods that have been + * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot + * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods + * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal). + */ + private static final ClassValue> SpeculationLogs = new ClassValue>() { + @Override + protected Map computeValue(java.lang.Class type) { + return new HashMap<>(4); + } + }; + + public SpeculationLog getSpeculationLog() { + Map map = SpeculationLogs.get(holder.mirror()); + synchronized (map) { + SpeculationLog log = map.get(this.metaspaceMethod); + if (log == null) { + log = new HotSpotSpeculationLog(); + map.put(metaspaceMethod, log); + } + return log; + } + } + + public int intrinsicId() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getChar(metaspaceMethod + config.methodIntrinsicIdOffset); + } + + @Override + public JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments) { + assert!isConstructor(); + Method javaMethod = toJava(); + javaMethod.setAccessible(true); + + Object[] objArguments = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + objArguments[i] = HotSpotObjectConstantImpl.asBoxedValue(arguments[i]); + } + Object objReceiver = receiver != null && !receiver.isNull() ? ((HotSpotObjectConstantImpl) receiver).object() : null; + + try { + Object objResult = javaMethod.invoke(objReceiver, objArguments); + return javaMethod.getReturnType() == void.class ? null : HotSpotObjectConstantImpl.forBoxedValue(getSignature().getReturnKind(), objResult); + + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new IllegalArgumentException(ex); + } + } + + /** + * Allocates a compile id for this method by asking the VM for one. + * + * @param entryBCI entry bci + * @return compile id + */ + public int allocateCompileId(int entryBCI) { + return runtime().getCompilerToVM().allocateCompileId(this, entryBCI); + } + + public boolean hasCodeAtLevel(int entryBCI, int level) { + if (entryBCI == runtime().getConfig().invocationEntryBci) { + return hasCompiledCodeAtLevel(level); + } + return runtime().getCompilerToVM().hasCompiledCodeForOSR(this, entryBCI, level); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { + + public HotSpotResolvedJavaType(String name) { + super(name); + } + + public abstract Class mirror(); + + @Override + public final boolean equals(Object obj) { + if (!(obj instanceof HotSpotResolvedJavaType)) { + return false; + } + HotSpotResolvedJavaType that = (HotSpotResolvedJavaType) obj; + return this.mirror().equals(that.mirror()); + } + + @Override + public final int hashCode() { + return getName().hashCode(); + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.*; + +/** + * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. + */ +public interface HotSpotResolvedObjectType extends ResolvedJavaType { + + HotSpotResolvedObjectType getArrayClass(); + + ResolvedJavaType getComponentType(); + + AssumptionResult findLeafConcreteSubtype(); + + HotSpotResolvedObjectType getSuperclass(); + + HotSpotResolvedObjectType[] getInterfaces(); + + HotSpotResolvedObjectType getSupertype(); + + HotSpotResolvedObjectType findLeastCommonAncestor(ResolvedJavaType otherType); + + HotSpotResolvedObjectType asExactType(); + + default boolean isPrimitive() { + return false; + } + + default JavaKind getJavaKind() { + return JavaKind.Object; + } + + ConstantPool getConstantPool(); + + /** + * Gets the instance size of this type. If an instance of this type cannot be fast path + * allocated, then the returned value is negative (its absolute value gives the size). Must not + * be called if this is an array or interface type. + */ + int instanceSize(); + + int getVtableLength(); + + @Override + AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method); + + /** + * Performs a fast-path check that this type is resolved in the context of a given accessing + * class. A negative result does not mean this type is not resolved with respect to + * {@code accessingClass}. That can only be determined by + * {@linkplain HotSpotJVMCIRuntime#lookupType(String, HotSpotResolvedObjectType, boolean) + * re-resolving} the type. + */ + boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass); + + /** + * Gets the metaspace Klass boxed in a {@link JavaConstant}. + */ + Constant klass(); + + boolean isPrimaryType(); + + int superCheckOffset(); + + long prototypeMarkWord(); + + int layoutHelper(); + + HotSpotResolvedObjectType getEnclosingType(); + + ResolvedJavaMethod getClassInitializer(); + + ResolvedJavaField createField(String name, JavaType type, long offset, int modifiers); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,889 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static java.util.Objects.*; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; +import java.nio.*; +import java.util.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.*; + +/** + * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. + */ +public final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, HotSpotProxified, MetaspaceWrapperObject { + + /** + * The Java class this type represents. + */ + private final Class javaClass; + private HashMap fieldCache; + private HashMap methodCache; + private HotSpotResolvedJavaField[] instanceFields; + private HotSpotResolvedObjectTypeImpl[] interfaces; + private HotSpotConstantPool constantPool; + final HotSpotJVMCIMetaAccessContext context; + private HotSpotResolvedObjectType arrayOfType; + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link HotSpotResolvedJavaType} corresponding to {@code javaClass} + */ + public static HotSpotResolvedObjectTypeImpl fromObjectClass(Class javaClass) { + return (HotSpotResolvedObjectTypeImpl) runtime().fromClass(javaClass); + } + + /** + * Gets the JVMCI mirror from a HotSpot type. Since {@link Class} is already a proxy for the + * underlying Klass*, it is used instead of the raw Klass*. + * + * Called from the VM. + * + * @param javaClass a {@link Class} object + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + @SuppressWarnings("unused") + private static HotSpotResolvedObjectTypeImpl fromMetaspace(Class javaClass) { + return fromObjectClass(javaClass); + } + + /** + * Creates the JVMCI mirror for a {@link Class} object. + * + *

+ * NOTE: Creating an instance of this class does not install the mirror for the + * {@link Class} type. Use {@link #fromObjectClass(Class)} or {@link #fromMetaspace(Class)} + * instead. + *

+ * + * @param javaClass the Class to create the mirror for + * @param context + */ + HotSpotResolvedObjectTypeImpl(Class javaClass, HotSpotJVMCIMetaAccessContext context) { + super(getSignatureName(javaClass)); + this.javaClass = javaClass; + this.context = context; + assert getName().charAt(0) != '[' || isArray() : getName(); + } + + /** + * Returns the name of this type as it would appear in a signature. + */ + private static String getSignatureName(Class javaClass) { + if (javaClass.isArray()) { + return javaClass.getName().replace('.', '/'); + } + return "L" + javaClass.getName().replace('.', '/') + ";"; + } + + /** + * Gets the metaspace Klass for this type. + */ + public long getMetaspaceKlass() { + if (HotSpotJVMCIRuntime.getHostWordKind() == JavaKind.Long) { + return UNSAFE.getLong(javaClass, (long) runtime().getConfig().klassOffset); + } + return UNSAFE.getInt(javaClass, (long) runtime().getConfig().klassOffset) & 0xFFFFFFFFL; + } + + public long getMetaspacePointer() { + return getMetaspaceKlass(); + } + + @Override + public int getModifiers() { + if (isArray()) { + return (getElementalType().getModifiers() & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED)) | Modifier.FINAL | Modifier.ABSTRACT; + } else { + return getAccessFlags() & ModifiersProvider.jvmClassModifiers(); + } + } + + public int getAccessFlags() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset); + } + + @Override + public HotSpotResolvedObjectType getArrayClass() { + if (arrayOfType == null) { + arrayOfType = fromObjectClass(Array.newInstance(mirror(), 0).getClass()); + } + return arrayOfType; + } + + @Override + public ResolvedJavaType getComponentType() { + Class javaComponentType = mirror().getComponentType(); + return javaComponentType == null ? null : runtime().fromClass(javaComponentType); + } + + @Override + public AssumptionResult findLeafConcreteSubtype() { + HotSpotVMConfig config = runtime().getConfig(); + if (isArray()) { + return getElementalType().isLeaf() ? new AssumptionResult<>(this) : null; + } else if (isInterface()) { + HotSpotResolvedObjectTypeImpl implementor = getSingleImplementor(); + /* + * If the implementor field contains itself that indicates that the interface has more + * than one implementors (see: InstanceKlass::add_implementor). + */ + if (implementor == null || implementor.equals(this)) { + return null; + } + + assert !implementor.isInterface(); + if (implementor.isAbstract() || !implementor.isLeafClass()) { + AssumptionResult leafConcreteSubtype = implementor.findLeafConcreteSubtype(); + if (leafConcreteSubtype != null) { + assert !leafConcreteSubtype.getResult().equals(implementor); + AssumptionResult newResult = new AssumptionResult<>(leafConcreteSubtype.getResult(), new ConcreteSubtype(this, implementor)); + // Accumulate leaf assumptions and return the combined result. + newResult.add(leafConcreteSubtype); + return newResult; + } + return null; + } + + return new AssumptionResult<>(implementor, new LeafType(implementor), new ConcreteSubtype(this, implementor)); + } else { + HotSpotResolvedObjectTypeImpl type = this; + while (type.isAbstract()) { + HotSpotResolvedObjectTypeImpl subklass = type.getSubklass(); + if (subklass == null || UNSAFE.getAddress(subklass.getMetaspaceKlass() + config.nextSiblingOffset) != 0) { + return null; + } + type = subklass; + } + if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) { + return null; + } + if (this.isAbstract()) { + return new AssumptionResult<>(type, new LeafType(type), new ConcreteSubtype(this, type)); + } else { + assert this.equals(type); + return new AssumptionResult<>(type, new LeafType(type)); + } + } + } + + /** + * Returns if type {@code type} is a leaf class. This is the case if the + * {@code Klass::_subklass} field of the underlying class is zero. + * + * @return true if the type is a leaf class + */ + private boolean isLeafClass() { + return getSubklass() == null; + } + + /** + * Returns the {@code Klass::_subklass} field of the underlying metaspace klass for the given + * type {@code type}. + * + * @return value of the subklass field as metaspace klass pointer + */ + private HotSpotResolvedObjectTypeImpl getSubklass() { + return runtime().getCompilerToVM().getResolvedJavaType(this, runtime().getConfig().subklassOffset, false); + } + + @Override + public HotSpotResolvedObjectTypeImpl getSuperclass() { + Class javaSuperclass = mirror().getSuperclass(); + return javaSuperclass == null ? null : fromObjectClass(javaSuperclass); + } + + @Override + public HotSpotResolvedObjectTypeImpl[] getInterfaces() { + if (interfaces == null) { + Class[] javaInterfaces = mirror().getInterfaces(); + HotSpotResolvedObjectTypeImpl[] result = new HotSpotResolvedObjectTypeImpl[javaInterfaces.length]; + for (int i = 0; i < javaInterfaces.length; i++) { + result[i] = fromObjectClass(javaInterfaces[i]); + } + interfaces = result; + } + return interfaces; + } + + @Override + public HotSpotResolvedObjectTypeImpl getSingleImplementor() { + if (!isInterface()) { + throw new JVMCIError("Cannot call getSingleImplementor() on a non-interface type: %s", this); + } + return runtime().getCompilerToVM().getImplementor(this); + } + + public HotSpotResolvedObjectTypeImpl getSupertype() { + if (isArray()) { + ResolvedJavaType componentType = getComponentType(); + if (mirror() == Object[].class || componentType.isPrimitive()) { + return fromObjectClass(Object.class); + } + return (HotSpotResolvedObjectTypeImpl) ((HotSpotResolvedObjectTypeImpl) componentType).getSupertype().getArrayClass(); + } + if (isInterface()) { + return fromObjectClass(Object.class); + } + return getSuperclass(); + } + + @Override + public HotSpotResolvedObjectType findLeastCommonAncestor(ResolvedJavaType otherType) { + if (otherType.isPrimitive()) { + return null; + } else { + HotSpotResolvedObjectTypeImpl t1 = this; + HotSpotResolvedObjectTypeImpl t2 = (HotSpotResolvedObjectTypeImpl) otherType; + while (true) { + if (t1.isAssignableFrom(t2)) { + return t1; + } + if (t2.isAssignableFrom(t1)) { + return t2; + } + t1 = t1.getSupertype(); + t2 = t2.getSupertype(); + } + } + } + + @Override + public HotSpotResolvedObjectType asExactType() { + return isLeaf() ? this : null; + } + + @Override + public JavaConstant getJavaClass() { + return HotSpotObjectConstantImpl.forObject(mirror()); + } + + @Override + public JavaConstant getObjectHub() { + return klass(); + } + + @Override + public AssumptionResult hasFinalizableSubclass() { + assert !isArray(); + if (!runtime().getCompilerToVM().hasFinalizableSubclass(this)) { + return new AssumptionResult<>(false, new NoFinalizableSubclass(this)); + } + return new AssumptionResult<>(true); + } + + @Override + public boolean hasFinalizer() { + HotSpotVMConfig config = runtime().getConfig(); + return (getAccessFlags() & config.klassHasFinalizerFlag) != 0; + } + + @Override + public boolean isPrimitive() { + return false; + } + + @Override + public boolean isArray() { + return mirror().isArray(); + } + + @Override + public boolean isInitialized() { + return isArray() ? true : getInitState() == runtime().getConfig().instanceKlassStateFullyInitialized; + } + + @Override + public boolean isLinked() { + return isArray() ? true : getInitState() >= runtime().getConfig().instanceKlassStateLinked; + } + + /** + * Returns the value of the state field {@code InstanceKlass::_init_state} of the metaspace + * klass. + * + * @return state field value of this type + */ + private int getInitState() { + assert !isArray() : "_init_state only exists in InstanceKlass"; + return UNSAFE.getByte(getMetaspaceKlass() + runtime().getConfig().instanceKlassInitStateOffset) & 0xFF; + } + + @Override + public void initialize() { + if (!isInitialized()) { + UNSAFE.ensureClassInitialized(mirror()); + assert isInitialized(); + } + } + + @Override + public boolean isInstance(JavaConstant obj) { + if (obj.getJavaKind() == JavaKind.Object && !obj.isNull()) { + return mirror().isInstance(((HotSpotObjectConstantImpl) obj).object()); + } + return false; + } + + @Override + public boolean isInstanceClass() { + return !isArray() && !isInterface(); + } + + @Override + public boolean isInterface() { + return mirror().isInterface(); + } + + @Override + public boolean isAssignableFrom(ResolvedJavaType other) { + assert other != null; + if (other instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl otherType = (HotSpotResolvedObjectTypeImpl) other; + return mirror().isAssignableFrom(otherType.mirror()); + } + return false; + } + + @Override + public boolean isJavaLangObject() { + return javaClass.equals(Object.class); + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + ResolvedJavaMethod resolvedMethod = resolveMethod(method, callerType); + if (resolvedMethod == null || resolvedMethod.isAbstract()) { + return null; + } + return resolvedMethod; + } + + @Override + public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + assert !callerType.isArray(); + if (method.isConcrete() && method.getDeclaringClass().equals(this) && method.isPublic()) { + return method; + } + if (!method.getDeclaringClass().isAssignableFrom(this)) { + return null; + } + HotSpotResolvedJavaMethodImpl hotSpotMethod = (HotSpotResolvedJavaMethodImpl) method; + HotSpotResolvedObjectTypeImpl hotSpotCallerType = (HotSpotResolvedObjectTypeImpl) callerType; + return runtime().getCompilerToVM().resolveMethod(this, hotSpotMethod, hotSpotCallerType); + } + + public HotSpotConstantPool getConstantPool() { + if (constantPool == null) { + constantPool = runtime().getCompilerToVM().getConstantPool(this, runtime().getConfig().instanceKlassConstantsOffset); + } + return constantPool; + } + + /** + * Gets the instance size of this type. If an instance of this type cannot be fast path + * allocated, then the returned value is negative (its absolute value gives the size). Must not + * be called if this is an array or interface type. + */ + public int instanceSize() { + assert !isArray(); + assert !isInterface(); + + HotSpotVMConfig config = runtime().getConfig(); + final int layoutHelper = layoutHelper(); + assert layoutHelper > config.klassLayoutHelperNeutralValue : "must be instance"; + + // See: Klass::layout_helper_size_in_bytes + int size = layoutHelper & ~config.klassLayoutHelperInstanceSlowPathBit; + + // See: Klass::layout_helper_needs_slow_path + boolean needsSlowPath = (layoutHelper & config.klassLayoutHelperInstanceSlowPathBit) != 0; + + return needsSlowPath ? -size : size; + } + + public int layoutHelper() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset); + } + + synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) { + HotSpotResolvedJavaMethodImpl method = null; + if (methodCache == null) { + methodCache = new HashMap<>(8); + } else { + method = methodCache.get(metaspaceMethod); + } + if (method == null) { + method = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod); + methodCache.put(metaspaceMethod, method); + context.add(method); + } + return method; + } + + public int getVtableLength() { + HotSpotVMConfig config = runtime().getConfig(); + if (isInterface() || isArray()) { + /* Everything has the core vtable of java.lang.Object */ + return config.baseVtableLength(); + } + int result = UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) / (config.vtableEntrySize / config.heapWordSize); + assert result >= config.baseVtableLength() : UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) + " " + config.vtableEntrySize; + return result; + } + + public synchronized HotSpotResolvedJavaField createField(String fieldName, JavaType type, long offset, int rawFlags) { + HotSpotResolvedJavaField result = null; + + final int flags = rawFlags & ModifiersProvider.jvmFieldModifiers(); + + final long id = offset + ((long) flags << 32); + + // Must cache the fields, because the local load elimination only works if the + // objects from two field lookups are identical. + if (fieldCache == null) { + fieldCache = new HashMap<>(8); + } else { + result = fieldCache.get(id); + } + + if (result == null) { + result = new HotSpotResolvedJavaFieldImpl(this, fieldName, type, offset, rawFlags); + fieldCache.put(id, result); + } else { + assert result.getName().equals(fieldName); + // assert result.getType().equals(type); + assert result.offset() == offset; + assert result.getModifiers() == flags; + } + + return result; + } + + @Override + public AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method) { + HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method; + HotSpotResolvedObjectType declaredHolder = hmethod.getDeclaringClass(); + /* + * Sometimes the receiver type in the graph hasn't stabilized to a subtype of declared + * holder, usually because of phis, so make sure that the type is related to the declared + * type before using it for lookup. Unlinked types should also be ignored because we can't + * resolve the proper method to invoke. Generally unlinked types in invokes should result in + * a deopt instead since they can't really be used if they aren't linked yet. + */ + if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder) || !isLinked() || isInterface()) { + ResolvedJavaMethod result = hmethod.uniqueConcreteMethod(declaredHolder); + if (result != null) { + return new AssumptionResult<>(result, new ConcreteMethod(method, declaredHolder, result)); + } + return null; + } + /* + * The holder may be a subtype of the declaredHolder so make sure to resolve the method to + * the correct method for the subtype. + */ + HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) resolveMethod(hmethod, this); + if (resolvedMethod == null) { + // The type isn't known to implement the method. + return null; + } + + ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this); + if (result != null) { + return new AssumptionResult<>(result, new ConcreteMethod(method, this, result)); + } + return null; + } + + /** + * This class represents the field information for one field contained in the fields array of an + * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. + */ + private class FieldInfo { + /** + * Native pointer into the array of Java shorts. + */ + private final long metaspaceData; + + /** + * Creates a field info for the field in the fields array at index {@code index}. + * + * @param index index to the fields array + */ + public FieldInfo(int index) { + HotSpotVMConfig config = runtime().getConfig(); + // Get Klass::_fields + final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); + assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code"; + metaspaceData = metaspaceFields + config.arrayU2DataOffset + config.fieldInfoFieldSlots * Short.BYTES * index; + } + + private int getAccessFlags() { + return readFieldSlot(runtime().getConfig().fieldInfoAccessFlagsOffset); + } + + private int getNameIndex() { + return readFieldSlot(runtime().getConfig().fieldInfoNameIndexOffset); + } + + private int getSignatureIndex() { + return readFieldSlot(runtime().getConfig().fieldInfoSignatureIndexOffset); + } + + public int getOffset() { + HotSpotVMConfig config = runtime().getConfig(); + final int lowPacked = readFieldSlot(config.fieldInfoLowPackedOffset); + final int highPacked = readFieldSlot(config.fieldInfoHighPackedOffset); + final int offset = ((highPacked << Short.SIZE) | lowPacked) >> config.fieldInfoTagSize; + return offset; + } + + /** + * Helper method to read an entry (slot) from the field array. Currently field info is laid + * on top an array of Java shorts. + */ + private int readFieldSlot(int index) { + return UNSAFE.getChar(metaspaceData + Short.BYTES * index); + } + + /** + * Returns the name of this field as a {@link String}. If the field is an internal field the + * name index is pointing into the vmSymbols table. + */ + public String getName() { + final int nameIndex = getNameIndex(); + return isInternal() ? HotSpotVmSymbols.symbolAt(nameIndex) : getConstantPool().lookupUtf8(nameIndex); + } + + /** + * Returns the signature of this field as {@link String}. If the field is an internal field + * the signature index is pointing into the vmSymbols table. + */ + public String getSignature() { + final int signatureIndex = getSignatureIndex(); + return isInternal() ? HotSpotVmSymbols.symbolAt(signatureIndex) : getConstantPool().lookupUtf8(signatureIndex); + } + + public JavaType getType() { + String signature = getSignature(); + return runtime().lookupType(signature, HotSpotResolvedObjectTypeImpl.this, false); + } + + private boolean isInternal() { + return (getAccessFlags() & runtime().getConfig().jvmAccFieldInternal) != 0; + } + + public boolean isStatic() { + return Modifier.isStatic(getAccessFlags()); + } + + public boolean hasGenericSignature() { + return (getAccessFlags() & runtime().getConfig().jvmAccFieldHasGenericSignature) != 0; + } + } + + private static class OffsetComparator implements java.util.Comparator { + @Override + public int compare(HotSpotResolvedJavaField o1, HotSpotResolvedJavaField o2) { + return o1.offset() - o2.offset(); + } + } + + @Override + public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { + if (instanceFields == null) { + if (isArray() || isInterface()) { + instanceFields = new HotSpotResolvedJavaField[0]; + } else { + final int fieldCount = getFieldCount(); + ArrayList fieldsArray = new ArrayList<>(fieldCount); + + for (int i = 0; i < fieldCount; i++) { + FieldInfo field = new FieldInfo(i); + + // We are only interested in instance fields. + if (!field.isStatic()) { + HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); + fieldsArray.add(resolvedJavaField); + } + } + + fieldsArray.sort(new OffsetComparator()); + + HotSpotResolvedJavaField[] myFields = fieldsArray.toArray(new HotSpotResolvedJavaField[0]); + + if (mirror() != Object.class) { + HotSpotResolvedJavaField[] superFields = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); + HotSpotResolvedJavaField[] fields = Arrays.copyOf(superFields, superFields.length + myFields.length); + System.arraycopy(myFields, 0, fields, superFields.length, myFields.length); + instanceFields = fields; + } else { + assert myFields.length == 0 : "java.lang.Object has fields!"; + instanceFields = myFields; + } + + } + } + if (!includeSuperclasses) { + int myFieldsStart = 0; + while (myFieldsStart < instanceFields.length && !instanceFields[myFieldsStart].getDeclaringClass().equals(this)) { + myFieldsStart++; + } + if (myFieldsStart == 0) { + return instanceFields; + } + if (myFieldsStart == instanceFields.length) { + return new HotSpotResolvedJavaField[0]; + } + return Arrays.copyOfRange(instanceFields, myFieldsStart, instanceFields.length); + } + return instanceFields; + } + + @Override + public ResolvedJavaField[] getStaticFields() { + if (isArray()) { + return new HotSpotResolvedJavaField[0]; + } else { + final int fieldCount = getFieldCount(); + ArrayList fieldsArray = new ArrayList<>(fieldCount); + + for (int i = 0; i < fieldCount; i++) { + FieldInfo field = new FieldInfo(i); + + // We are only interested in static fields. + if (field.isStatic()) { + HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); + fieldsArray.add(resolvedJavaField); + } + } + + fieldsArray.sort(new OffsetComparator()); + return fieldsArray.toArray(new HotSpotResolvedJavaField[fieldsArray.size()]); + } + } + + /** + * Returns the actual field count of this class's internal {@code InstanceKlass::_fields} array + * by walking the array and discounting the generic signature slots at the end of the array. + * + *

+ * See {@code FieldStreamBase::init_generic_signature_start_slot} + */ + private int getFieldCount() { + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); + int metaspaceFieldsLength = UNSAFE.getInt(metaspaceFields + config.arrayU1LengthOffset); + int fieldCount = 0; + + for (int i = 0, index = 0; i < metaspaceFieldsLength; i += config.fieldInfoFieldSlots, index++) { + FieldInfo field = new FieldInfo(index); + if (field.hasGenericSignature()) { + metaspaceFieldsLength--; + } + fieldCount++; + } + return fieldCount; + } + + @Override + public Class mirror() { + return javaClass; + } + + @Override + public String getSourceFileName() { + HotSpotVMConfig config = runtime().getConfig(); + final int sourceFileNameIndex = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassSourceFileNameIndexOffset); + if (sourceFileNameIndex == 0) { + return null; + } + return getConstantPool().lookupUtf8(sourceFileNameIndex); + } + + @Override + public Annotation[] getAnnotations() { + return mirror().getAnnotations(); + } + + @Override + public T getAnnotation(Class annotationClass) { + return mirror().getAnnotation(annotationClass); + } + + /** + * Performs a fast-path check that this type is resolved in the context of a given accessing + * class. A negative result does not mean this type is not resolved with respect to + * {@code accessingClass}. That can only be determined by + * {@linkplain HotSpotJVMCIRuntime#lookupType(String, HotSpotResolvedObjectType, boolean) + * re-resolving} the type. + */ + public boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass) { + assert accessingClass != null; + ResolvedJavaType elementType = getElementalType(); + if (elementType.isPrimitive()) { + // Primitive type resolution is context free. + return true; + } + if (elementType.getName().startsWith("Ljava/")) { + // Classes in a java.* package can only be defined by the + // boot class loader. This is enforced by ClassLoader.preDefineClass() + assert mirror().getClassLoader() == null; + return true; + } + ClassLoader thisCl = mirror().getClassLoader(); + ClassLoader accessingClassCl = ((HotSpotResolvedObjectTypeImpl) accessingClass).mirror().getClassLoader(); + return thisCl == accessingClassCl; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + if (isDefinitelyResolvedWithRespectTo(requireNonNull(accessingClass))) { + return this; + } + HotSpotResolvedObjectTypeImpl accessingType = (HotSpotResolvedObjectTypeImpl) accessingClass; + return (ResolvedJavaType) runtime().lookupType(getName(), accessingType, true); + } + + /** + * Gets the metaspace Klass boxed in a {@link JavaConstant}. + */ + public JavaConstant klass() { + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(runtime().getHostJVMCIBackend().getTarget().wordKind, getMetaspaceKlass(), this, false); + } + + public boolean isPrimaryType() { + return runtime().getConfig().secondarySuperCacheOffset != superCheckOffset(); + } + + public int superCheckOffset() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getInt(getMetaspaceKlass() + config.superCheckOffsetOffset); + } + + public long prototypeMarkWord() { + HotSpotVMConfig config = runtime().getConfig(); + if (isArray()) { + return config.arrayPrototypeMarkWord(); + } else { + return UNSAFE.getAddress(getMetaspaceKlass() + config.prototypeMarkWordOffset); + } + } + + @Override + public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedEntryKind) { + ResolvedJavaField[] declaredFields = getInstanceFields(true); + for (ResolvedJavaField field : declaredFields) { + HotSpotResolvedJavaField resolvedField = (HotSpotResolvedJavaField) field; + long resolvedFieldOffset = resolvedField.offset(); + // @formatter:off + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && + expectedEntryKind.isPrimitive() && + !expectedEntryKind.equals(JavaKind.Void) && + resolvedField.getJavaKind().isPrimitive()) { + resolvedFieldOffset += + resolvedField.getJavaKind().getByteCount() - + Math.min(resolvedField.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()); + } + if (resolvedFieldOffset == offset) { + return field; + } + // @formatter:on + } + return null; + } + + @Override + public URL getClassFilePath() { + Class cls = mirror(); + return cls.getResource(MetaUtil.getSimpleName(cls, true).replace('.', '$') + ".class"); + } + + @Override + public boolean isLocal() { + return mirror().isLocalClass(); + } + + @Override + public boolean isMember() { + return mirror().isMemberClass(); + } + + @Override + public HotSpotResolvedObjectTypeImpl getEnclosingType() { + final Class encl = mirror().getEnclosingClass(); + return encl == null ? null : fromObjectClass(encl); + } + + @Override + public ResolvedJavaMethod[] getDeclaredConstructors() { + Constructor[] constructors = mirror().getDeclaredConstructors(); + ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length]; + for (int i = 0; i < constructors.length; i++) { + result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(constructors[i]); + assert result[i].isConstructor(); + } + return result; + } + + @Override + public ResolvedJavaMethod[] getDeclaredMethods() { + Method[] methods = mirror().getDeclaredMethods(); + ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length]; + for (int i = 0; i < methods.length; i++) { + result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(methods[i]); + assert !result[i].isConstructor(); + } + return result; + } + + public ResolvedJavaMethod getClassInitializer() { + return runtime().getCompilerToVM().getClassInitializer(this); + } + + @Override + public String toString() { + return "HotSpotType<" + getName() + ", resolved>"; + } + + @Override + public boolean isTrustedInterfaceType() { + return TrustedInterface.class.isAssignableFrom(mirror()); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static java.util.Objects.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.AssumptionResult; + +/** + * Implementation of {@link JavaType} for primitive HotSpot types. + */ +public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType implements HotSpotProxified { + + private final JavaKind kind; + + /** + * Creates the JVMCI mirror for a primitive {@link JavaKind}. + * + *

+ * NOTE: Creating an instance of this class does not install the mirror for the + * {@link Class} type. Use {@link HotSpotJVMCIRuntimeProvider#fromClass(Class)} instead. + *

+ * + * @param kind the Kind to create the mirror for + */ + public HotSpotResolvedPrimitiveType(JavaKind kind) { + super(String.valueOf(Character.toUpperCase(kind.getTypeChar()))); + this.kind = kind; + assert mirror().isPrimitive() : mirror() + " not a primitive type"; + } + + @Override + public int getModifiers() { + return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; + } + + @Override + public HotSpotResolvedObjectTypeImpl getArrayClass() { + if (kind == JavaKind.Void) { + return null; + } + Class javaArrayMirror = Array.newInstance(mirror(), 0).getClass(); + return HotSpotResolvedObjectTypeImpl.fromObjectClass(javaArrayMirror); + } + + public ResolvedJavaType getElementalType() { + return this; + } + + @Override + public ResolvedJavaType getComponentType() { + return null; + } + + @Override + public ResolvedJavaType asExactType() { + return this; + } + + @Override + public ResolvedJavaType getSuperclass() { + return null; + } + + @Override + public ResolvedJavaType[] getInterfaces() { + return new ResolvedJavaType[0]; + } + + @Override + public ResolvedJavaType getSingleImplementor() { + throw new JVMCIError("Cannot call getSingleImplementor() on a non-interface type: %s", this); + } + + @Override + public ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType) { + return null; + } + + @Override + public JavaConstant getObjectHub() { + throw JVMCIError.unimplemented(); + } + + @Override + public JavaConstant getJavaClass() { + throw JVMCIError.unimplemented(); + } + + @Override + public AssumptionResult hasFinalizableSubclass() { + return new AssumptionResult<>(false); + } + + @Override + public boolean hasFinalizer() { + return false; + } + + @Override + public boolean isArray() { + return false; + } + + @Override + public boolean isPrimitive() { + return true; + } + + @Override + public boolean isInitialized() { + return true; + } + + public boolean isLinked() { + return true; + } + + @Override + public boolean isInstance(JavaConstant obj) { + return false; + } + + @Override + public boolean isInstanceClass() { + return false; + } + + @Override + public boolean isInterface() { + return false; + } + + @Override + public boolean isAssignableFrom(ResolvedJavaType other) { + assert other != null; + return other.equals(this); + } + + @Override + public JavaKind getJavaKind() { + return kind; + } + + @Override + public boolean isJavaLangObject() { + return false; + } + + @Override + public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + return null; + } + + @Override + public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { + return null; + } + + @Override + public String toString() { + return "HotSpotResolvedPrimitiveType<" + kind + ">"; + } + + @Override + public AssumptionResult findLeafConcreteSubtype() { + return new AssumptionResult<>(this); + } + + @Override + public AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method) { + return null; + } + + @Override + public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { + return new ResolvedJavaField[0]; + } + + @Override + public ResolvedJavaField[] getStaticFields() { + return new ResolvedJavaField[0]; + } + + @Override + public Annotation[] getAnnotations() { + return new Annotation[0]; + } + + @Override + public T getAnnotation(Class annotationClass) { + return null; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + requireNonNull(accessingClass); + return this; + } + + @Override + public void initialize() { + } + + @Override + public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedType) { + return null; + } + + @Override + public String getSourceFileName() { + throw JVMCIError.unimplemented(); + } + + @Override + public Class mirror() { + return kind.toJavaClass(); + } + + @Override + public URL getClassFilePath() { + return null; + } + + @Override + public boolean isLocal() { + return false; + } + + @Override + public boolean isMember() { + return false; + } + + @Override + public ResolvedJavaType getEnclosingType() { + return null; + } + + @Override + public ResolvedJavaMethod[] getDeclaredConstructors() { + return new ResolvedJavaMethod[0]; + } + + @Override + public ResolvedJavaMethod[] getDeclaredMethods() { + return new ResolvedJavaMethod[0]; + } + + @Override + public ResolvedJavaMethod getClassInitializer() { + return null; + } + + @Override + public boolean isTrustedInterfaceType() { + return false; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +public final class HotSpotSentinelConstant extends Value implements JavaConstant, VMConstant { + + public HotSpotSentinelConstant(JavaKind kind) { + super(LIRKind.reference(kind)); + } + + public JavaKind getJavaKind() { + return (JavaKind) getLIRKind().getPlatformKind(); + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean isDefaultForKind() { + return true; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return JavaConstant.toString(this); + } + + @Override + public String toValueString() { + return "sentinel"; + } + + @Override + public int hashCode() { + return 13; + } + + @Override + public boolean equals(Object o) { + return o instanceof HotSpotSentinelConstant; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import java.util.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; + +/** + * Represents a method signature. + */ +public class HotSpotSignature implements Signature { + + private final List parameters = new ArrayList<>(); + private final String returnType; + private final String originalString; + private ResolvedJavaType[] parameterTypes; + private ResolvedJavaType returnTypeCache; + private final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, String signature) { + this.runtime = runtime; + assert signature.length() > 0; + this.originalString = signature; + + if (signature.charAt(0) == '(') { + int cur = 1; + while (cur < signature.length() && signature.charAt(cur) != ')') { + int nextCur = parseSignature(signature, cur); + parameters.add(signature.substring(cur, nextCur)); + cur = nextCur; + } + + cur++; + int nextCur = parseSignature(signature, cur); + returnType = signature.substring(cur, nextCur); + assert nextCur == signature.length(); + } else { + returnType = null; + } + } + + public HotSpotSignature(HotSpotJVMCIRuntimeProvider runtime, ResolvedJavaType returnType, ResolvedJavaType... parameterTypes) { + this.runtime = runtime; + this.parameterTypes = parameterTypes.clone(); + this.returnTypeCache = returnType; + this.returnType = returnType.getName(); + StringBuilder sb = new StringBuilder("("); + for (JavaType type : parameterTypes) { + parameters.add(type.getName()); + sb.append(type.getName()); + } + sb.append(")").append(returnType.getName()); + this.originalString = sb.toString(); + assert new HotSpotSignature(runtime, originalString).equals(this); + } + + private static int parseSignature(String signature, int start) { + int cur = start; + char first; + do { + first = signature.charAt(cur++); + } while (first == '['); + + switch (first) { + case 'L': + while (signature.charAt(cur) != ';') { + cur++; + } + cur++; + break; + case 'V': + case 'I': + case 'B': + case 'C': + case 'D': + case 'F': + case 'J': + case 'S': + case 'Z': + break; + default: + throw new JVMCIError("Invalid character at index %d in signature: %s", cur, signature); + } + return cur; + } + + @Override + public int getParameterCount(boolean withReceiver) { + return parameters.size() + (withReceiver ? 1 : 0); + } + + @Override + public JavaKind getParameterKind(int index) { + return JavaKind.fromTypeString(parameters.get(index)); + } + + private static boolean checkValidCache(ResolvedJavaType type, ResolvedJavaType accessingClass) { + assert accessingClass != null; + if (type == null) { + return false; + } else if (type instanceof HotSpotResolvedObjectTypeImpl) { + return ((HotSpotResolvedObjectTypeImpl) type).isDefinitelyResolvedWithRespectTo(accessingClass); + } + return true; + } + + private static JavaType getUnresolvedOrPrimitiveType(HotSpotJVMCIRuntimeProvider runtime, String name) { + if (name.length() == 1) { + JavaKind kind = JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)); + return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(kind.toJavaClass()); + } + return new HotSpotUnresolvedJavaType(name, runtime); + } + + @Override + public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { + if (accessingClass == null) { + // Caller doesn't care about resolution context so return an unresolved + // or primitive type (primitive type resolution is context free) + return getUnresolvedOrPrimitiveType(runtime, parameters.get(index)); + } + if (parameterTypes == null) { + parameterTypes = new ResolvedJavaType[parameters.size()]; + } + + ResolvedJavaType type = parameterTypes[index]; + if (!checkValidCache(type, accessingClass)) { + JavaType result = runtime.lookupType(parameters.get(index), (HotSpotResolvedObjectType) accessingClass, false); + if (result instanceof ResolvedJavaType) { + type = (ResolvedJavaType) result; + parameterTypes[index] = type; + } else { + return result; + } + } + return type; + } + + @Override + public String toMethodDescriptor() { + assert originalString.equals(Signature.super.toMethodDescriptor()); + return originalString; + } + + @Override + public JavaKind getReturnKind() { + return JavaKind.fromTypeString(returnType); + } + + @Override + public JavaType getReturnType(ResolvedJavaType accessingClass) { + if (accessingClass == null) { + // Caller doesn't care about resolution context so return an unresolved + // or primitive type (primitive type resolution is context free) + return getUnresolvedOrPrimitiveType(runtime, returnType); + } + if (!checkValidCache(returnTypeCache, accessingClass)) { + JavaType result = runtime.lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false); + if (result instanceof ResolvedJavaType) { + returnTypeCache = (ResolvedJavaType) result; + } else { + return result; + } + } + return returnTypeCache; + } + + @Override + public String toString() { + return "HotSpotSignature<" + originalString + ">"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof HotSpotSignature) { + HotSpotSignature other = (HotSpotSignature) obj; + if (other.originalString.equals(originalString)) { + assert other.parameters.equals(parameters); + assert other.returnType.equals(returnType); + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return originalString.hashCode(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +public class HotSpotSpeculationLog extends SpeculationLog { + + @Override + public JavaConstant speculate(Object reason) { + addSpeculation(reason); + return HotSpotObjectConstantImpl.forObject(reason); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import java.util.*; + +import jdk.vm.ci.code.stack.*; +import jdk.vm.ci.meta.*; + +public class HotSpotStackFrameReference implements InspectedFrame { + + private CompilerToVM compilerToVM; + + // information used to find the stack frame + private long stackPointer; + private int frameNumber; + + // information about the stack frame's contents + private int bci; + private HotSpotResolvedJavaMethod method; + private Object[] locals; + private boolean[] localIsVirtual; + + public long getStackPointer() { + return stackPointer; + } + + public int getFrameNumber() { + return frameNumber; + } + + @Override + public Object getLocal(int index) { + return locals[index]; + } + + @Override + public boolean isVirtual(int index) { + return localIsVirtual == null ? false : localIsVirtual[index]; + } + + @Override + public void materializeVirtualObjects(boolean invalidateCode) { + compilerToVM.materializeVirtualObjects(this, invalidateCode); + } + + @Override + public int getBytecodeIndex() { + return bci; + } + + @Override + public ResolvedJavaMethod getMethod() { + return method; + } + + @Override + public boolean isMethod(ResolvedJavaMethod otherMethod) { + return method.equals(otherMethod); + } + + @Override + public boolean hasVirtualObjects() { + return localIsVirtual != null; + } + + @Override + public String toString() { + return "HotSpotStackFrameReference [stackPointer=" + stackPointer + ", frameNumber=" + frameNumber + ", bci=" + bci + ", method=" + getMethod() + ", locals=" + Arrays.toString(locals) + + ", localIsVirtual=" + Arrays.toString(localIsVirtual) + "]"; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedField.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * A implementation of {@link JavaField} for an unresolved field. + */ +public class HotSpotUnresolvedField implements JavaField { + + private final String name; + private final JavaType holder; + private final JavaType type; + + public HotSpotUnresolvedField(JavaType holder, String name, JavaType type) { + this.name = name; + this.type = type; + this.holder = holder; + } + + public String getName() { + return name; + } + + public JavaType getType() { + return type; + } + + public JavaType getDeclaringClass() { + return holder; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof HotSpotUnresolvedField)) { + return false; + } + HotSpotUnresolvedField that = (HotSpotUnresolvedField) obj; + return this.holder.equals(that.holder) && this.name.equals(that.name) && this.type.equals(that.type); + } + + /** + * Converts this compiler interface field to a string. + */ + @Override + public String toString() { + return format("HotSpotField<%H.%n %t, unresolved>"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedJavaType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotUnresolvedJavaType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.*; + +/** + * Implementation of {@link JavaType} for unresolved HotSpot classes. + */ +public class HotSpotUnresolvedJavaType extends HotSpotJavaType { + + private final HotSpotJVMCIRuntimeProvider runtime; + + public HotSpotUnresolvedJavaType(String name, HotSpotJVMCIRuntimeProvider runtime) { + super(name); + assert name.charAt(0) == '[' || name.charAt(name.length() - 1) == ';' : name; + this.runtime = runtime; + } + + /** + * Creates an unresolved type for a valid {@link JavaType#getName() type name}. + */ + public static HotSpotUnresolvedJavaType create(HotSpotJVMCIRuntimeProvider runtime, String name) { + return new HotSpotUnresolvedJavaType(name, runtime); + } + + @Override + public JavaType getComponentType() { + assert getName().charAt(0) == '[' : "no array class" + getName(); + return new HotSpotUnresolvedJavaType(getName().substring(1), runtime); + } + + @Override + public JavaType getArrayClass() { + return new HotSpotUnresolvedJavaType('[' + getName(), runtime); + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public int hashCode() { + return getName().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof HotSpotUnresolvedJavaType)) { + return false; + } + HotSpotUnresolvedJavaType that = (HotSpotUnresolvedJavaType) obj; + return this.getName().equals(that.getName()); + } + + @Override + public String toString() { + return "HotSpotType<" + getName() + ", unresolved>"; + } + + @Override + public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { + return (ResolvedJavaType) runtime.lookupType(getName(), (HotSpotResolvedObjectType) accessingClass, true); + } + + /** + * Try to find a loaded version of this class. + * + * @param accessingClass + * @return the resolved class or null. + */ + ResolvedJavaType reresolve(HotSpotResolvedObjectType accessingClass) { + JavaType type = runtime.lookupType(getName(), accessingClass, false); + if (type instanceof ResolvedJavaType) { + return (ResolvedJavaType) type; + } + return null; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1771 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.common.UnsafeUtil.readCString; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.reflect.*; +import java.util.*; + +import sun.misc.*; +import jdk.vm.ci.common.*; +import jdk.vm.ci.hotspotvmconfig.*; + +//JaCoCo Exclude + +/** + * Used to access native configuration details. + * + * All non-static, public fields in this class are so that they can be compiled as constants. + */ +public class HotSpotVMConfig { + + /** + * Maximum allowed size of allocated area for a frame. + */ + public final int maxFrameSize = 16 * 1024; + + public HotSpotVMConfig(CompilerToVM compilerToVm) { + // Get raw pointer to the array that contains all gHotSpotVM values. + final long gHotSpotVMData = compilerToVm.initializeConfiguration(); + assert gHotSpotVMData != 0; + + // Make FindBugs happy. + gHotSpotVMStructs = 0; + gHotSpotVMTypes = 0; + gHotSpotVMIntConstants = 0; + gHotSpotVMLongConstants = 0; + gHotSpotVMAddresses = 0; + + // Initialize the gHotSpotVM fields. + for (Field f : HotSpotVMConfig.class.getDeclaredFields()) { + if (f.isAnnotationPresent(HotSpotVMData.class)) { + HotSpotVMData annotation = f.getAnnotation(HotSpotVMData.class); + final int index = annotation.index(); + final long value = UNSAFE.getAddress(gHotSpotVMData + Unsafe.ADDRESS_SIZE * index); + try { + f.setLong(this, value); + } catch (IllegalAccessException e) { + throw new JVMCIError("index " + index, e); + } + } + } + + // Quick sanity check. + assert gHotSpotVMStructs != 0; + assert gHotSpotVMTypes != 0; + assert gHotSpotVMIntConstants != 0; + assert gHotSpotVMLongConstants != 0; + assert gHotSpotVMAddresses != 0; + + initialize(); + + oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment()); + klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment); + + final long barrierSetAddress = UNSAFE.getAddress(universeCollectedHeap + collectedHeapBarrierSetOffset); + final int kind = UNSAFE.getInt(barrierSetAddress + barrierSetFakeRttiOffset + fakeRttiConcreteTagOffset); + if ((kind == barrierSetCardTableModRef) || (kind == barrierSetCardTableForRS) || (kind == barrierSetCardTableExtension) || (kind == barrierSetG1SATBCT) || (kind == barrierSetG1SATBCTLogging)) { + final long base = UNSAFE.getAddress(barrierSetAddress + cardTableModRefBSByteMapBaseOffset); + assert base != 0 : "unexpected byte_map_base: " + base; + cardtableStartAddress = base; + cardtableShift = cardTableModRefBSCardShift; + } else if (kind == barrierSetModRef) { + // No post barriers + cardtableStartAddress = 0; + cardtableShift = 0; + } else { + cardtableStartAddress = -1; + cardtableShift = -1; + } + + // Now handle all HotSpotVMManual fields. + inlineCacheMissStub = inlineCacheMissBlob + UNSAFE.getInt(inlineCacheMissBlob + codeBlobCodeOffsetOffset); + handleWrongMethodStub = wrongMethodBlob + UNSAFE.getInt(wrongMethodBlob + codeBlobCodeOffsetOffset); + handleDeoptStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUnpackOffsetOffset); + uncommonTrapStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUncommonTrapOffsetOffset); + + assert check(); + assert HotSpotVMConfigVerifier.check(); + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + + /** + * Initialize fields by reading their values from vmStructs. + */ + private void initialize() { + // Fill the VM fields hash map. + HashMap vmFields = new HashMap<>(); + for (VMFields.Field e : new VMFields(gHotSpotVMStructs)) { + vmFields.put(e.getName(), e); + } + + // Fill the VM types hash map. + HashMap vmTypes = new HashMap<>(); + for (VMTypes.Type e : new VMTypes(gHotSpotVMTypes)) { + vmTypes.put(e.getTypeName(), e); + } + + // Fill the VM constants hash map. + HashMap vmConstants = new HashMap<>(); + for (AbstractConstant e : new VMIntConstants(gHotSpotVMIntConstants)) { + vmConstants.put(e.getName(), e); + } + for (AbstractConstant e : new VMAddresses(gHotSpotVMLongConstants)) { + vmConstants.put(e.getName(), e); + } + + // Fill the VM addresses hash map. + HashMap vmAddresses = new HashMap<>(); + for (VMAddresses.Address e : new VMAddresses(gHotSpotVMAddresses)) { + vmAddresses.put(e.getName(), e); + } + + // Fill the flags hash map. + HashMap flags = new HashMap<>(); + for (Flags.Flag e : new Flags(vmFields, vmTypes)) { + flags.put(e.getName(), e); + } + + String osName = getHostOSName(); + String osArch = getHostArchitectureName(); + + for (Field f : HotSpotVMConfig.class.getDeclaredFields()) { + if (f.isAnnotationPresent(HotSpotVMField.class)) { + HotSpotVMField annotation = f.getAnnotation(HotSpotVMField.class); + String name = annotation.name(); + String type = annotation.type(); + VMFields.Field entry = vmFields.get(name); + if (entry == null) { + if (!isRequired(osArch, annotation.archs())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM field not found: " + name); + } + + // Make sure the native type is still the type we expect. + if (!type.isEmpty()) { + if (!type.equals(entry.getTypeString())) { + throw new JVMCIError(f.getName() + ": compiler expects type " + type + " but VM field " + name + " is of type " + entry.getTypeString()); + } + } + + switch (annotation.get()) { + case OFFSET: + setField(f, entry.getOffset()); + break; + case ADDRESS: + setField(f, entry.getAddress()); + break; + case VALUE: + setField(f, entry.getValue()); + break; + default: + throw new JVMCIError(f.getName() + ": unknown kind: " + annotation.get()); + } + } else if (f.isAnnotationPresent(HotSpotVMType.class)) { + HotSpotVMType annotation = f.getAnnotation(HotSpotVMType.class); + String name = annotation.name(); + VMTypes.Type entry = vmTypes.get(name); + if (entry == null) { + throw new JVMCIError(f.getName() + ": expected VM type not found: " + name); + } + switch (annotation.get()) { + case SIZE: + setField(f, entry.getSize()); + break; + default: + throw new JVMCIError(f.getName() + ": unknown kind: " + annotation.get()); + } + } else if (f.isAnnotationPresent(HotSpotVMConstant.class)) { + HotSpotVMConstant annotation = f.getAnnotation(HotSpotVMConstant.class); + String name = annotation.name(); + AbstractConstant entry = vmConstants.get(name); + if (entry == null) { + if (!isRequired(osArch, annotation.archs())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM constant not found: " + name); + } + setField(f, entry.getValue()); + } else if (f.isAnnotationPresent(HotSpotVMAddress.class)) { + HotSpotVMAddress annotation = f.getAnnotation(HotSpotVMAddress.class); + String name = annotation.name(); + VMAddresses.Address entry = vmAddresses.get(name); + if (entry == null) { + if (!isRequired(osName, annotation.os())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM address not found: " + name); + } + setField(f, entry.getValue()); + } else if (f.isAnnotationPresent(HotSpotVMFlag.class)) { + HotSpotVMFlag annotation = f.getAnnotation(HotSpotVMFlag.class); + String name = annotation.name(); + Flags.Flag entry = flags.get(name); + if (entry == null) { + if (annotation.optional() || !isRequired(osArch, annotation.archs())) { + continue; + } + throw new JVMCIError(f.getName() + ": expected VM flag not found: " + name); + + } + setField(f, entry.getValue()); + } + } + } + + private final CompressEncoding oopEncoding; + private final CompressEncoding klassEncoding; + + public CompressEncoding getOopEncoding() { + return oopEncoding; + } + + public CompressEncoding getKlassEncoding() { + return klassEncoding; + } + + private void setField(Field field, Object value) { + try { + Class fieldType = field.getType(); + if (fieldType == boolean.class) { + if (value instanceof String) { + field.setBoolean(this, Boolean.valueOf((String) value)); + } else if (value instanceof Boolean) { + field.setBoolean(this, (boolean) value); + } else if (value instanceof Long) { + field.setBoolean(this, ((long) value) != 0); + } else { + throw new JVMCIError(value.getClass().getSimpleName()); + } + } else if (fieldType == byte.class) { + if (value instanceof Long) { + field.setByte(this, (byte) (long) value); + } else { + throw new JVMCIError(value.getClass().getSimpleName()); + } + } else if (fieldType == int.class) { + if (value instanceof Integer) { + field.setInt(this, (int) value); + } else if (value instanceof Long) { + field.setInt(this, (int) (long) value); + } else { + throw new JVMCIError(value.getClass().getSimpleName()); + } + } else if (fieldType == long.class) { + field.setLong(this, (long) value); + } else { + throw new JVMCIError(field.toString()); + } + } catch (IllegalAccessException e) { + throw new JVMCIError("%s: %s", field, e); + } + } + + /** + * Gets the host operating system name. + */ + private static String getHostOSName() { + String osName = System.getProperty("os.name"); + switch (osName) { + case "Linux": + osName = "linux"; + break; + case "SunOS": + osName = "solaris"; + break; + case "Mac OS X": + osName = "bsd"; + break; + default: + // Of course Windows is different... + if (osName.startsWith("Windows")) { + osName = "windows"; + } else { + throw new JVMCIError("Unexpected OS name: " + osName); + } + } + return osName; + } + + /** + * Gets the host architecture name for the purpose of finding the corresponding + * {@linkplain HotSpotJVMCIBackendFactory backend}. + */ + public String getHostArchitectureName() { + String arch = System.getProperty("os.arch"); + switch (arch) { + case "x86_64": + arch = "amd64"; + break; + case "sparcv9": + arch = "sparc"; + break; + } + return arch; + } + + /** + * Determines if the current specification is included in a given set of specifications. + * + * @param current + * @param specification specifies a set of specifications, e.g. architectures or operating + * systems. A zero length value implies all. + */ + private static boolean isRequired(String current, String[] specification) { + if (specification.length == 0) { + return true; + } + for (String arch : specification) { + if (arch.equals(current)) { + return true; + } + } + return false; + } + + /** + * VMStructEntry (see {@code vmStructs.hpp}). + */ + @HotSpotVMData(index = 0) @Stable private long gHotSpotVMStructs; + @HotSpotVMData(index = 1) @Stable private long gHotSpotVMStructEntryTypeNameOffset; + @HotSpotVMData(index = 2) @Stable private long gHotSpotVMStructEntryFieldNameOffset; + @HotSpotVMData(index = 3) @Stable private long gHotSpotVMStructEntryTypeStringOffset; + @HotSpotVMData(index = 4) @Stable private long gHotSpotVMStructEntryIsStaticOffset; + @HotSpotVMData(index = 5) @Stable private long gHotSpotVMStructEntryOffsetOffset; + @HotSpotVMData(index = 6) @Stable private long gHotSpotVMStructEntryAddressOffset; + @HotSpotVMData(index = 7) @Stable private long gHotSpotVMStructEntryArrayStride; + + final class VMFields implements Iterable { + + private final long address; + + public VMFields(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Field current() { + return new Field(address + gHotSpotVMStructEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL fieldName. + */ + public boolean hasNext() { + Field entry = current(); + return entry.getFieldName() != null; + } + + public Field next() { + Field entry = current(); + index++; + return entry; + } + }; + } + + final class Field { + + private final long entryAddress; + + Field(long address) { + this.entryAddress = address; + } + + public String getTypeName() { + long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeNameOffset); + return readCString(UNSAFE, typeNameAddress); + } + + public String getFieldName() { + long fieldNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryFieldNameOffset); + return readCString(UNSAFE, fieldNameAddress); + } + + public String getTypeString() { + long typeStringAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeStringOffset); + return readCString(UNSAFE, typeStringAddress); + } + + public boolean isStatic() { + return UNSAFE.getInt(entryAddress + gHotSpotVMStructEntryIsStaticOffset) != 0; + } + + public long getOffset() { + return UNSAFE.getLong(entryAddress + gHotSpotVMStructEntryOffsetOffset); + } + + public long getAddress() { + return UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryAddressOffset); + } + + public String getName() { + String typeName = getTypeName(); + String fieldName = getFieldName(); + return typeName + "::" + fieldName; + } + + public long getValue() { + String type = getTypeString(); + switch (type) { + case "bool": + return UNSAFE.getByte(getAddress()); + case "int": + return UNSAFE.getInt(getAddress()); + case "uint64_t": + return UNSAFE.getLong(getAddress()); + case "address": + case "intptr_t": + case "uintptr_t": + return UNSAFE.getAddress(getAddress()); + default: + // All foo* types are addresses. + if (type.endsWith("*")) { + return UNSAFE.getAddress(getAddress()); + } + throw new JVMCIError(type); + } + } + + @Override + public String toString() { + return String.format("Field[typeName=%s, fieldName=%s, typeString=%s, isStatic=%b, offset=%d, address=0x%x]", getTypeName(), getFieldName(), getTypeString(), isStatic(), getOffset(), + getAddress()); + } + } + } + + /** + * VMTypeEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 8) @Stable private long gHotSpotVMTypes; + @HotSpotVMData(index = 9) @Stable private long gHotSpotVMTypeEntryTypeNameOffset; + @HotSpotVMData(index = 10) @Stable private long gHotSpotVMTypeEntrySuperclassNameOffset; + @HotSpotVMData(index = 11) @Stable private long gHotSpotVMTypeEntryIsOopTypeOffset; + @HotSpotVMData(index = 12) @Stable private long gHotSpotVMTypeEntryIsIntegerTypeOffset; + @HotSpotVMData(index = 13) @Stable private long gHotSpotVMTypeEntryIsUnsignedOffset; + @HotSpotVMData(index = 14) @Stable private long gHotSpotVMTypeEntrySizeOffset; + @HotSpotVMData(index = 15) @Stable private long gHotSpotVMTypeEntryArrayStride; + + final class VMTypes implements Iterable { + + private final long address; + + public VMTypes(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Type current() { + return new Type(address + gHotSpotVMTypeEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL type name. + */ + public boolean hasNext() { + Type entry = current(); + return entry.getTypeName() != null; + } + + public Type next() { + Type entry = current(); + index++; + return entry; + } + }; + } + + final class Type { + + private final long entryAddress; + + Type(long address) { + this.entryAddress = address; + } + + public String getTypeName() { + long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntryTypeNameOffset); + return readCString(UNSAFE, typeNameAddress); + } + + public String getSuperclassName() { + long superclassNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntrySuperclassNameOffset); + return readCString(UNSAFE, superclassNameAddress); + } + + public boolean isOopType() { + return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsOopTypeOffset) != 0; + } + + public boolean isIntegerType() { + return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsIntegerTypeOffset) != 0; + } + + public boolean isUnsigned() { + return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsUnsignedOffset) != 0; + } + + public long getSize() { + return UNSAFE.getLong(entryAddress + gHotSpotVMTypeEntrySizeOffset); + } + + @Override + public String toString() { + return String.format("Type[typeName=%s, superclassName=%s, isOopType=%b, isIntegerType=%b, isUnsigned=%b, size=%d]", getTypeName(), getSuperclassName(), isOopType(), isIntegerType(), + isUnsigned(), getSize()); + } + } + } + + public abstract class AbstractConstant { + + protected final long address; + protected final long nameOffset; + protected final long valueOffset; + + AbstractConstant(long address, long nameOffset, long valueOffset) { + this.address = address; + this.nameOffset = nameOffset; + this.valueOffset = valueOffset; + } + + public String getName() { + long nameAddress = UNSAFE.getAddress(address + nameOffset); + return readCString(UNSAFE, nameAddress); + } + + public abstract long getValue(); + } + + /** + * VMIntConstantEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 16) @Stable private long gHotSpotVMIntConstants; + @HotSpotVMData(index = 17) @Stable private long gHotSpotVMIntConstantEntryNameOffset; + @HotSpotVMData(index = 18) @Stable private long gHotSpotVMIntConstantEntryValueOffset; + @HotSpotVMData(index = 19) @Stable private long gHotSpotVMIntConstantEntryArrayStride; + + final class VMIntConstants implements Iterable { + + private final long address; + + public VMIntConstants(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Constant current() { + return new Constant(address + gHotSpotVMIntConstantEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Constant entry = current(); + return entry.getName() != null; + } + + public Constant next() { + Constant entry = current(); + index++; + return entry; + } + }; + } + + final class Constant extends AbstractConstant { + + Constant(long address) { + super(address, gHotSpotVMIntConstantEntryNameOffset, gHotSpotVMIntConstantEntryValueOffset); + } + + @Override + public long getValue() { + return UNSAFE.getInt(address + valueOffset); + } + + @Override + public String toString() { + return String.format("IntConstant[name=%s, value=%d (0x%x)]", getName(), getValue(), getValue()); + } + } + } + + /** + * VMLongConstantEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 20) @Stable private long gHotSpotVMLongConstants; + @HotSpotVMData(index = 21) @Stable private long gHotSpotVMLongConstantEntryNameOffset; + @HotSpotVMData(index = 22) @Stable private long gHotSpotVMLongConstantEntryValueOffset; + @HotSpotVMData(index = 23) @Stable private long gHotSpotVMLongConstantEntryArrayStride; + + final class VMLongConstants implements Iterable { + + private final long address; + + public VMLongConstants(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Constant currentEntry() { + return new Constant(address + gHotSpotVMLongConstantEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Constant entry = currentEntry(); + return entry.getName() != null; + } + + public Constant next() { + Constant entry = currentEntry(); + index++; + return entry; + } + }; + } + + final class Constant extends AbstractConstant { + + Constant(long address) { + super(address, gHotSpotVMLongConstantEntryNameOffset, gHotSpotVMLongConstantEntryValueOffset); + } + + @Override + public long getValue() { + return UNSAFE.getLong(address + valueOffset); + } + + @Override + public String toString() { + return String.format("LongConstant[name=%s, value=%d (0x%x)]", getName(), getValue(), getValue()); + } + } + } + + /** + * VMAddressEntry (see vmStructs.hpp). + */ + @HotSpotVMData(index = 24) @Stable private long gHotSpotVMAddresses; + @HotSpotVMData(index = 25) @Stable private long gHotSpotVMAddressEntryNameOffset; + @HotSpotVMData(index = 26) @Stable private long gHotSpotVMAddressEntryValueOffset; + @HotSpotVMData(index = 27) @Stable private long gHotSpotVMAddressEntryArrayStride; + + final class VMAddresses implements Iterable { + + private final long address; + + public VMAddresses(long address) { + this.address = address; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Address currentEntry() { + return new Address(address + gHotSpotVMAddressEntryArrayStride * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Address entry = currentEntry(); + return entry.getName() != null; + } + + public Address next() { + Address entry = currentEntry(); + index++; + return entry; + } + }; + } + + final class Address extends AbstractConstant { + + Address(long address) { + super(address, gHotSpotVMAddressEntryNameOffset, gHotSpotVMAddressEntryValueOffset); + } + + @Override + public long getValue() { + return UNSAFE.getLong(address + valueOffset); + } + + @Override + public String toString() { + return String.format("Address[name=%s, value=%d (0x%x)]", getName(), getValue(), getValue()); + } + } + } + + final class Flags implements Iterable { + + private final long address; + private final long entrySize; + private final long typeOffset; + private final long nameOffset; + private final long addrOffset; + + public Flags(HashMap vmStructs, HashMap vmTypes) { + address = vmStructs.get("Flag::flags").getValue(); + entrySize = vmTypes.get("Flag").getSize(); + typeOffset = vmStructs.get("Flag::_type").getOffset(); + nameOffset = vmStructs.get("Flag::_name").getOffset(); + addrOffset = vmStructs.get("Flag::_addr").getOffset(); + + assert vmTypes.get("bool").getSize() == Byte.BYTES; + assert vmTypes.get("intx").getSize() == Long.BYTES; + assert vmTypes.get("uintx").getSize() == Long.BYTES; + } + + public Iterator iterator() { + return new Iterator() { + + private int index = 0; + + private Flag current() { + return new Flag(address + entrySize * index); + } + + /** + * The last entry is identified by a NULL name. + */ + public boolean hasNext() { + Flag entry = current(); + return entry.getName() != null; + } + + public Flag next() { + Flag entry = current(); + index++; + return entry; + } + }; + } + + final class Flag { + + private final long entryAddress; + + Flag(long address) { + this.entryAddress = address; + } + + public String getType() { + long typeAddress = UNSAFE.getAddress(entryAddress + typeOffset); + return readCString(UNSAFE, typeAddress); + } + + public String getName() { + long nameAddress = UNSAFE.getAddress(entryAddress + nameOffset); + return readCString(UNSAFE, nameAddress); + } + + public long getAddr() { + return UNSAFE.getAddress(entryAddress + addrOffset); + } + + public Object getValue() { + switch (getType()) { + case "bool": + return Boolean.valueOf(UNSAFE.getByte(getAddr()) != 0); + case "intx": + case "uintx": + case "uint64_t": + return Long.valueOf(UNSAFE.getLong(getAddr())); + case "double": + return Double.valueOf(UNSAFE.getDouble(getAddr())); + case "ccstr": + case "ccstrlist": + return readCString(UNSAFE, getAddr()); + default: + throw new JVMCIError(getType()); + } + } + + @Override + public String toString() { + return String.format("Flag[type=%s, name=%s, value=%s]", getType(), getName(), getValue()); + } + } + } + + @HotSpotVMConstant(name = "ASSERT") @Stable public boolean cAssertions; + public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); + + @HotSpotVMFlag(name = "CodeEntryAlignment") @Stable public int codeEntryAlignment; + @HotSpotVMFlag(name = "VerifyOops") @Stable public boolean verifyOops; + @HotSpotVMFlag(name = "CITime") @Stable public boolean ciTime; + @HotSpotVMFlag(name = "CITimeEach") @Stable public boolean ciTimeEach; + @HotSpotVMFlag(name = "CompileTheWorldStartAt", optional = true) @Stable public int compileTheWorldStartAt; + @HotSpotVMFlag(name = "CompileTheWorldStopAt", optional = true) @Stable public int compileTheWorldStopAt; + @HotSpotVMFlag(name = "DontCompileHugeMethods") @Stable public boolean dontCompileHugeMethods; + @HotSpotVMFlag(name = "HugeMethodLimit") @Stable public int hugeMethodLimit; + @HotSpotVMFlag(name = "PrintInlining") @Stable public boolean printInlining; + @HotSpotVMFlag(name = "JVMCIUseFastLocking") @Stable public boolean useFastLocking; + @HotSpotVMFlag(name = "ForceUnreachable") @Stable public boolean forceUnreachable; + @HotSpotVMFlag(name = "CodeCacheSegmentSize") @Stable public int codeSegmentSize; + + @HotSpotVMFlag(name = "UseTLAB") @Stable public boolean useTLAB; + @HotSpotVMFlag(name = "UseBiasedLocking") @Stable public boolean useBiasedLocking; + @HotSpotVMFlag(name = "UsePopCountInstruction") @Stable public boolean usePopCountInstruction; + @HotSpotVMFlag(name = "UseCountLeadingZerosInstruction", archs = {"amd64"}) @Stable public boolean useCountLeadingZerosInstruction; + @HotSpotVMFlag(name = "UseCountTrailingZerosInstruction", archs = {"amd64"}) @Stable public boolean useCountTrailingZerosInstruction; + @HotSpotVMFlag(name = "UseAESIntrinsics") @Stable public boolean useAESIntrinsics; + @HotSpotVMFlag(name = "UseCRC32Intrinsics") @Stable public boolean useCRC32Intrinsics; + @HotSpotVMFlag(name = "UseG1GC") @Stable public boolean useG1GC; + @HotSpotVMFlag(name = "UseConcMarkSweepGC") @Stable public boolean useCMSGC; + + @HotSpotVMFlag(name = "AllocatePrefetchStyle") @Stable public int allocatePrefetchStyle; + @HotSpotVMFlag(name = "AllocatePrefetchInstr") @Stable public int allocatePrefetchInstr; + @HotSpotVMFlag(name = "AllocatePrefetchLines") @Stable public int allocatePrefetchLines; + @HotSpotVMFlag(name = "AllocateInstancePrefetchLines") @Stable public int allocateInstancePrefetchLines; + @HotSpotVMFlag(name = "AllocatePrefetchStepSize") @Stable public int allocatePrefetchStepSize; + @HotSpotVMFlag(name = "AllocatePrefetchDistance") @Stable public int allocatePrefetchDistance; + + @HotSpotVMFlag(name = "FlightRecorder", optional = true) @Stable public boolean flightRecorder; + + @HotSpotVMField(name = "Universe::_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap; + @HotSpotVMField(name = "CollectedHeap::_total_collections", type = "unsigned int", get = HotSpotVMField.Type.OFFSET) @Stable private int collectedHeapTotalCollectionsOffset; + + public long gcTotalCollectionsAddress() { + return universeCollectedHeap + collectedHeapTotalCollectionsOffset; + } + + @HotSpotVMFlag(name = "ReduceInitialCardMarks") @Stable public boolean useDeferredInitBarriers; + + // Compressed Oops related values. + @HotSpotVMFlag(name = "UseCompressedOops") @Stable public boolean useCompressedOops; + @HotSpotVMFlag(name = "UseCompressedClassPointers") @Stable public boolean useCompressedClassPointers; + + @HotSpotVMField(name = "Universe::_narrow_oop._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowOopBase; + @HotSpotVMField(name = "Universe::_narrow_oop._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowOopShift; + @HotSpotVMFlag(name = "ObjectAlignmentInBytes") @Stable public int objectAlignment; + + public final int minObjAlignment() { + return objectAlignment / heapWordSize; + } + + public final int logMinObjAlignment() { + return (int) (Math.log(objectAlignment) / Math.log(2)); + } + + @HotSpotVMType(name = "narrowKlass", get = HotSpotVMType.Type.SIZE) @Stable public int narrowKlassSize; + @HotSpotVMField(name = "Universe::_narrow_klass._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowKlassBase; + @HotSpotVMField(name = "Universe::_narrow_klass._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowKlassShift; + @HotSpotVMConstant(name = "LogKlassAlignmentInBytes") @Stable public int logKlassAlignment; + + // CPU capabilities + @HotSpotVMFlag(name = "UseSSE") @Stable public int useSSE; + @HotSpotVMFlag(name = "UseAVX", archs = {"amd64"}) @Stable public int useAVX; + + @HotSpotVMField(name = "Abstract_VM_Version::_reserve_for_allocation_prefetch", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int abstractVmVersionReserveForAllocationPrefetch; + + // X86 specific values + @HotSpotVMField(name = "VM_Version::_cpuFeatures", type = "uint64_t", get = HotSpotVMField.Type.VALUE, archs = {"amd64"}) @Stable public long x86CPUFeatures; + @HotSpotVMConstant(name = "VM_Version::CPU_CX8", archs = {"amd64"}) @Stable public long cpuCX8; + @HotSpotVMConstant(name = "VM_Version::CPU_CMOV", archs = {"amd64"}) @Stable public long cpuCMOV; + @HotSpotVMConstant(name = "VM_Version::CPU_FXSR", archs = {"amd64"}) @Stable public long cpuFXSR; + @HotSpotVMConstant(name = "VM_Version::CPU_HT", archs = {"amd64"}) @Stable public long cpuHT; + @HotSpotVMConstant(name = "VM_Version::CPU_MMX", archs = {"amd64"}) @Stable public long cpuMMX; + @HotSpotVMConstant(name = "VM_Version::CPU_3DNOW_PREFETCH", archs = {"amd64"}) @Stable public long cpu3DNOWPREFETCH; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE", archs = {"amd64"}) @Stable public long cpuSSE; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE2", archs = {"amd64"}) @Stable public long cpuSSE2; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE3", archs = {"amd64"}) @Stable public long cpuSSE3; + @HotSpotVMConstant(name = "VM_Version::CPU_SSSE3", archs = {"amd64"}) @Stable public long cpuSSSE3; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4A", archs = {"amd64"}) @Stable public long cpuSSE4A; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_1", archs = {"amd64"}) @Stable public long cpuSSE41; + @HotSpotVMConstant(name = "VM_Version::CPU_SSE4_2", archs = {"amd64"}) @Stable public long cpuSSE42; + @HotSpotVMConstant(name = "VM_Version::CPU_POPCNT", archs = {"amd64"}) @Stable public long cpuPOPCNT; + @HotSpotVMConstant(name = "VM_Version::CPU_LZCNT", archs = {"amd64"}) @Stable public long cpuLZCNT; + @HotSpotVMConstant(name = "VM_Version::CPU_TSC", archs = {"amd64"}) @Stable public long cpuTSC; + @HotSpotVMConstant(name = "VM_Version::CPU_TSCINV", archs = {"amd64"}) @Stable public long cpuTSCINV; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX", archs = {"amd64"}) @Stable public long cpuAVX; + @HotSpotVMConstant(name = "VM_Version::CPU_AVX2", archs = {"amd64"}) @Stable public long cpuAVX2; + @HotSpotVMConstant(name = "VM_Version::CPU_AES", archs = {"amd64"}) @Stable public long cpuAES; + @HotSpotVMConstant(name = "VM_Version::CPU_ERMS", archs = {"amd64"}) @Stable public long cpuERMS; + @HotSpotVMConstant(name = "VM_Version::CPU_CLMUL", archs = {"amd64"}) @Stable public long cpuCLMUL; + @HotSpotVMConstant(name = "VM_Version::CPU_BMI1", archs = {"amd64"}) @Stable public long cpuBMI1; + + // SPARC specific values + @HotSpotVMField(name = "VM_Version::_features", type = "int", get = HotSpotVMField.Type.VALUE, archs = {"sparc"}) @Stable public int sparcFeatures; + @HotSpotVMConstant(name = "VM_Version::vis3_instructions_m", archs = {"sparc"}) @Stable public int vis3Instructions; + @HotSpotVMConstant(name = "VM_Version::vis2_instructions_m", archs = {"sparc"}) @Stable public int vis2Instructions; + @HotSpotVMConstant(name = "VM_Version::vis1_instructions_m", archs = {"sparc"}) @Stable public int vis1Instructions; + @HotSpotVMConstant(name = "VM_Version::cbcond_instructions_m", archs = {"sparc"}) @Stable public int cbcondInstructions; + @HotSpotVMFlag(name = "UseBlockZeroing", archs = {"sparc"}) @Stable public boolean useBlockZeroing; + @HotSpotVMFlag(name = "BlockZeroingLowLimit", archs = {"sparc"}) @Stable public int blockZeroingLowLimit; + + // offsets, ... + @HotSpotVMFlag(name = "StackShadowPages") @Stable public int stackShadowPages; + @HotSpotVMFlag(name = "UseStackBanging") @Stable public boolean useStackBanging; + @HotSpotVMConstant(name = "STACK_BIAS") @Stable public int stackBias; + + @HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset; + @HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset; + + @HotSpotVMField(name = "Klass::_prototype_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int prototypeMarkWordOffset; + @HotSpotVMField(name = "Klass::_subklass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int subklassOffset; + @HotSpotVMField(name = "Klass::_next_sibling", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int nextSiblingOffset; + @HotSpotVMField(name = "Klass::_super_check_offset", type = "juint", get = HotSpotVMField.Type.OFFSET) @Stable public int superCheckOffsetOffset; + @HotSpotVMField(name = "Klass::_secondary_super_cache", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int secondarySuperCacheOffset; + @HotSpotVMField(name = "Klass::_secondary_supers", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int secondarySupersOffset; + + /** + * The offset of the _java_mirror field (of type {@link Class}) in a Klass. + */ + @HotSpotVMField(name = "Klass::_java_mirror", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int classMirrorOffset; + + @HotSpotVMField(name = "Klass::_super", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int klassSuperKlassOffset; + @HotSpotVMField(name = "Klass::_modifier_flags", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassModifierFlagsOffset; + @HotSpotVMField(name = "Klass::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int klassAccessFlagsOffset; + @HotSpotVMField(name = "Klass::_layout_helper", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int klassLayoutHelperOffset; + + @HotSpotVMConstant(name = "Klass::_lh_neutral_value") @Stable public int klassLayoutHelperNeutralValue; + @HotSpotVMConstant(name = "Klass::_lh_instance_slow_path_bit") @Stable public int klassLayoutHelperInstanceSlowPathBit; + @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_shift") @Stable public int layoutHelperLog2ElementSizeShift; + @HotSpotVMConstant(name = "Klass::_lh_log2_element_size_mask") @Stable public int layoutHelperLog2ElementSizeMask; + @HotSpotVMConstant(name = "Klass::_lh_element_type_shift") @Stable public int layoutHelperElementTypeShift; + @HotSpotVMConstant(name = "Klass::_lh_element_type_mask") @Stable public int layoutHelperElementTypeMask; + @HotSpotVMConstant(name = "Klass::_lh_header_size_shift") @Stable public int layoutHelperHeaderSizeShift; + @HotSpotVMConstant(name = "Klass::_lh_header_size_mask") @Stable public int layoutHelperHeaderSizeMask; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_shift") @Stable public int layoutHelperArrayTagShift; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_type_value") @Stable public int layoutHelperArrayTagTypeValue; + @HotSpotVMConstant(name = "Klass::_lh_array_tag_obj_value") @Stable public int layoutHelperArrayTagObjectValue; + + /** + * This filters out the bit that differentiates a type array from an object array. + */ + public int layoutHelperElementTypePrimitiveInPlace() { + return (layoutHelperArrayTagTypeValue & ~layoutHelperArrayTagObjectValue) << layoutHelperArrayTagShift; + } + + /** + * Bit pattern in the klass layout helper that can be used to identify arrays. + */ + public final int arrayKlassLayoutHelperIdentifier = 0x80000000; + + @HotSpotVMType(name = "vtableEntry", get = HotSpotVMType.Type.SIZE) @Stable public int vtableEntrySize; + @HotSpotVMField(name = "vtableEntry::_method", type = "Method*", get = HotSpotVMField.Type.OFFSET) @Stable public int vtableEntryMethodOffset; + + @HotSpotVMType(name = "InstanceKlass", get = HotSpotVMType.Type.SIZE) @Stable public int instanceKlassSize; + @HotSpotVMField(name = "InstanceKlass::_source_file_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassSourceFileNameIndexOffset; + @HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassInitStateOffset; + @HotSpotVMField(name = "InstanceKlass::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassConstantsOffset; + @HotSpotVMField(name = "InstanceKlass::_fields", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassFieldsOffset; + @HotSpotVMField(name = "InstanceKlass::_vtable_len", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassVtableLengthOffset; + + @HotSpotVMConstant(name = "InstanceKlass::linked") @Stable public int instanceKlassStateLinked; + @HotSpotVMConstant(name = "InstanceKlass::fully_initialized") @Stable public int instanceKlassStateFullyInitialized; + + /** + * See {@code InstanceKlass::vtable_start_offset()}. + */ + public final int instanceKlassVtableStartOffset() { + return roundUp(instanceKlassSize, heapWordSize); + } + + // TODO use CodeUtil method once it's moved from NumUtil + private static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } + + @HotSpotVMType(name = "arrayOopDesc", get = HotSpotVMType.Type.SIZE) @Stable public int arrayOopDescSize; + + /** + * The offset of the array length word in an array object's header. + * + * See {@code arrayOopDesc::length_offset_in_bytes()}. + */ + public final int arrayOopDescLengthOffset() { + return useCompressedClassPointers ? hubOffset + narrowKlassSize : arrayOopDescSize; + } + + @HotSpotVMField(name = "Array::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1LengthOffset; + @HotSpotVMField(name = "Array::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU1DataOffset; + @HotSpotVMField(name = "Array::_data", type = "", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayU2DataOffset; + @HotSpotVMField(name = "Array::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayLengthOffset; + @HotSpotVMField(name = "Array::_data[0]", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayBaseOffset; + + @HotSpotVMField(name = "ObjArrayKlass::_element_klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int arrayClassElementOffset; + + @HotSpotVMConstant(name = "FieldInfo::access_flags_offset") @Stable public int fieldInfoAccessFlagsOffset; + @HotSpotVMConstant(name = "FieldInfo::name_index_offset") @Stable public int fieldInfoNameIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::signature_index_offset") @Stable public int fieldInfoSignatureIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::initval_index_offset") @Stable public int fieldInfoInitvalIndexOffset; + @HotSpotVMConstant(name = "FieldInfo::low_packed_offset") @Stable public int fieldInfoLowPackedOffset; + @HotSpotVMConstant(name = "FieldInfo::high_packed_offset") @Stable public int fieldInfoHighPackedOffset; + @HotSpotVMConstant(name = "FieldInfo::field_slots") @Stable public int fieldInfoFieldSlots; + + @HotSpotVMConstant(name = "FIELDINFO_TAG_SIZE") @Stable public int fieldInfoTagSize; + + @HotSpotVMConstant(name = "JVM_ACC_FIELD_INTERNAL") @Stable public int jvmAccFieldInternal; + @HotSpotVMConstant(name = "JVM_ACC_FIELD_STABLE") @Stable public int jvmAccFieldStable; + @HotSpotVMConstant(name = "JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE") @Stable public int jvmAccFieldHasGenericSignature; + @HotSpotVMConstant(name = "JVM_ACC_WRITTEN_FLAGS") @Stable public int jvmAccWrittenFlags; + + @HotSpotVMField(name = "Thread::_tlab", type = "ThreadLocalAllocBuffer", get = HotSpotVMField.Type.OFFSET) @Stable public int threadTlabOffset; + + @HotSpotVMField(name = "JavaThread::_anchor", type = "JavaFrameAnchor", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadAnchorOffset; + @HotSpotVMField(name = "JavaThread::_threadObj", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectOffset; + @HotSpotVMField(name = "JavaThread::_osthread", type = "OSThread*", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadOffset; + @HotSpotVMField(name = "JavaThread::_dirty_card_queue", type = "DirtyCardQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadDirtyCardQueueOffset; + @HotSpotVMField(name = "JavaThread::_is_method_handle_return", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int threadIsMethodHandleReturnOffset; + @HotSpotVMField(name = "JavaThread::_satb_mark_queue", type = "ObjPtrQueue", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadSatbMarkQueueOffset; + @HotSpotVMField(name = "JavaThread::_vm_result", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadObjectResultOffset; + @HotSpotVMField(name = "JavaThread::_jvmci_counters", type = "jlong*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciCountersThreadOffset; + + /** + * An invalid value for {@link #rtldDefault}. + */ + public static final long INVALID_RTLD_DEFAULT_HANDLE = 0xDEADFACE; + + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *
+     *     void* (const char *filename, char *ebuf, int ebuflen)
+     * 
+ */ + @HotSpotVMAddress(name = "os::dll_load") @Stable public long dllLoad; + + /** + * Address of the library lookup routine. The C signature of this routine is: + * + *
+     *     void* (void* handle, const char* name)
+     * 
+ */ + @HotSpotVMAddress(name = "os::dll_lookup") @Stable public long dllLookup; + + /** + * A pseudo-handle which when used as the first argument to {@link #dllLookup} means lookup will + * return the first occurrence of the desired symbol using the default library search order. If + * this field is {@value #INVALID_RTLD_DEFAULT_HANDLE}, then this capability is not supported on + * the current platform. + */ + @HotSpotVMAddress(name = "RTLD_DEFAULT", os = {"bsd", "linux"}) @Stable public long rtldDefault = INVALID_RTLD_DEFAULT_HANDLE; + + /** + * This field is used to pass exception objects into and out of the runtime system during + * exception handling for compiled code. + */ + @HotSpotVMField(name = "JavaThread::_exception_oop", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int threadExceptionOopOffset; + @HotSpotVMField(name = "JavaThread::_exception_pc", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int threadExceptionPcOffset; + @HotSpotVMField(name = "ThreadShadow::_pending_exception", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingExceptionOffset; + + @HotSpotVMField(name = "JavaThread::_pending_deoptimization", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingDeoptimizationOffset; + @HotSpotVMField(name = "JavaThread::_pending_failed_speculation", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingFailedSpeculationOffset; + @HotSpotVMField(name = "JavaThread::_pending_transfer_to_interpreter", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int pendingTransferToInterpreterOffset; + + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_sp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaSpOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_pc", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaPcOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_fp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET, archs = {"amd64"}) @Stable private int javaFrameAnchorLastJavaFpOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_flags", type = "int", get = HotSpotVMField.Type.OFFSET, archs = {"sparc"}) @Stable private int javaFrameAnchorFlagsOffset; + + public int threadLastJavaSpOffset() { + return javaThreadAnchorOffset + javaFrameAnchorLastJavaSpOffset; + } + + public int threadLastJavaPcOffset() { + return javaThreadAnchorOffset + javaFrameAnchorLastJavaPcOffset; + } + + /** + * This value is only valid on AMD64. + */ + public int threadLastJavaFpOffset() { + // TODO add an assert for AMD64 + return javaThreadAnchorOffset + javaFrameAnchorLastJavaFpOffset; + } + + /** + * This value is only valid on SPARC. + */ + public int threadJavaFrameAnchorFlagsOffset() { + // TODO add an assert for SPARC + return javaThreadAnchorOffset + javaFrameAnchorFlagsOffset; + } + + // These are only valid on AMD64. + @HotSpotVMConstant(name = "frame::arg_reg_save_area_bytes", archs = {"amd64"}) @Stable public int runtimeCallStackSize; + @HotSpotVMConstant(name = "frame::interpreter_frame_sender_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameSenderSpOffset; + @HotSpotVMConstant(name = "frame::interpreter_frame_last_sp_offset", archs = {"amd64"}) @Stable public int frameInterpreterFrameLastSpOffset; + + @HotSpotVMField(name = "PtrQueue::_active", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueActiveOffset; + @HotSpotVMField(name = "PtrQueue::_buf", type = "void**", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueBufferOffset; + @HotSpotVMField(name = "PtrQueue::_index", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable public int ptrQueueIndexOffset; + + @HotSpotVMField(name = "OSThread::_interrupted", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadInterruptedOffset; + + @HotSpotVMConstant(name = "markOopDesc::unlocked_value") @Stable public int unlockedMask; + @HotSpotVMConstant(name = "markOopDesc::biased_lock_mask_in_place") @Stable public int biasedLockMaskInPlace; + @HotSpotVMConstant(name = "markOopDesc::age_mask_in_place") @Stable public int ageMaskInPlace; + @HotSpotVMConstant(name = "markOopDesc::epoch_mask_in_place") @Stable public int epochMaskInPlace; + + @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public long markOopDescHashShift; + @HotSpotVMConstant(name = "markOopDesc::hash_mask") @Stable public long markOopDescHashMask; + @HotSpotVMConstant(name = "markOopDesc::hash_mask_in_place") @Stable public long markOopDescHashMaskInPlace; + + @HotSpotVMConstant(name = "markOopDesc::biased_lock_pattern") @Stable public int biasedLockPattern; + @HotSpotVMConstant(name = "markOopDesc::no_hash_in_place") @Stable public int markWordNoHashInPlace; + @HotSpotVMConstant(name = "markOopDesc::no_lock_in_place") @Stable public int markWordNoLockInPlace; + + /** + * See {@code markOopDesc::prototype()}. + */ + public long arrayPrototypeMarkWord() { + return markWordNoHashInPlace | markWordNoLockInPlace; + } + + /** + * See {@code markOopDesc::copy_set_hash()}. + */ + public long tlabIntArrayMarkWord() { + long tmp = arrayPrototypeMarkWord() & (~markOopDescHashMaskInPlace); + tmp |= ((0x2 & markOopDescHashMask) << markOopDescHashShift); + return tmp; + } + + /** + * Mark word right shift to get identity hash code. + */ + @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public int identityHashCodeShift; + + /** + * Identity hash code value when uninitialized. + */ + @HotSpotVMConstant(name = "markOopDesc::no_hash") @Stable public int uninitializedIdentityHashCodeValue; + + @HotSpotVMField(name = "Method::_access_flags", type = "AccessFlags", get = HotSpotVMField.Type.OFFSET) @Stable public int methodAccessFlagsOffset; + @HotSpotVMField(name = "Method::_constMethod", type = "ConstMethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodConstMethodOffset; + @HotSpotVMField(name = "Method::_intrinsic_id", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int methodIntrinsicIdOffset; + @HotSpotVMField(name = "Method::_flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset; + @HotSpotVMField(name = "Method::_vtable_index", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodVtableIndexOffset; + + @HotSpotVMConstant(name = "Method::_jfr_towrite") @Stable public int methodFlagsJfrTowrite; + @HotSpotVMConstant(name = "Method::_caller_sensitive") @Stable public int methodFlagsCallerSensitive; + @HotSpotVMConstant(name = "Method::_force_inline") @Stable public int methodFlagsForceInline; + @HotSpotVMConstant(name = "Method::_dont_inline") @Stable public int methodFlagsDontInline; + @HotSpotVMConstant(name = "Method::_hidden") @Stable public int methodFlagsHidden; + @HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex; + @HotSpotVMConstant(name = "Method::invalid_vtable_index") @Stable public int invalidVtableIndex; + + @HotSpotVMConstant(name = "InvocationEntryBci") @Stable public int invocationEntryBci; + + @HotSpotVMField(name = "JVMCIEnv::_task", type = "CompileTask*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvTaskOffset; + @HotSpotVMField(name = "JVMCIEnv::_jvmti_can_hotswap_or_post_breakpoint", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvJvmtiCanHotswapOrPostBreakpointOffset; + @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset; + + /** + * See {@code Method::extra_stack_entries()}. + */ + @HotSpotVMConstant(name = "Method::extra_stack_entries_for_jsr292") @Stable public int extraStackEntries; + + @HotSpotVMField(name = "ConstMethod::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodConstantsOffset; + @HotSpotVMField(name = "ConstMethod::_flags", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodFlagsOffset; + @HotSpotVMField(name = "ConstMethod::_code_size", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodCodeSizeOffset; + @HotSpotVMField(name = "ConstMethod::_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodNameIndexOffset; + @HotSpotVMField(name = "ConstMethod::_signature_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodSignatureIndexOffset; + @HotSpotVMField(name = "ConstMethod::_max_stack", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodMaxStackOffset; + @HotSpotVMField(name = "ConstMethod::_max_locals", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int methodMaxLocalsOffset; + + @HotSpotVMConstant(name = "ConstMethod::_has_linenumber_table") @Stable public int constMethodHasLineNumberTable; + @HotSpotVMConstant(name = "ConstMethod::_has_localvariable_table") @Stable public int constMethodHasLocalVariableTable; + @HotSpotVMConstant(name = "ConstMethod::_has_exception_table") @Stable public int constMethodHasExceptionTable; + + @HotSpotVMType(name = "ExceptionTableElement", get = HotSpotVMType.Type.SIZE) @Stable public int exceptionTableElementSize; + @HotSpotVMField(name = "ExceptionTableElement::start_pc", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementStartPcOffset; + @HotSpotVMField(name = "ExceptionTableElement::end_pc", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementEndPcOffset; + @HotSpotVMField(name = "ExceptionTableElement::handler_pc", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementHandlerPcOffset; + @HotSpotVMField(name = "ExceptionTableElement::catch_type_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int exceptionTableElementCatchTypeIndexOffset; + + @HotSpotVMType(name = "LocalVariableTableElement", get = HotSpotVMType.Type.SIZE) @Stable public int localVariableTableElementSize; + @HotSpotVMField(name = "LocalVariableTableElement::start_bci", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementStartBciOffset; + @HotSpotVMField(name = "LocalVariableTableElement::length", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementLengthOffset; + @HotSpotVMField(name = "LocalVariableTableElement::name_cp_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementNameCpIndexOffset; + @HotSpotVMField(name = "LocalVariableTableElement::descriptor_cp_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementDescriptorCpIndexOffset; + @HotSpotVMField(name = "LocalVariableTableElement::signature_cp_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementSignatureCpIndexOffset; + @HotSpotVMField(name = "LocalVariableTableElement::slot", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int localVariableTableElementSlotOffset; + + @HotSpotVMType(name = "ConstantPool", get = HotSpotVMType.Type.SIZE) @Stable public int constantPoolSize; + @HotSpotVMField(name = "ConstantPool::_tags", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolTagsOffset; + @HotSpotVMField(name = "ConstantPool::_pool_holder", type = "InstanceKlass*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolHolderOffset; + @HotSpotVMField(name = "ConstantPool::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolLengthOffset; + + @HotSpotVMConstant(name = "ConstantPool::CPCACHE_INDEX_TAG") @Stable public int constantPoolCpCacheIndexTag; + + @HotSpotVMConstant(name = "JVM_CONSTANT_Utf8") @Stable public int jvmConstantUtf8; + @HotSpotVMConstant(name = "JVM_CONSTANT_Integer") @Stable public int jvmConstantInteger; + @HotSpotVMConstant(name = "JVM_CONSTANT_Long") @Stable public int jvmConstantLong; + @HotSpotVMConstant(name = "JVM_CONSTANT_Float") @Stable public int jvmConstantFloat; + @HotSpotVMConstant(name = "JVM_CONSTANT_Double") @Stable public int jvmConstantDouble; + @HotSpotVMConstant(name = "JVM_CONSTANT_Class") @Stable public int jvmConstantClass; + @HotSpotVMConstant(name = "JVM_CONSTANT_UnresolvedClass") @Stable public int jvmConstantUnresolvedClass; + @HotSpotVMConstant(name = "JVM_CONSTANT_UnresolvedClassInError") @Stable public int jvmConstantUnresolvedClassInError; + @HotSpotVMConstant(name = "JVM_CONSTANT_String") @Stable public int jvmConstantString; + @HotSpotVMConstant(name = "JVM_CONSTANT_Fieldref") @Stable public int jvmConstantFieldref; + @HotSpotVMConstant(name = "JVM_CONSTANT_Methodref") @Stable public int jvmConstantMethodref; + @HotSpotVMConstant(name = "JVM_CONSTANT_InterfaceMethodref") @Stable public int jvmConstantInterfaceMethodref; + @HotSpotVMConstant(name = "JVM_CONSTANT_NameAndType") @Stable public int jvmConstantNameAndType; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodHandle") @Stable public int jvmConstantMethodHandle; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodHandleInError") @Stable public int jvmConstantMethodHandleInError; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodType") @Stable public int jvmConstantMethodType; + @HotSpotVMConstant(name = "JVM_CONSTANT_MethodTypeInError") @Stable public int jvmConstantMethodTypeInError; + @HotSpotVMConstant(name = "JVM_CONSTANT_InvokeDynamic") @Stable public int jvmConstantInvokeDynamic; + + @HotSpotVMConstant(name = "JVM_CONSTANT_ExternalMax") @Stable public int jvmConstantExternalMax; + @HotSpotVMConstant(name = "JVM_CONSTANT_InternalMin") @Stable public int jvmConstantInternalMin; + @HotSpotVMConstant(name = "JVM_CONSTANT_InternalMax") @Stable public int jvmConstantInternalMax; + + @HotSpotVMConstant(name = "HeapWordSize") @Stable public int heapWordSize; + + @HotSpotVMType(name = "Symbol*", get = HotSpotVMType.Type.SIZE) @Stable public int symbolPointerSize; + @HotSpotVMField(name = "Symbol::_length", type = "unsigned short", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolLengthOffset; + @HotSpotVMField(name = "Symbol::_body[0]", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolBodyOffset; + + @HotSpotVMField(name = "vmSymbols::_symbols[0]", type = "Symbol*", get = HotSpotVMField.Type.ADDRESS) @Stable public long vmSymbolsSymbols; + @HotSpotVMConstant(name = "vmSymbols::FIRST_SID") @Stable public int vmSymbolsFirstSID; + @HotSpotVMConstant(name = "vmSymbols::SID_LIMIT") @Stable public int vmSymbolsSIDLimit; + + @HotSpotVMConstant(name = "JVM_ACC_HAS_FINALIZER") @Stable public int klassHasFinalizerFlag; + + // Modifier.SYNTHETIC is not public so we get it via vmStructs. + @HotSpotVMConstant(name = "JVM_ACC_SYNTHETIC") @Stable public int syntheticFlag; + + /** + * @see HotSpotResolvedObjectTypeImpl#createField + */ + @HotSpotVMConstant(name = "JVM_RECOGNIZED_FIELD_MODIFIERS") @Stable public int recognizedFieldModifiers; + + /** + * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value + * are allowed to look like (respectively) the high or low bits of a real oop. + */ + @HotSpotVMField(name = "Universe::_non_oop_bits", type = "intptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long nonOopBits; + + @HotSpotVMField(name = "StubRoutines::_verify_oop_count", type = "jint", get = HotSpotVMField.Type.ADDRESS) @Stable public long verifyOopCounterAddress; + @HotSpotVMField(name = "Universe::_verify_oop_mask", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopMask; + @HotSpotVMField(name = "Universe::_verify_oop_bits", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopBits; + @HotSpotVMField(name = "Universe::_base_vtable_size", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int universeBaseVtableSize; + + public final int baseVtableLength() { + return universeBaseVtableSize / vtableEntrySize; + } + + @HotSpotVMField(name = "CollectedHeap::_barrier_set", type = "BarrierSet*", get = HotSpotVMField.Type.OFFSET) @Stable public int collectedHeapBarrierSetOffset; + + @HotSpotVMField(name = "HeapRegion::LogOfHRGrainBytes", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int logOfHRGrainBytes; + + @HotSpotVMField(name = "BarrierSet::_fake_rtti", type = "BarrierSet::FakeRtti", get = HotSpotVMField.Type.OFFSET) @Stable private int barrierSetFakeRttiOffset; + @HotSpotVMConstant(name = "BarrierSet::CardTableModRef") @Stable public int barrierSetCardTableModRef; + @HotSpotVMConstant(name = "BarrierSet::CardTableForRS") @Stable public int barrierSetCardTableForRS; + @HotSpotVMConstant(name = "BarrierSet::CardTableExtension") @Stable public int barrierSetCardTableExtension; + @HotSpotVMConstant(name = "BarrierSet::G1SATBCT") @Stable public int barrierSetG1SATBCT; + @HotSpotVMConstant(name = "BarrierSet::G1SATBCTLogging") @Stable public int barrierSetG1SATBCTLogging; + @HotSpotVMConstant(name = "BarrierSet::ModRef") @Stable public int barrierSetModRef; + + @HotSpotVMField(name = "BarrierSet::FakeRtti::_concrete_tag", type = "BarrierSet::Name", get = HotSpotVMField.Type.OFFSET) @Stable private int fakeRttiConcreteTagOffset; + + @HotSpotVMField(name = "CardTableModRefBS::byte_map_base", type = "jbyte*", get = HotSpotVMField.Type.OFFSET) @Stable private int cardTableModRefBSByteMapBaseOffset; + @HotSpotVMConstant(name = "CardTableModRefBS::card_shift") @Stable public int cardTableModRefBSCardShift; + + @HotSpotVMConstant(name = "CardTableModRefBS::dirty_card") @Stable public byte dirtyCardValue; + @HotSpotVMConstant(name = "G1SATBCardTableModRefBS::g1_young_gen") @Stable public byte g1YoungCardValue; + + private final long cardtableStartAddress; + private final int cardtableShift; + + public long cardtableStartAddress() { + if (cardtableStartAddress == -1) { + throw JVMCIError.shouldNotReachHere(); + } + return cardtableStartAddress; + } + + public int cardtableShift() { + if (cardtableShift == -1) { + throw JVMCIError.shouldNotReachHere(); + } + return cardtableShift; + } + + @HotSpotVMField(name = "os::_polling_page", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long safepointPollingAddress; + + // G1 Collector Related Values. + + public int g1CardQueueIndexOffset() { + return javaThreadDirtyCardQueueOffset + ptrQueueIndexOffset; + } + + public int g1CardQueueBufferOffset() { + return javaThreadDirtyCardQueueOffset + ptrQueueBufferOffset; + } + + public int g1SATBQueueMarkingOffset() { + return javaThreadSatbMarkQueueOffset + ptrQueueActiveOffset; + } + + public int g1SATBQueueIndexOffset() { + return javaThreadSatbMarkQueueOffset + ptrQueueIndexOffset; + } + + public int g1SATBQueueBufferOffset() { + return javaThreadSatbMarkQueueOffset + ptrQueueBufferOffset; + } + + @HotSpotVMField(name = "java_lang_Class::_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassOffset; + @HotSpotVMField(name = "java_lang_Class::_array_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int arrayKlassOffset; + + @HotSpotVMField(name = "Method::_method_counters", type = "MethodCounters*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCountersOffset; + @HotSpotVMField(name = "Method::_method_data", type = "MethodData*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOffset; + @HotSpotVMField(name = "Method::_from_compiled_entry", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCompiledEntryOffset; + @HotSpotVMField(name = "Method::_code", type = "nmethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCodeOffset; + + @HotSpotVMField(name = "MethodCounters::_invocation_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int invocationCounterOffset; + @HotSpotVMField(name = "MethodCounters::_backedge_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int backedgeCounterOffset; + @HotSpotVMConstant(name = "InvocationCounter::count_increment") @Stable public int invocationCounterIncrement; + @HotSpotVMConstant(name = "InvocationCounter::count_shift") @Stable public int invocationCounterShift; + + @HotSpotVMField(name = "MethodData::_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataSize; + @HotSpotVMField(name = "MethodData::_data_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataDataSize; + @HotSpotVMField(name = "MethodData::_data[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopDataOffset; + @HotSpotVMField(name = "MethodData::_trap_hist._array[0]", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopTrapHistoryOffset; + @HotSpotVMField(name = "MethodData::_jvmci_ir_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataIRSizeOffset; + + @HotSpotVMField(name = "nmethod::_verified_entry_point", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodEntryOffset; + @HotSpotVMField(name = "nmethod::_comp_level", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodCompLevelOffset; + + @HotSpotVMConstant(name = "CompLevel_full_optimization") @Stable public int compilationLevelFullOptimization; + + @HotSpotVMType(name = "BasicLock", get = HotSpotVMType.Type.SIZE) @Stable public int basicLockSize; + @HotSpotVMField(name = "BasicLock::_displaced_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int basicLockDisplacedHeaderOffset; + + @HotSpotVMField(name = "Thread::_allocated_bytes", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int threadAllocatedBytesOffset; + + @HotSpotVMFlag(name = "TLABWasteIncrement") @Stable public int tlabRefillWasteIncrement; + + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_start", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferStartOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_end", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferEndOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_top", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferTopOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_pf_top", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferPfTopOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_slow_allocations", type = "unsigned", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferSlowAllocationsOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_fast_refill_waste", type = "unsigned", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferFastRefillWasteOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_number_of_refills", type = "unsigned", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferNumberOfRefillsOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_refill_waste_limit", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferRefillWasteLimitOffset; + @HotSpotVMField(name = "ThreadLocalAllocBuffer::_desired_size", type = "size_t", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferDesiredSizeOffset; + + public int tlabSlowAllocationsOffset() { + return threadTlabOffset + threadLocalAllocBufferSlowAllocationsOffset; + } + + public int tlabFastRefillWasteOffset() { + return threadTlabOffset + threadLocalAllocBufferFastRefillWasteOffset; + } + + public int tlabNumberOfRefillsOffset() { + return threadTlabOffset + threadLocalAllocBufferNumberOfRefillsOffset; + } + + public int tlabRefillWasteLimitOffset() { + return threadTlabOffset + threadLocalAllocBufferRefillWasteLimitOffset; + } + + public int threadTlabSizeOffset() { + return threadTlabOffset + threadLocalAllocBufferDesiredSizeOffset; + } + + public int threadTlabStartOffset() { + return threadTlabOffset + threadLocalAllocBufferStartOffset; + } + + public int threadTlabEndOffset() { + return threadTlabOffset + threadLocalAllocBufferEndOffset; + } + + public int threadTlabTopOffset() { + return threadTlabOffset + threadLocalAllocBufferTopOffset; + } + + public int threadTlabPfTopOffset() { + return threadTlabOffset + threadLocalAllocBufferPfTopOffset; + } + + /** + * See: {@code ThreadLocalAllocBuffer::end_reserve()}. + */ + public final int threadLocalAllocBufferEndReserve() { + final int typeSizeInBytes = roundUp(arrayOopDescLengthOffset() + Integer.BYTES, heapWordSize); + // T_INT arrays need not be 8 byte aligned. + final int reserveSize = typeSizeInBytes / heapWordSize; + return Integer.max(reserveSize, abstractVmVersionReserveForAllocationPrefetch); + } + + /** + * See: {@code ThreadLocalAllocBuffer::alignment_reserve()}. + */ + public final int tlabAlignmentReserve() { + return roundUp(threadLocalAllocBufferEndReserve(), minObjAlignment()); + } + + @HotSpotVMFlag(name = "TLABStats") @Stable public boolean tlabStats; + + // FIXME This is only temporary until the GC code is changed. + @HotSpotVMField(name = "CompilerToVM::_supports_inline_contig_alloc", type = "bool", get = HotSpotVMField.Type.VALUE) @Stable public boolean inlineContiguousAllocationSupported; + @HotSpotVMField(name = "CompilerToVM::_heap_end_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapEndAddress; + @HotSpotVMField(name = "CompilerToVM::_heap_top_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapTopAddress; + + /** + * The DataLayout header size is the same as the cell size. + */ + @HotSpotVMConstant(name = "DataLayout::cell_size") @Stable public int dataLayoutHeaderSize; + @HotSpotVMField(name = "DataLayout::_header._struct._tag", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutTagOffset; + @HotSpotVMField(name = "DataLayout::_header._struct._flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutFlagsOffset; + @HotSpotVMField(name = "DataLayout::_header._struct._bci", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutBCIOffset; + @HotSpotVMField(name = "DataLayout::_cells[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int dataLayoutCellsOffset; + @HotSpotVMConstant(name = "DataLayout::cell_size") @Stable public int dataLayoutCellSize; + + @HotSpotVMConstant(name = "DataLayout::no_tag") @Stable public int dataLayoutNoTag; + @HotSpotVMConstant(name = "DataLayout::bit_data_tag") @Stable public int dataLayoutBitDataTag; + @HotSpotVMConstant(name = "DataLayout::counter_data_tag") @Stable public int dataLayoutCounterDataTag; + @HotSpotVMConstant(name = "DataLayout::jump_data_tag") @Stable public int dataLayoutJumpDataTag; + @HotSpotVMConstant(name = "DataLayout::receiver_type_data_tag") @Stable public int dataLayoutReceiverTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::virtual_call_data_tag") @Stable public int dataLayoutVirtualCallDataTag; + @HotSpotVMConstant(name = "DataLayout::ret_data_tag") @Stable public int dataLayoutRetDataTag; + @HotSpotVMConstant(name = "DataLayout::branch_data_tag") @Stable public int dataLayoutBranchDataTag; + @HotSpotVMConstant(name = "DataLayout::multi_branch_data_tag") @Stable public int dataLayoutMultiBranchDataTag; + @HotSpotVMConstant(name = "DataLayout::arg_info_data_tag") @Stable public int dataLayoutArgInfoDataTag; + @HotSpotVMConstant(name = "DataLayout::call_type_data_tag") @Stable public int dataLayoutCallTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::virtual_call_type_data_tag") @Stable public int dataLayoutVirtualCallTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::parameters_type_data_tag") @Stable public int dataLayoutParametersTypeDataTag; + @HotSpotVMConstant(name = "DataLayout::speculative_trap_data_tag") @Stable public int dataLayoutSpeculativeTrapDataTag; + + @HotSpotVMFlag(name = "BciProfileWidth") @Stable public int bciProfileWidth; + @HotSpotVMFlag(name = "TypeProfileWidth") @Stable public int typeProfileWidth; + @HotSpotVMFlag(name = "MethodProfileWidth") @Stable public int methodProfileWidth; + + @HotSpotVMField(name = "CodeBlob::_code_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int codeBlobCodeOffsetOffset; + @HotSpotVMField(name = "DeoptimizationBlob::_unpack_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUnpackOffsetOffset; + @HotSpotVMField(name = "DeoptimizationBlob::_uncommon_trap_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUncommonTrapOffsetOffset; + + @HotSpotVMField(name = "SharedRuntime::_ic_miss_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long inlineCacheMissBlob; + @HotSpotVMField(name = "SharedRuntime::_wrong_method_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long wrongMethodBlob; + @HotSpotVMField(name = "SharedRuntime::_deopt_blob", type = "DeoptimizationBlob*", get = HotSpotVMField.Type.VALUE) @Stable private long deoptBlob; + + @HotSpotVMManual(name = "SharedRuntime::get_ic_miss_stub()") public final long inlineCacheMissStub; + @HotSpotVMManual(name = "SharedRuntime::get_handle_wrong_method_stub()") public final long handleWrongMethodStub; + + @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->unpack()") public final long handleDeoptStub; + @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->uncommon_trap()") public final long uncommonTrapStub; + + @HotSpotVMField(name = "CodeCache::_low_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheLowBound; + @HotSpotVMField(name = "CodeCache::_high_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheHighBound; + + @HotSpotVMField(name = "StubRoutines::_aescrypt_encryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptEncryptBlockStub; + @HotSpotVMField(name = "StubRoutines::_aescrypt_decryptBlock", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long aescryptDecryptBlockStub; + @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_encryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingEncryptAESCryptStub; + @HotSpotVMField(name = "StubRoutines::_cipherBlockChaining_decryptAESCrypt", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long cipherBlockChainingDecryptAESCryptStub; + @HotSpotVMField(name = "StubRoutines::_updateBytesCRC32", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long updateBytesCRC32Stub; + @HotSpotVMField(name = "StubRoutines::_crc_table_adr", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long crcTableAddress; + + @HotSpotVMField(name = "StubRoutines::_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteArraycopy; + @HotSpotVMField(name = "StubRoutines::_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortArraycopy; + @HotSpotVMField(name = "StubRoutines::_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintArraycopy; + @HotSpotVMField(name = "StubRoutines::_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopDisjointArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_arrayof_jbyte_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jbyteAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jshort_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jshortAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jint_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jintAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_jlong_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long jlongAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedDisjointArraycopy; + @HotSpotVMField(name = "StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long oopAlignedDisjointArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopy; + @HotSpotVMField(name = "StubRoutines::_checkcast_arraycopy_uninit", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long checkcastArraycopyUninit; + @HotSpotVMField(name = "StubRoutines::_unsafe_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long unsafeArraycopy; + @HotSpotVMField(name = "StubRoutines::_generic_arraycopy", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long genericArraycopy; + + @HotSpotVMAddress(name = "JVMCIRuntime::new_instance") @Stable public long newInstanceAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::new_array") @Stable public long newArrayAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::new_multi_array") @Stable public long newMultiArrayAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::dynamic_new_array") @Stable public long dynamicNewArrayAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::dynamic_new_instance") @Stable public long dynamicNewInstanceAddress; + + @HotSpotVMAddress(name = "JVMCIRuntime::thread_is_interrupted") @Stable public long threadIsInterruptedAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::vm_message") @Stable public long vmMessageAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::identity_hash_code") @Stable public long identityHashCodeAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::exception_handler_for_pc") @Stable public long exceptionHandlerForPcAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::monitorenter") @Stable public long monitorenterAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::monitorexit") @Stable public long monitorexitAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::create_null_exception") @Stable public long createNullPointerExceptionAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::create_out_of_bounds_exception") @Stable public long createOutOfBoundsExceptionAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::log_primitive") @Stable public long logPrimitiveAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::log_object") @Stable public long logObjectAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::log_printf") @Stable public long logPrintfAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::vm_error") @Stable public long vmErrorAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::load_and_clear_exception") @Stable public long loadAndClearExceptionAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::write_barrier_pre") @Stable public long writeBarrierPreAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::write_barrier_post") @Stable public long writeBarrierPostAddress; + @HotSpotVMAddress(name = "JVMCIRuntime::validate_object") @Stable public long validateObject; + + @HotSpotVMAddress(name = "JVMCIRuntime::test_deoptimize_call_int") @Stable public long testDeoptimizeCallInt; + + @HotSpotVMAddress(name = "SharedRuntime::register_finalizer") @Stable public long registerFinalizerAddress; + @HotSpotVMAddress(name = "SharedRuntime::exception_handler_for_return_address") @Stable public long exceptionHandlerForReturnAddressAddress; + @HotSpotVMAddress(name = "SharedRuntime::OSR_migration_end") @Stable public long osrMigrationEndAddress; + + @HotSpotVMAddress(name = "os::javaTimeMillis") @Stable public long javaTimeMillisAddress; + @HotSpotVMAddress(name = "os::javaTimeNanos") @Stable public long javaTimeNanosAddress; + @HotSpotVMAddress(name = "SharedRuntime::dsin") @Stable public long arithmeticSinAddress; + @HotSpotVMAddress(name = "SharedRuntime::dcos") @Stable public long arithmeticCosAddress; + @HotSpotVMAddress(name = "SharedRuntime::dtan") @Stable public long arithmeticTanAddress; + @HotSpotVMAddress(name = "SharedRuntime::dexp") @Stable public long arithmeticExpAddress; + @HotSpotVMAddress(name = "SharedRuntime::dlog") @Stable public long arithmeticLogAddress; + @HotSpotVMAddress(name = "SharedRuntime::dlog10") @Stable public long arithmeticLog10Address; + @HotSpotVMAddress(name = "SharedRuntime::dpow") @Stable public long arithmeticPowAddress; + + @HotSpotVMFlag(name = "JVMCICounterSize") @Stable public int jvmciCountersSize; + + @HotSpotVMAddress(name = "Deoptimization::fetch_unroll_info") @Stable public long deoptimizationFetchUnrollInfo; + @HotSpotVMAddress(name = "Deoptimization::uncommon_trap") @Stable public long deoptimizationUncommonTrap; + @HotSpotVMAddress(name = "Deoptimization::unpack_frames") @Stable public long deoptimizationUnpackFrames; + + @HotSpotVMConstant(name = "Deoptimization::Reason_none") @Stable public int deoptReasonNone; + @HotSpotVMConstant(name = "Deoptimization::Reason_null_check") @Stable public int deoptReasonNullCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_range_check") @Stable public int deoptReasonRangeCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_class_check") @Stable public int deoptReasonClassCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_array_check") @Stable public int deoptReasonArrayCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_unreached0") @Stable public int deoptReasonUnreached0; + @HotSpotVMConstant(name = "Deoptimization::Reason_type_checked_inlining") @Stable public int deoptReasonTypeCheckInlining; + @HotSpotVMConstant(name = "Deoptimization::Reason_optimized_type_check") @Stable public int deoptReasonOptimizedTypeCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_not_compiled_exception_handler") @Stable public int deoptReasonNotCompiledExceptionHandler; + @HotSpotVMConstant(name = "Deoptimization::Reason_unresolved") @Stable public int deoptReasonUnresolved; + @HotSpotVMConstant(name = "Deoptimization::Reason_jsr_mismatch") @Stable public int deoptReasonJsrMismatch; + @HotSpotVMConstant(name = "Deoptimization::Reason_div0_check") @Stable public int deoptReasonDiv0Check; + @HotSpotVMConstant(name = "Deoptimization::Reason_constraint") @Stable public int deoptReasonConstraint; + @HotSpotVMConstant(name = "Deoptimization::Reason_loop_limit_check") @Stable public int deoptReasonLoopLimitCheck; + @HotSpotVMConstant(name = "Deoptimization::Reason_aliasing") @Stable public int deoptReasonAliasing; + @HotSpotVMConstant(name = "Deoptimization::Reason_transfer_to_interpreter") @Stable public int deoptReasonTransferToInterpreter; + @HotSpotVMConstant(name = "Deoptimization::Reason_LIMIT") @Stable public int deoptReasonOSROffset; + + @HotSpotVMConstant(name = "Deoptimization::Action_none") @Stable public int deoptActionNone; + @HotSpotVMConstant(name = "Deoptimization::Action_maybe_recompile") @Stable public int deoptActionMaybeRecompile; + @HotSpotVMConstant(name = "Deoptimization::Action_reinterpret") @Stable public int deoptActionReinterpret; + @HotSpotVMConstant(name = "Deoptimization::Action_make_not_entrant") @Stable public int deoptActionMakeNotEntrant; + @HotSpotVMConstant(name = "Deoptimization::Action_make_not_compilable") @Stable public int deoptActionMakeNotCompilable; + + @HotSpotVMConstant(name = "Deoptimization::_action_bits") @Stable public int deoptimizationActionBits; + @HotSpotVMConstant(name = "Deoptimization::_reason_bits") @Stable public int deoptimizationReasonBits; + @HotSpotVMConstant(name = "Deoptimization::_debug_id_bits") @Stable public int deoptimizationDebugIdBits; + @HotSpotVMConstant(name = "Deoptimization::_action_shift") @Stable public int deoptimizationActionShift; + @HotSpotVMConstant(name = "Deoptimization::_reason_shift") @Stable public int deoptimizationReasonShift; + @HotSpotVMConstant(name = "Deoptimization::_debug_id_shift") @Stable public int deoptimizationDebugIdShift; + + @HotSpotVMConstant(name = "Deoptimization::Unpack_deopt") @Stable public int deoptimizationUnpackDeopt; + @HotSpotVMConstant(name = "Deoptimization::Unpack_exception") @Stable public int deoptimizationUnpackException; + @HotSpotVMConstant(name = "Deoptimization::Unpack_uncommon_trap") @Stable public int deoptimizationUnpackUncommonTrap; + @HotSpotVMConstant(name = "Deoptimization::Unpack_reexecute") @Stable public int deoptimizationUnpackReexecute; + + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_size_of_deoptimized_frame", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockSizeOfDeoptimizedFrameOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_caller_adjustment", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockCallerAdjustmentOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_number_of_frames", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockNumberOfFramesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_total_frame_sizes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockTotalFrameSizesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_sizes", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFrameSizesOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_frame_pcs", type = "address*", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockFramePcsOffset; + @HotSpotVMField(name = "Deoptimization::UnrollBlock::_initial_info", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int deoptimizationUnrollBlockInitialInfoOffset; + + @HotSpotVMConstant(name = "vmIntrinsics::_invokeBasic") @Stable public int vmIntrinsicInvokeBasic; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToVirtual") @Stable public int vmIntrinsicLinkToVirtual; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToStatic") @Stable public int vmIntrinsicLinkToStatic; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToSpecial") @Stable public int vmIntrinsicLinkToSpecial; + @HotSpotVMConstant(name = "vmIntrinsics::_linkToInterface") @Stable public int vmIntrinsicLinkToInterface; + + @HotSpotVMConstant(name = "JVMCIEnv::ok") @Stable public int codeInstallResultOk; + @HotSpotVMConstant(name = "JVMCIEnv::dependencies_failed") @Stable public int codeInstallResultDependenciesFailed; + @HotSpotVMConstant(name = "JVMCIEnv::dependencies_invalid") @Stable public int codeInstallResultDependenciesInvalid; + @HotSpotVMConstant(name = "JVMCIEnv::cache_full") @Stable public int codeInstallResultCacheFull; + @HotSpotVMConstant(name = "JVMCIEnv::code_too_large") @Stable public int codeInstallResultCodeTooLarge; + + public String getCodeInstallResultDescription(int codeInstallResult) { + if (codeInstallResult == codeInstallResultOk) { + return "ok"; + } + if (codeInstallResult == codeInstallResultDependenciesFailed) { + return "dependencies failed"; + } + if (codeInstallResult == codeInstallResultDependenciesInvalid) { + return "dependencies invalid"; + } + if (codeInstallResult == codeInstallResultCacheFull) { + return "code cache is full"; + } + if (codeInstallResult == codeInstallResultCodeTooLarge) { + return "code is too large"; + } + assert false : codeInstallResult; + return "unknown"; + } + + @HotSpotVMConstant(name = "CompilerToVM::KLASS_TAG") @Stable public int compilerToVMKlassTag; + @HotSpotVMConstant(name = "CompilerToVM::SYMBOL_TAG") @Stable public int compilerToVMSymbolTag; + + // Checkstyle: stop + @HotSpotVMConstant(name = "CodeInstaller::VERIFIED_ENTRY") @Stable public int MARKID_VERIFIED_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::UNVERIFIED_ENTRY") @Stable public int MARKID_UNVERIFIED_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::OSR_ENTRY") @Stable public int MARKID_OSR_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::EXCEPTION_HANDLER_ENTRY") @Stable public int MARKID_EXCEPTION_HANDLER_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::DEOPT_HANDLER_ENTRY") @Stable public int MARKID_DEOPT_HANDLER_ENTRY; + @HotSpotVMConstant(name = "CodeInstaller::INVOKEINTERFACE") @Stable public int MARKID_INVOKEINTERFACE; + @HotSpotVMConstant(name = "CodeInstaller::INVOKEVIRTUAL") @Stable public int MARKID_INVOKEVIRTUAL; + @HotSpotVMConstant(name = "CodeInstaller::INVOKESTATIC") @Stable public int MARKID_INVOKESTATIC; + @HotSpotVMConstant(name = "CodeInstaller::INVOKESPECIAL") @Stable public int MARKID_INVOKESPECIAL; + @HotSpotVMConstant(name = "CodeInstaller::INLINE_INVOKE") @Stable public int MARKID_INLINE_INVOKE; + @HotSpotVMConstant(name = "CodeInstaller::POLL_NEAR") @Stable public int MARKID_POLL_NEAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_NEAR") @Stable public int MARKID_POLL_RETURN_NEAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_FAR") @Stable public int MARKID_POLL_FAR; + @HotSpotVMConstant(name = "CodeInstaller::POLL_RETURN_FAR") @Stable public int MARKID_POLL_RETURN_FAR; + @HotSpotVMConstant(name = "CodeInstaller::CARD_TABLE_ADDRESS") @Stable public int MARKID_CARD_TABLE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::HEAP_TOP_ADDRESS") @Stable public int MARKID_HEAP_TOP_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::HEAP_END_ADDRESS") @Stable public int MARKID_HEAP_END_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::NARROW_KLASS_BASE_ADDRESS") @Stable public int MARKID_NARROW_KLASS_BASE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::CRC_TABLE_ADDRESS") @Stable public int MARKID_CRC_TABLE_ADDRESS; + @HotSpotVMConstant(name = "CodeInstaller::INVOKE_INVALID") @Stable public int MARKID_INVOKE_INVALID; + + // Checkstyle: resume + + private boolean check() { + for (Field f : getClass().getDeclaredFields()) { + int modifiers = f.getModifiers(); + if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) { + assert Modifier.isFinal(modifiers) || f.getAnnotation(Stable.class) != null : "field should either be final or @Stable: " + f; + } + } + + assert codeEntryAlignment > 0 : codeEntryAlignment; + assert (layoutHelperArrayTagObjectValue & (1 << (Integer.SIZE - 1))) != 0 : "object array must have first bit set"; + assert (layoutHelperArrayTagTypeValue & (1 << (Integer.SIZE - 1))) != 0 : "type array must have first bit set"; + + return true; + } + + /** + * A compact representation of the different encoding strategies for Objects and metadata. + */ + public static class CompressEncoding { + public final long base; + public final int shift; + public final int alignment; + + CompressEncoding(long base, int shift, int alignment) { + this.base = base; + this.shift = shift; + this.alignment = alignment; + } + + public int compress(long ptr) { + if (ptr == 0L) { + return 0; + } else { + return (int) ((ptr - base) >>> shift); + } + } + + public long uncompress(int ptr) { + if (ptr == 0) { + return 0L; + } else { + return ((ptr & 0xFFFFFFFFL) << shift) + base; + } + } + + @Override + public String toString() { + return "base: " + base + " shift: " + shift + " alignment: " + alignment; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + alignment; + result = prime * result + (int) (base ^ (base >>> 32)); + result = prime * result + shift; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CompressEncoding) { + CompressEncoding other = (CompressEncoding) obj; + return alignment == other.alignment && base == other.base && shift == other.shift; + } else { + return false; + } + } + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigVerifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigVerifier.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static java.lang.String.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.org.objectweb.asm.*; +import jdk.internal.org.objectweb.asm.Type; +import jdk.vm.ci.common.*; +import sun.misc.*; + +/** + * A {@link ClassVisitor} that verifies {@link HotSpotVMConfig} does not access {@link Unsafe} from + * any of its non-static, non-constructor methods. This ensures that a deserialized + * {@link HotSpotVMConfig} object does not perform any unsafe reads on addresses that are only valid + * in the context in which the object was serialized. Note that this does not catch cases where a + * client uses an address stored in a {@link HotSpotVMConfig} field. + */ +final class HotSpotVMConfigVerifier extends ClassVisitor { + + public static boolean check() { + Class cls = HotSpotVMConfig.class; + String classFilePath = "/" + cls.getName().replace('.', '/') + ".class"; + try { + InputStream classfile = cls.getResourceAsStream(classFilePath); + ClassReader cr = new ClassReader(Objects.requireNonNull(classfile, "Could not find class file for " + cls.getName())); + ClassVisitor cv = new HotSpotVMConfigVerifier(); + cr.accept(cv, 0); + return true; + } catch (IOException e) { + throw new JVMCIError(e); + } + } + + /** + * Source file context for error reporting. + */ + String sourceFile = null; + + /** + * Line number for error reporting. + */ + int lineNo = -1; + + private static Class resolve(String name) { + try { + return Class.forName(name.replace('/', '.')); + } catch (ClassNotFoundException e) { + throw new JVMCIError(e); + } + } + + HotSpotVMConfigVerifier() { + super(Opcodes.ASM5); + } + + @Override + public void visitSource(String source, String debug) { + this.sourceFile = source; + } + + void verify(boolean condition, String message) { + if (!condition) { + error(message); + } + } + + void error(String message) { + String errorMessage = format("%s:%d: %s is not allowed in the context of compilation replay. The unsafe access should be moved into the %s constructor and the result cached in a field", + sourceFile, lineNo, message, HotSpotVMConfig.class.getSimpleName()); + throw new JVMCIError(errorMessage); + + } + + @Override + public MethodVisitor visitMethod(int access, String name, String d, String signature, String[] exceptions) { + if (!Modifier.isStatic(access) && Modifier.isPublic(access) && !name.equals("")) { + return new MethodVisitor(Opcodes.ASM5) { + + @Override + public void visitLineNumber(int line, Label start) { + lineNo = line; + } + + private Executable resolveMethod(String owner, String methodName, String methodDesc) { + Class declaringClass = resolve(owner); + while (declaringClass != null) { + if (methodName.equals("")) { + for (Constructor c : declaringClass.getDeclaredConstructors()) { + if (methodDesc.equals(Type.getConstructorDescriptor(c))) { + return c; + } + } + } else { + Type[] argumentTypes = Type.getArgumentTypes(methodDesc); + for (Method m : declaringClass.getDeclaredMethods()) { + if (m.getName().equals(methodName)) { + if (Arrays.equals(argumentTypes, Type.getArgumentTypes(m))) { + if (Type.getReturnType(methodDesc).equals(Type.getReturnType(m))) { + return m; + } + } + } + } + } + declaringClass = declaringClass.getSuperclass(); + } + throw new NoSuchMethodError(owner + "." + methodName + methodDesc); + } + + /** + * Checks whether a given method is allowed to be called. + */ + private boolean checkInvokeTarget(Executable method) { + if (method.getDeclaringClass().equals(Unsafe.class)) { + return false; + } + return true; + } + + @Override + public void visitMethodInsn(int opcode, String owner, String methodName, String methodDesc, boolean itf) { + Executable callee = resolveMethod(owner, methodName, methodDesc); + verify(checkInvokeTarget(callee), "invocation of " + callee); + } + }; + } else { + return null; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMEventListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMEventListener.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.meta.*; + +public interface HotSpotVMEventListener { + + /** + * Notifies this client that the VM is shutting down. + */ + default void notifyShutdown() { + } + + /** + * Notify on successful install into the CodeCache. + * + * @param hotSpotCodeCacheProvider + * @param installedCode + * @param compResult + */ + default void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompilationResult compResult) { + } + + /** + * Perform any extra initialization required. + * + * @param runtime + */ + default void completeInitialization(HotSpotJVMCIRuntime runtime) { + } + + /** + * Create a custom {@link JVMCIMetaAccessContext} to be used for managing the lifetime of loaded + * metadata. It a custom one isn't created then the default implementation will be a single + * context with globally shared instances of {@link ResolvedJavaType} that are never released. + * + * @param hotSpotJVMCIRuntime + * @return a custom context or null + */ + default JVMCIMetaAccessContext createMetaAccessContext(HotSpotJVMCIRuntime hotSpotJVMCIRuntime) { + return null; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVmSymbols.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVmSymbols.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; + +import sun.misc.*; + +/** + * Class to access the C++ {@code vmSymbols} table. + */ +public final class HotSpotVmSymbols { + + /** + * Returns the symbol in the {@code vmSymbols} table at position {@code index} as {@link String} + * . + * + * @param index position in the symbol table + * @return the symbol at position id + */ + public static String symbolAt(int index) { + HotSpotJVMCIRuntimeProvider runtime = runtime(); + HotSpotVMConfig config = runtime.getConfig(); + assert config.vmSymbolsFirstSID <= index && index < config.vmSymbolsSIDLimit : "index " + index + " is out of bounds"; + assert config.symbolPointerSize == Unsafe.ADDRESS_SIZE : "the following address read is broken"; + return runtime.getCompilerToVM().getSymbol(UNSAFE.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize)); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceWrapperObject.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceWrapperObject.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +/** + * A tag interface indicating that this type is a wrapper around a HotSpot metaspace object. + * + * It would preferable if this were the base class containing the pointer but that would require + * mixins since most of the wrapper types have complex supertype hierarchies. + */ +public interface MetaspaceWrapperObject { + + long getMetaspacePointer(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.vm.ci.hotspot; + +import java.lang.annotation.*; + +/** + * This annotation functions as an alias for the sun.invoke.Stable annotation within JVMCI code. It + * is specially recognized during class file parsing in the same way as that annotation. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Stable { +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SuppressFBWarnings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SuppressFBWarnings.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +/** + * Used to suppress FindBugs warnings. + */ +public @interface SuppressFBWarnings { + /** + * The set of FindBugs warnings that are to be + * suppressed in annotated element. The value can be a bug category, kind or pattern. + */ + String[] value(); + + /** + * Reason why the warning is suppressed. + */ + String justification(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.hotspot; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +/** + * Package private access to the {@link Unsafe} capability. + */ +class UnsafeAccess { + + static final Unsafe UNSAFE = initUnsafe(); + + private static Unsafe initUnsafe() { + try { + // Fast path when we are trusted. + return Unsafe.getUnsafe(); + } catch (SecurityException se) { + // Slow path when we are not trusted. + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + return (Unsafe) theUnsafe.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe", e); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EmptyEventProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EmptyEventProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot.events; + +import jdk.vm.ci.common.*; + +/** + * An empty implementation for {@link EventProvider}. This implementation is used when no logging is + * requested. + */ +public final class EmptyEventProvider implements EventProvider { + + public CompilationEvent newCompilationEvent() { + return new EmptyCompilationEvent(); + } + + public static class EmptyCompilationEvent implements CompilationEvent { + public void commit() { + throw JVMCIError.shouldNotReachHere(); + } + + public boolean shouldWrite() { + // Events of this class should never been written. + return false; + } + + public void begin() { + } + + public void end() { + } + + public void setMethod(String method) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setCompileId(int compileId) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setCompileLevel(int compileLevel) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setSucceeded(boolean succeeded) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setIsOsr(boolean isOsr) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setCodeSize(int codeSize) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setInlinedBytes(int inlinedBytes) { + throw JVMCIError.shouldNotReachHere(); + } + } + + public CompilerFailureEvent newCompilerFailureEvent() { + return new EmptyCompilerFailureEvent(); + } + + public static class EmptyCompilerFailureEvent implements CompilerFailureEvent { + public void commit() { + throw JVMCIError.shouldNotReachHere(); + } + + public boolean shouldWrite() { + // Events of this class should never been written. + return false; + } + + public void setCompileId(int compileId) { + throw JVMCIError.shouldNotReachHere(); + } + + public void setMessage(String message) { + throw JVMCIError.shouldNotReachHere(); + } + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EventProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/events/EventProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot.events; + +/** + * A provider that provides a specific implementation for events that can be logged in the compiler. + */ +public interface EventProvider { + + /** + * An instant event is an event that is not considered to have taken any time. + */ + interface InstantEvent { + /** + * Commits the event. + */ + void commit(); + + /** + * Determines if this particular event instance would be committed to the data stream right + * now if application called {@link #commit()}. This in turn depends on whether the event is + * enabled and possible other factors. + * + * @return if this event would be committed on a call to {@link #commit()}. + */ + boolean shouldWrite(); + } + + /** + * Timed events describe an operation that somehow consumes time. + */ + interface TimedEvent extends InstantEvent { + /** + * Starts the timing for this event. + */ + void begin(); + + /** + * Ends the timing period for this event. + */ + void end(); + } + + /** + * Creates a new {@link CompilationEvent}. + * + * @return a compilation event + */ + CompilationEvent newCompilationEvent(); + + /** + * A compilation event. + */ + interface CompilationEvent extends TimedEvent { + void setMethod(String method); + + void setCompileId(int compileId); + + void setCompileLevel(int compileLevel); + + void setSucceeded(boolean succeeded); + + void setIsOsr(boolean isOsr); + + void setCodeSize(int codeSize); + + void setInlinedBytes(int inlinedBytes); + } + + /** + * Creates a new {@link CompilerFailureEvent}. + * + * @return a compiler failure event + */ + CompilerFailureEvent newCompilerFailureEvent(); + + /** + * A compiler failure event. + */ + interface CompilerFailureEvent extends InstantEvent { + void setCompileId(int compileId); + + void setMessage(String message); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/logging/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/logging/package-info.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/** + * Logging framework for the HotSpot CRI implementation. + */ +package jdk.vm.ci.hotspot.logging; + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMAddress.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMAddress.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ address in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMAddress { + + /** + * Returns the name of the symbol this address is referring to. + * + * @return name of symbol of this address + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; + + /** + * List of operating systems where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostOSName()}. An empty list implies that the constant is required + * on all operating systems. + */ + @SuppressWarnings("javadoc") + String[] os() default {}; + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ constant in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMConstant { + + /** + * Returns the name of the constant. + * + * @return name of constant + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMData.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a entry in {@code gHotSpotVMData}. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMData { + + /** + * Returns the array index of this field. + * + * @return array index of field + */ + int index(); + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMField.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ field in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMField { + + /** + * Types of information this annotation can return. + */ + enum Type { + /** + * Returns the offset of this field within the type. Only valid for instance fields. + */ + OFFSET, + + /** + * Returns the absolute address of this field. Only valid for static fields. + */ + ADDRESS, + + /** + * Returns the value of this field. Only valid for static fields. + */ + VALUE; + } + + /** + * Specifies what type of information to return. + * + * @see Type + */ + Type get(); + + /** + * Returns the type name containing this field. + * + * @return name of containing type + */ + String type(); + + /** + * Returns the name of this field. + * + * @return name of field + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMFlag.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMFlag.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ flag in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMFlag { + + /** + * Returns the name of this flag. + * + * @return name of flag. + */ + String name(); + + /** + * List of architectures where this constant is required. Names are derived from + * {@link HotSpotVMConfig#getHostArchitectureName()}. An empty list implies that the constant is + * required on all architectures. + */ + @SuppressWarnings("javadoc") + String[] archs() default {}; + + boolean optional() default false; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMManual.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMManual.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Annotates a field in HotSpotVMConfig which is not read from the VM but is calculated manually. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMManual { + + /** + * Returns the name associated with that field. + * + * @return name associated with field + */ + String name(); + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspotvmconfig; + +import java.lang.annotation.*; + +/** + * Refers to a C++ type in the VM. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface HotSpotVMType { + + /** + * Types of information this annotation can return. + */ + enum Type { + /** + * Returns the size of the type (C++ {@code sizeof()}). + */ + SIZE; + } + + /** + * Specifies what type of information to return. + * + * @see Type + */ + Type get(); + + /** + * Returns the name of the type. + * + * @return name of type + */ + String name(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.inittimer; + +/** + * A facility for timing a step in the runtime initialization sequence. This is independent from all + * other JVMCI code so as to not perturb the initialization sequence. It is enabled by setting the + * {@code "jvmci.inittimer"} system property to {@code "true"}. + */ +public final class InitTimer implements AutoCloseable { + final String name; + final long start; + + private InitTimer(String name) { + this.name = name; + this.start = System.currentTimeMillis(); + System.out.println("START: " + SPACES.substring(0, timerDepth * 2) + name); + assert Thread.currentThread() == initializingThread : Thread.currentThread() + " != " + initializingThread; + timerDepth++; + } + + @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "only the initializing thread accesses this field") + public void close() { + final long end = System.currentTimeMillis(); + timerDepth--; + System.out.println(" DONE: " + SPACES.substring(0, timerDepth * 2) + name + " [" + (end - start) + " ms]"); + } + + public static InitTimer timer(String name) { + return ENABLED ? new InitTimer(name) : null; + } + + public static InitTimer timer(String name, Object suffix) { + return ENABLED ? new InitTimer(name + suffix) : null; + } + + /** + * Specifies if initialization timing is enabled. + */ + private static final boolean ENABLED = Boolean.getBoolean("jvmci.inittimer") || Boolean.getBoolean("jvmci.runtime.TimeInit"); + + public static int timerDepth = 0; + public static final String SPACES = " "; + + /** + * Used to assert the invariant that all initialization happens on the same thread. + */ + public static final Thread initializingThread; + static { + if (ENABLED) { + initializingThread = Thread.currentThread(); + System.out.println("INITIALIZING THREAD: " + initializingThread); + } else { + initializingThread = null; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/SuppressFBWarnings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/SuppressFBWarnings.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.inittimer; + +/** + * Used to suppress FindBugs warnings. + */ +public @interface SuppressFBWarnings { + /** + * The set of FindBugs warnings that are to be + * suppressed in annotated element. The value can be a bug category, kind or pattern. + */ + String[] value(); + + /** + * Reason why the warning is suppressed. + */ + String justification(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/overview.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/overview.html Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,38 @@ + + + + + + + + +The jdk.vm.ci.meta project provides an API to the runtime data structures +for various Java elements. Unlike standard Java reflection, it can model elements that are not yet loaded. +It can also expose profiling information collected by the runtime system. + + + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractJavaProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractJavaProfile.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * This object holds probability information for a set of items that were profiled at a specific + * BCI. The precision of the supplied values may vary, but a runtime that provides this information + * should be aware that it will be used to guide performance-critical decisions like speculative + * inlining, etc. + * + * @param a subclass of AbstractProfiledItem + * @param the class of the items that are profiled at the specific BCI and for which + * probabilities are stored. E.g., a ResolvedJavaType or a ResolvedJavaMethod. + */ +public abstract class AbstractJavaProfile, U> { + + private final double notRecordedProbability; + private final T[] pitems; + + public AbstractJavaProfile(double notRecordedProbability, T[] pitems) { + this.pitems = pitems; + assert !Double.isNaN(notRecordedProbability); + this.notRecordedProbability = notRecordedProbability; + assert isSorted(); + assert totalProbablility() >= 0 && totalProbablility() <= 1.0001 : totalProbablility() + " " + this; + } + + private double totalProbablility() { + double total = notRecordedProbability; + for (T item : pitems) { + total += item.probability; + } + return total; + } + + /** + * Determines if an array of profiled items are sorted in descending order of their + * probabilities. + */ + private boolean isSorted() { + for (int i = 1; i < pitems.length; i++) { + if (pitems[i - 1].getProbability() < pitems[i].getProbability()) { + return false; + } + } + return true; + } + + /** + * Returns the estimated probability of all types that could not be recorded due to profiling + * limitations. + * + * @return double value ≥ 0.0 and ≤ 1.0 + */ + public double getNotRecordedProbability() { + return notRecordedProbability; + } + + protected T[] getItems() { + return pitems; + } + + /** + * Searches for an entry of a given resolved Java type. + * + * @param type the type for which an entry should be searched + * @return the entry or null if no entry for this type can be found + */ + public T findEntry(ResolvedJavaType type) { + if (pitems != null) { + for (T pt : pitems) { + if (pt.getItem().equals(type)) { + return pt; + } + } + } + return null; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(this.getClass().getName()); + builder.append("["); + if (pitems != null) { + for (T pt : pitems) { + builder.append(pt.toString()); + builder.append(", "); + } + } + builder.append(this.notRecordedProbability); + builder.append("]"); + return builder.toString(); + } + + public boolean isIncluded(U item) { + if (this.getNotRecordedProbability() > 0.0) { + return true; + } else { + for (int i = 0; i < getItems().length; i++) { + T pitem = getItems()[i]; + U curType = pitem.getItem(); + if (curType == item) { + return true; + } + } + } + return false; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof AbstractJavaProfile)) { + return false; + } + AbstractJavaProfile that = (AbstractJavaProfile) obj; + if (that.notRecordedProbability != notRecordedProbability) { + return false; + } + if (that.pitems.length != pitems.length) { + return false; + } + for (int i = 0; i < pitems.length; ++i) { + if (!pitems[i].equals(that.pitems[i])) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return (int) Double.doubleToLongBits(notRecordedProbability) + pitems.length * 13; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractProfiledItem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractProfiledItem.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * A profiled type that has a probability. Profiled types are naturally sorted in descending order + * of their probabilities. + */ +public abstract class AbstractProfiledItem implements Comparable> { + + protected final T item; + protected final double probability; + + public AbstractProfiledItem(T item, double probability) { + assert item != null; + assert probability >= 0.0D && probability <= 1.0D; + this.item = item; + this.probability = probability; + } + + protected T getItem() { + return item; + } + + /** + * Returns the estimated probability of {@link #getItem()}. + * + * @return double value ≥ 0.0 and ≤ 1.0 + */ + public double getProbability() { + return probability; + } + + @Override + public int compareTo(AbstractProfiledItem o) { + if (getProbability() > o.getProbability()) { + return -1; + } else if (getProbability() < o.getProbability()) { + return 1; + } + return 0; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(probability); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + item.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + AbstractProfiledItem other = (AbstractProfiledItem) obj; + if (Double.doubleToLongBits(probability) != Double.doubleToLongBits(other.probability)) { + return false; + } + return item.equals(other.item); + } + + @Override + public abstract String toString(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AllocatableValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AllocatableValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Common base class for values that are stored in some location that's managed by the register + * allocator (e.g. register, stack slot). + */ +public abstract class AllocatableValue extends Value implements JavaValue { + + public static final AllocatableValue[] NONE = {}; + + public AllocatableValue(LIRKind lirKind) { + super(lirKind); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Assumptions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Assumptions.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.lang.invoke.*; +import java.util.*; + +/** + * Class for recording assumptions made during compilation. + */ +public final class Assumptions implements Iterable { + + /** + * Abstract base class for assumptions. An assumption assumes a property of the runtime that may + * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing + * {@link NoFinalizableSubclass Object.finalize()}). + */ + public abstract static class Assumption { + } + + /** + * A class for providing information that is only valid in association with a set of + * {@link Assumption}s. + * + * @param + */ + public static class AssumptionResult { + Assumption[] assumptions; + final T result; + + private static final Assumption[] EMPTY = new Assumption[0]; + + public AssumptionResult(T result, Assumption... assumptions) { + this.result = result; + this.assumptions = assumptions; + } + + public AssumptionResult(T result) { + this(result, EMPTY); + } + + public T getResult() { + return result; + } + + public boolean isAssumptionFree() { + return assumptions.length == 0; + } + + public void add(AssumptionResult other) { + Assumption[] newAssumptions = Arrays.copyOf(this.assumptions, this.assumptions.length + other.assumptions.length); + System.arraycopy(other.assumptions, 0, newAssumptions, this.assumptions.length, other.assumptions.length); + this.assumptions = newAssumptions; + } + + public boolean canRecordTo(Assumptions target) { + /* + * We can use the result if it is either assumption free, or if we have a valid + * Assumptions object where we can record assumptions. + */ + return assumptions.length == 0 || target != null; + } + + public void recordTo(Assumptions target) { + assert canRecordTo(target); + + if (assumptions.length > 0) { + for (Assumption assumption : assumptions) { + target.record(assumption); + } + } + } + } + + /** + * An assumption that a given class has no subclasses implementing {@link Object#finalize()}). + */ + public static final class NoFinalizableSubclass extends Assumption { + + private ResolvedJavaType receiverType; + + public NoFinalizableSubclass(ResolvedJavaType receiverType) { + this.receiverType = receiverType; + } + + @Override + public int hashCode() { + return 31 + receiverType.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NoFinalizableSubclass) { + NoFinalizableSubclass other = (NoFinalizableSubclass) obj; + return other.receiverType.equals(receiverType); + } + return false; + } + + @Override + public String toString() { + return "NoFinalizableSubclass[receiverType=" + receiverType.toJavaName() + "]"; + } + + } + + /** + * An assumption that a given abstract or interface type has one direct concrete subtype. There + * is no requirement that the subtype is a leaf type. + */ + public static final class ConcreteSubtype extends Assumption { + + /** + * Type the assumption is made about. + */ + public final ResolvedJavaType context; + + /** + * Assumed concrete sub-type of the context type. + */ + public final ResolvedJavaType subtype; + + public ConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) { + this.context = context; + this.subtype = subtype; + assert context.isAbstract(); + assert subtype.isConcrete() || context.isInterface() : subtype.toString() + " : " + context.toString(); + assert !subtype.isArray() || subtype.getElementalType().isFinalFlagSet() : subtype.toString() + " : " + context.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + context.hashCode(); + result = prime * result + subtype.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConcreteSubtype) { + ConcreteSubtype other = (ConcreteSubtype) obj; + return other.context.equals(context) && other.subtype.equals(subtype); + } + return false; + } + + @Override + public String toString() { + return "ConcreteSubtype[context=" + context.toJavaName() + ", subtype=" + subtype.toJavaName() + "]"; + } + } + + /** + * An assumption that a given type has no subtypes. + */ + public static final class LeafType extends Assumption { + + /** + * Type the assumption is made about. + */ + public final ResolvedJavaType context; + + public LeafType(ResolvedJavaType context) { + this.context = context; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + context.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof LeafType) { + LeafType other = (LeafType) obj; + return other.context.equals(context); + } + return false; + } + + @Override + public String toString() { + return "LeafSubtype[context=" + context.toJavaName() + "]"; + } + } + + /** + * An assumption that a given virtual method has a given unique implementation. + */ + public static final class ConcreteMethod extends Assumption { + + /** + * A virtual (or interface) method whose unique implementation for the receiver type in + * {@link #context} is {@link #impl}. + */ + public final ResolvedJavaMethod method; + + /** + * A receiver type. + */ + public final ResolvedJavaType context; + + /** + * The unique implementation of {@link #method} for {@link #context}. + */ + public final ResolvedJavaMethod impl; + + public ConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { + this.method = method; + this.context = context; + this.impl = impl; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + method.hashCode(); + result = prime * result + context.hashCode(); + result = prime * result + impl.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConcreteMethod) { + ConcreteMethod other = (ConcreteMethod) obj; + return other.method.equals(method) && other.context.equals(context) && other.impl.equals(impl); + } + return false; + } + + @Override + public String toString() { + return "ConcreteMethod[method=" + method.format("%H.%n(%p)%r") + ", context=" + context.toJavaName() + ", impl=" + impl.format("%H.%n(%p)%r") + "]"; + } + } + + /** + * An assumption that a given call site's method handle did not change. + */ + public static final class CallSiteTargetValue extends Assumption { + + public final CallSite callSite; + public final MethodHandle methodHandle; + + public CallSiteTargetValue(CallSite callSite, MethodHandle methodHandle) { + this.callSite = callSite; + this.methodHandle = methodHandle; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + callSite.hashCode(); + result = prime * result + methodHandle.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof CallSiteTargetValue) { + CallSiteTargetValue other = (CallSiteTargetValue) obj; + return callSite.equals(other.callSite) && methodHandle.equals(other.methodHandle); + } + return false; + } + + @Override + public String toString() { + return "CallSiteTargetValue[callSite=" + callSite + ", methodHandle=" + methodHandle + "]"; + } + } + + private final Set assumptions = new HashSet<>(); + + /** + * Returns whether any assumptions have been registered. + * + * @return {@code true} if at least one assumption has been registered, {@code false} otherwise. + */ + public boolean isEmpty() { + return assumptions.isEmpty(); + } + + @Override + public int hashCode() { + throw new UnsupportedOperationException("hashCode"); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof Assumptions) { + Assumptions that = (Assumptions) obj; + if (!this.assumptions.equals(that.assumptions)) { + return false; + } + return true; + } + return false; + } + + @Override + public Iterator iterator() { + return assumptions.iterator(); + } + + /** + * Records an assumption that the specified type has no finalizable subclasses. + * + * @param receiverType the type that is assumed to have no finalizable subclasses + */ + public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) { + record(new NoFinalizableSubclass(receiverType)); + } + + /** + * Records that {@code subtype} is the only concrete subtype in the class hierarchy below + * {@code context}. + * + * @param context the root of the subtree of the class hierarchy that this assumptions is about + * @param subtype the one concrete subtype + */ + public void recordConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) { + record(new ConcreteSubtype(context, subtype)); + } + + /** + * Records that {@code impl} is the only possible concrete target for a virtual call to + * {@code method} with a receiver of type {@code context}. + * + * @param method a method that is the target of a virtual call + * @param context the receiver type of a call to {@code method} + * @param impl the concrete method that is the only possible target for the virtual call + */ + public void recordConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) { + record(new ConcreteMethod(method, context, impl)); + } + + public void record(Assumption assumption) { + assumptions.add(assumption); + } + + /** + * Gets a copy of the assumptions recorded in this object as an array. + */ + public Assumption[] toArray() { + return assumptions.toArray(new Assumption[assumptions.size()]); + } + + /** + * Copies assumptions recorded by another {@link Assumptions} object into this object. + */ + public void record(Assumptions other) { + assert other != this; + assumptions.addAll(other.assumptions); + } + + @Override + public String toString() { + return "Assumptions[" + assumptions + "]"; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Represents a compile-time constant (boxed) value within the compiler. + */ +public interface Constant { + + boolean isDefaultForKind(); + + String toValueString(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantPool.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantPool.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Represents the runtime representation of the constant pool that is used by the compiler when + * parsing bytecode. Provides methods to look up a constant pool entry without performing + * resolution. They are used during compilation. + */ +public interface ConstantPool { + + /** + * Returns the number of entries the constant pool. + * + * @return number of entries in the constant pool + */ + int length(); + + /** + * Ensures that the type referenced by the specified constant pool entry is loaded and + * initialized. This can be used to compile time resolve a type. It works for field, method, or + * type constant pool entries. + * + * @param cpi the index of the constant pool entry that references the type + * @param opcode the opcode of the instruction that references the type + */ + void loadReferencedType(int cpi, int opcode); + + /** + * Looks up a reference to a field. If {@code opcode} is non-negative, then resolution checks + * specific to the bytecode it denotes are performed if the field is already resolved. Should + * any of these checks fail, an unresolved field reference is returned. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return a reference to the field at {@code cpi} in this pool + * @throws ClassFormatError if the entry at {@code cpi} is not a field + */ + JavaField lookupField(int cpi, int opcode); + + /** + * Looks up a reference to a method. If {@code opcode} is non-negative, then resolution checks + * specific to the bytecode it denotes are performed if the method is already resolved. Should + * any of these checks fail, an unresolved method reference is returned. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return a reference to the method at {@code cpi} in this pool + * @throws ClassFormatError if the entry at {@code cpi} is not a method + */ + JavaMethod lookupMethod(int cpi, int opcode); + + /** + * Looks up a reference to a type. If {@code opcode} is non-negative, then resolution checks + * specific to the bytecode it denotes are performed if the type is already resolved. Should any + * of these checks fail, an unresolved type reference is returned. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return a reference to the compiler interface type + */ + JavaType lookupType(int cpi, int opcode); + + /** + * Looks up an Utf8 string. + * + * @param cpi the constant pool index + * @return the Utf8 string at index {@code cpi} in this constant pool + */ + String lookupUtf8(int cpi); + + /** + * Looks up a method signature. + * + * @param cpi the constant pool index + * @return the method signature at index {@code cpi} in this constant pool + */ + Signature lookupSignature(int cpi); + + /** + * Looks up a constant at the specified index. + * + * @param cpi the constant pool index + * @return the {@code Constant} or {@code JavaType} instance representing the constant pool + * entry + */ + Object lookupConstant(int cpi); + + /** + * Looks up the appendix at the specified index. + * + * @param cpi the constant pool index + * @param opcode the opcode of the instruction for which the lookup is being performed or + * {@code -1} + * @return the appendix if it exists and is resolved or {@code null} + */ + JavaConstant lookupAppendix(int cpi, int opcode); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.lang.invoke.*; + +/** + * Reflection operations on values represented as {@linkplain JavaConstant constants}. All methods + * in this interface require the VM to access the actual object encapsulated in + * {@link JavaKind#Object object} constants. This access is not always possible, depending on kind + * of VM and the state that the VM is in. Therefore, all methods can return {@code null} at any + * time, to indicate that the result is not available at this point. The caller is responsible to + * check for {@code null} results and handle them properly, e.g., not perform an optimization. + */ +public interface ConstantReflectionProvider { + + /** + * Compares two constants for equality. The equality relationship is symmetric. Returns + * {@link Boolean#TRUE true} if the two constants represent the same run time value, + * {@link Boolean#FALSE false} if they are different. Returns {@code null} if the constants + * cannot be compared at this point. + */ + Boolean constantEquals(Constant x, Constant y); + + /** + * Returns the length of the array constant. Returns {@code null} if the constant is not an + * array, or if the array length is not available at this point. + */ + Integer readArrayLength(JavaConstant array); + + /** + * Reads a value from the given array at the given index. Returns {@code null} if the constant + * is not an array, if the index is out of bounds, or if the value is not available at this + * point. + */ + JavaConstant readArrayElement(JavaConstant array, int index); + + /** + * Reads a value from the given array at the given index if it is a stable array. Returns + * {@code null} if the constant is not a stable array, if it is a default value, if the index is + * out of bounds, or if the value is not available at this point. + */ + JavaConstant readConstantArrayElement(JavaConstant array, int index); + + /** + * Reads a value from the given array at the given offset if it is a stable array. The offset + * will be decoded relative to the platform addressing into an index into the array. Returns + * {@code null} if the constant is not a stable array, if it is a default value, if the offset + * is out of bounds, or if the value is not available at this point. + */ + JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset); + + /** + * Gets the constant value of this field. Note that a {@code static final} field may not be + * considered constant if its declaring class is not yet initialized or if it is a well known + * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}). + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @return the constant value of this field or {@code null} if this field is not considered + * constant by the runtime + */ + JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver); + + /** + * Gets the current value of this field for a given object, if available. + * + * There is no guarantee that the same value will be returned by this method for a field unless + * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) + * constant} by the runtime. + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @return the value of this field or {@code null} if the value is not available (e.g., because + * the field holder is not yet initialized). + */ + JavaConstant readFieldValue(JavaField field, JavaConstant receiver); + + /** + * Gets the current value of this field for a given object, if available. Like + * {@link #readFieldValue(JavaField, JavaConstant)} but treats array fields as stable. + * + * There is no guarantee that the same value will be returned by this method for a field unless + * the field is considered to be {@linkplain #readConstantFieldValue(JavaField, JavaConstant) + * constant} by the runtime. + * + * @param receiver object from which this field's value is to be read. This value is ignored if + * this field is static. + * @param isDefaultStable if {@code true}, default values are considered stable + * @return the value of this field or {@code null} if the value is not available (e.g., because + * the field holder is not yet initialized). + */ + JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable); + + /** + * Converts the given {@link JavaKind#isPrimitive() primitive} constant to a boxed + * {@link JavaKind#Object object} constant, according to the Java boxing rules. Returns + * {@code null} if the source is is not a primitive constant, or the boxed value is not + * available at this point. + */ + JavaConstant boxPrimitive(JavaConstant source); + + /** + * Converts the given {@link JavaKind#Object object} constant to a + * {@link JavaKind#isPrimitive() primitive} constant, according to the Java unboxing rules. + * Returns {@code null} if the source is is not an object constant that can be unboxed, or the + * unboxed value is not available at this point. + */ + JavaConstant unboxPrimitive(JavaConstant source); + + /** + * Gets a string as a {@link JavaConstant}. + */ + JavaConstant forString(String value); + + /** + * Returns the {@link ResolvedJavaType} for a {@link Class} object (or any other object regarded + * as a class by the VM) encapsulated in the given constant. Returns {@code null} if the + * constant does not encapsulate a class, or if the type is not available at this point. + */ + ResolvedJavaType asJavaType(Constant constant); + + /** + * Check if the constant is embeddable in the code. + */ + boolean isEmbeddable(Constant constant); + + /** + * Gets access to the internals of {@link MethodHandle}. + */ + MethodHandleAccessProvider getMethodHandleAccess(); + + /** + * Gets raw memory access. + */ + MemoryAccessProvider getMemoryAccessProvider(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DefaultProfilingInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DefaultProfilingInfo.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * An implementation of {@link ProfilingInfo} that can used in the absence of real profile + * information. + */ +public final class DefaultProfilingInfo implements ProfilingInfo { + + private static final ProfilingInfo[] NO_PROFILING_INFO = new ProfilingInfo[]{new DefaultProfilingInfo(TriState.TRUE), new DefaultProfilingInfo(TriState.FALSE), + new DefaultProfilingInfo(TriState.UNKNOWN)}; + + private final TriState exceptionSeen; + + DefaultProfilingInfo(TriState exceptionSeen) { + this.exceptionSeen = exceptionSeen; + } + + @Override + public int getCodeSize() { + return 0; + } + + @Override + public JavaTypeProfile getTypeProfile(int bci) { + return null; + } + + @Override + public JavaMethodProfile getMethodProfile(int bci) { + return null; + } + + @Override + public double getBranchTakenProbability(int bci) { + return -1; + } + + @Override + public double[] getSwitchProbabilities(int bci) { + return null; + } + + @Override + public TriState getExceptionSeen(int bci) { + return exceptionSeen; + } + + @Override + public TriState getNullSeen(int bci) { + return TriState.UNKNOWN; + } + + @Override + public int getExecutionCount(int bci) { + return -1; + } + + public static ProfilingInfo get(TriState exceptionSeen) { + return NO_PROFILING_INFO[exceptionSeen.ordinal()]; + } + + @Override + public int getDeoptimizationCount(DeoptimizationReason reason) { + return 0; + } + + @Override + public boolean isMature() { + return false; + } + + @Override + public String toString() { + return "BaseProfilingInfo<" + this.toString(null, "; ") + ">"; + } + + public void setMature() { + // Do nothing + } + + public boolean setCompilerIRSize(Class irType, int nodeCount) { + return false; + } + + public int getCompilerIRSize(Class irType) { + return -1; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationAction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationAction.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Specifies the action that should be taken by the runtime in case a certain deoptimization is + * triggered. + */ +public enum DeoptimizationAction { + /** + * Do not invalidate the machine code. This is typically used when deoptimizing at a point where + * it's highly likely nothing will change the likelihood of the deoptimization happening again. + * For example, a compiled array allocation where the size is negative. + */ + None(false), + + /** + * Do not invalidate the machine code, but schedule a recompilation if this deoptimization is + * triggered too often. + */ + RecompileIfTooManyDeopts(true), + + /** + * Invalidate the machine code and reset the profiling information. + */ + InvalidateReprofile(true), + + /** + * Invalidate the machine code and immediately schedule a recompilation. This is typically used + * when deoptimizing to resolve an unresolved symbol in which case extra profiling is not + * required to determine that the deoptimization will not re-occur. + */ + InvalidateRecompile(true), + + /** + * Invalidate the machine code and stop compiling the outermost method of this compilation. + */ + InvalidateStopCompiling(true); + + private final boolean invalidatesCompilation; + + private DeoptimizationAction(boolean invalidatesCompilation) { + this.invalidatesCompilation = invalidatesCompilation; + } + + public boolean doesInvalidateCompilation() { + return invalidatesCompilation; + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Enumeration of reasons for why a deoptimization is happening. + */ +public enum DeoptimizationReason { + None, + NullCheckException, + BoundsCheckException, + ClassCastException, + ArrayStoreException, + UnreachedCode, + TypeCheckedInliningViolated, + OptimizedTypeCheckViolated, + NotCompiledExceptionHandler, + Unresolved, + JavaSubroutineMismatch, + ArithmeticException, + RuntimeConstraint, + LoopLimitCheck, + Aliasing, + TransferToInterpreter, +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ExceptionHandler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ExceptionHandler.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +/** + * Represents an exception handler within the bytecodes. + */ +public final class ExceptionHandler { + + private final int startBCI; + private final int endBCI; + private final int handlerBCI; + private final int catchTypeCPI; + private final JavaType catchType; + + /** + * Creates a new exception handler with the specified ranges. + * + * @param startBCI the start index of the protected range + * @param endBCI the end index of the protected range + * @param catchBCI the index of the handler + * @param catchTypeCPI the index of the throwable class in the constant pool + * @param catchType the type caught by this exception handler + */ + public ExceptionHandler(int startBCI, int endBCI, int catchBCI, int catchTypeCPI, JavaType catchType) { + this.startBCI = startBCI; + this.endBCI = endBCI; + this.handlerBCI = catchBCI; + this.catchTypeCPI = catchTypeCPI; + this.catchType = catchType; + } + + /** + * Returns the start bytecode index of the protected range of this handler. + */ + public int getStartBCI() { + return startBCI; + } + + /** + * Returns the end bytecode index of the protected range of this handler. + */ + public int getEndBCI() { + return endBCI; + } + + /** + * Returns the bytecode index of the handler block of this handler. + */ + public int getHandlerBCI() { + return handlerBCI; + } + + /** + * Returns the index into the constant pool representing the type of exception caught by this + * handler. + */ + public int catchTypeCPI() { + return catchTypeCPI; + } + + /** + * Checks whether this handler catches all exceptions. + * + * @return {@code true} if this handler catches all exceptions + */ + public boolean isCatchAll() { + return catchTypeCPI == 0; + } + + /** + * Returns the type of exception caught by this exception handler. + */ + public JavaType getCatchType() { + return catchType; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ExceptionHandler)) { + return false; + } + ExceptionHandler that = (ExceptionHandler) obj; + if (this.startBCI != that.startBCI || this.endBCI != that.endBCI || this.handlerBCI != that.handlerBCI || this.catchTypeCPI != that.catchTypeCPI) { + return false; + } + return Objects.equals(this.catchType, that.catchType); + } + + @Override + public String toString() { + return "ExceptionHandler"; + } + + @Override + public int hashCode() { + return catchTypeCPI ^ endBCI ^ handlerBCI; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Represents the resolved target of an invocation. + */ +public interface InvokeTarget { +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JVMCIMetaAccessContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JVMCIMetaAccessContext.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * A context in which the results looking up the {@link ResolvedJavaType} for a {@link Class} are + * cached. + */ +public interface JVMCIMetaAccessContext { + + /** + * Gets the JVMCI mirror for a {@link Class} object. + * + * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} + */ + + ResolvedJavaType fromClass(Class clazz); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Represents a constant (boxed) value, such as an integer, floating point number, or object + * reference, within the compiler and across the compiler/runtime interface. Exports a set of + * {@code JavaConstant} instances that represent frequently used constant values, such as + * {@link #NULL_POINTER}. + */ +public interface JavaConstant extends Constant, JavaValue { + /* + * Using a larger cache for integers leads to only a slight increase in cache hit ratio which is + * not enough to justify the impact on startup time. + */ + JavaConstant NULL_POINTER = new NullConstant(); + PrimitiveConstant INT_MINUS_1 = new PrimitiveConstant(JavaKind.Int, -1); + PrimitiveConstant INT_0 = new PrimitiveConstant(JavaKind.Int, 0); + PrimitiveConstant INT_1 = new PrimitiveConstant(JavaKind.Int, 1); + PrimitiveConstant INT_2 = new PrimitiveConstant(JavaKind.Int, 2); + PrimitiveConstant LONG_0 = new PrimitiveConstant(JavaKind.Long, 0L); + PrimitiveConstant LONG_1 = new PrimitiveConstant(JavaKind.Long, 1L); + PrimitiveConstant FLOAT_0 = new PrimitiveConstant(JavaKind.Float, Float.floatToRawIntBits(0.0F)); + PrimitiveConstant FLOAT_1 = new PrimitiveConstant(JavaKind.Float, Float.floatToRawIntBits(1.0F)); + PrimitiveConstant DOUBLE_0 = new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(0.0D)); + PrimitiveConstant DOUBLE_1 = new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(1.0D)); + PrimitiveConstant TRUE = new PrimitiveConstant(JavaKind.Boolean, 1L); + PrimitiveConstant FALSE = new PrimitiveConstant(JavaKind.Boolean, 0L); + + /** + * Returns the Java kind of this constant. + */ + JavaKind getJavaKind(); + + /** + * Checks whether this constant is null. + * + * @return {@code true} if this constant is the null constant + */ + boolean isNull(); + + static boolean isNull(Constant c) { + if (c instanceof JavaConstant) { + return ((JavaConstant) c).isNull(); + } else { + return false; + } + } + + /** + * Checks whether this constant is non-null. + * + * @return {@code true} if this constant is a primitive, or an object constant that is not null + */ + default boolean isNonNull() { + return !isNull(); + } + + /** + * Checks whether this constant is the default value for its kind (null, 0, 0.0, false). + * + * @return {@code true} if this constant is the default value for its kind + */ + boolean isDefaultForKind(); + + /** + * Returns the value of this constant as a boxed Java value. + * + * @return the value of this constant + */ + Object asBoxedPrimitive(); + + /** + * Returns the primitive int value this constant represents. The constant must have a + * {@link JavaKind#getStackKind()} of {@link JavaKind#Int}. + * + * @return the constant value + */ + int asInt(); + + /** + * Returns the primitive boolean value this constant represents. The constant must have kind + * {@link JavaKind#Boolean}. + * + * @return the constant value + */ + boolean asBoolean(); + + /** + * Returns the primitive long value this constant represents. The constant must have kind + * {@link JavaKind#Long}, a {@link JavaKind#getStackKind()} of {@link JavaKind#Int}. + * + * @return the constant value + */ + long asLong(); + + /** + * Returns the primitive float value this constant represents. The constant must have kind + * {@link JavaKind#Float}. + * + * @return the constant value + */ + float asFloat(); + + /** + * Returns the primitive double value this constant represents. The constant must have kind + * {@link JavaKind#Double}. + * + * @return the constant value + */ + double asDouble(); + + default String toValueString() { + if (getJavaKind() == JavaKind.Illegal) { + return "illegal"; + } else { + return getJavaKind().format(asBoxedPrimitive()); + } + } + + static String toString(JavaConstant constant) { + if (constant.getJavaKind() == JavaKind.Illegal) { + return "illegal"; + } else { + return constant.getJavaKind().getJavaName() + "[" + constant.toValueString() + "]"; + } + } + + /** + * Creates a boxed double constant. + * + * @param d the double value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forDouble(double d) { + if (Double.compare(0.0D, d) == 0) { + return DOUBLE_0; + } + if (Double.compare(d, 1.0D) == 0) { + return DOUBLE_1; + } + return new PrimitiveConstant(JavaKind.Double, Double.doubleToRawLongBits(d)); + } + + /** + * Creates a boxed float constant. + * + * @param f the float value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forFloat(float f) { + if (Float.compare(f, 0.0F) == 0) { + return FLOAT_0; + } + if (Float.compare(f, 1.0F) == 0) { + return FLOAT_1; + } + return new PrimitiveConstant(JavaKind.Float, Float.floatToRawIntBits(f)); + } + + /** + * Creates a boxed long constant. + * + * @param i the long value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forLong(long i) { + if (i == 0) { + return LONG_0; + } else if (i == 1) { + return LONG_1; + } else { + return new PrimitiveConstant(JavaKind.Long, i); + } + } + + /** + * Creates a boxed integer constant. + * + * @param i the integer value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forInt(int i) { + switch (i) { + case -1: + return INT_MINUS_1; + case 0: + return INT_0; + case 1: + return INT_1; + case 2: + return INT_2; + default: + return new PrimitiveConstant(JavaKind.Int, i); + } + } + + /** + * Creates a boxed byte constant. + * + * @param i the byte value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forByte(byte i) { + return new PrimitiveConstant(JavaKind.Byte, i); + } + + /** + * Creates a boxed boolean constant. + * + * @param i the boolean value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forBoolean(boolean i) { + return i ? TRUE : FALSE; + } + + /** + * Creates a boxed char constant. + * + * @param i the char value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forChar(char i) { + return new PrimitiveConstant(JavaKind.Char, i); + } + + /** + * Creates a boxed short constant. + * + * @param i the short value to box + * @return a boxed copy of {@code value} + */ + static PrimitiveConstant forShort(short i) { + return new PrimitiveConstant(JavaKind.Short, i); + } + + /** + * Creates a {@link JavaConstant} from a primitive integer of a certain kind. + */ + static PrimitiveConstant forIntegerKind(JavaKind kind, long i) { + switch (kind) { + case Boolean: + return forBoolean(i != 0); + case Byte: + return forByte((byte) i); + case Short: + return forShort((short) i); + case Char: + return forChar((char) i); + case Int: + return forInt((int) i); + case Long: + return forLong(i); + default: + throw new IllegalArgumentException("not an integer kind: " + kind); + } + } + + /** + * Creates a {@link JavaConstant} from a primitive integer of a certain width. + */ + static PrimitiveConstant forPrimitiveInt(int bits, long i) { + assert bits <= 64; + switch (bits) { + case 1: + return forBoolean(i != 0); + case 8: + return forByte((byte) i); + case 16: + return forShort((short) i); + case 32: + return forInt((int) i); + case 64: + return forLong(i); + default: + throw new IllegalArgumentException("unsupported integer width: " + bits); + } + } + + /** + * Creates a boxed constant for the given boxed primitive value. + * + * @param value the Java boxed value + * @return the primitive constant holding the {@code value} + */ + static PrimitiveConstant forBoxedPrimitive(Object value) { + if (value instanceof Boolean) { + return forBoolean((Boolean) value); + } else if (value instanceof Byte) { + return forByte((Byte) value); + } else if (value instanceof Character) { + return forChar((Character) value); + } else if (value instanceof Short) { + return forShort((Short) value); + } else if (value instanceof Integer) { + return forInt((Integer) value); + } else if (value instanceof Long) { + return forLong((Long) value); + } else if (value instanceof Float) { + return forFloat((Float) value); + } else if (value instanceof Double) { + return forDouble((Double) value); + } else { + return null; + } + } + + static PrimitiveConstant forIllegal() { + return new PrimitiveConstant(JavaKind.Illegal, 0); + } + + /** + * Returns a constant with the default value for the given kind. + */ + static JavaConstant defaultForKind(JavaKind kind) { + switch (kind) { + case Boolean: + return FALSE; + case Byte: + return forByte((byte) 0); + case Char: + return forChar((char) 0); + case Short: + return forShort((short) 0); + case Int: + return INT_0; + case Double: + return DOUBLE_0; + case Float: + return FLOAT_0; + case Long: + return LONG_0; + case Object: + return NULL_POINTER; + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Returns the zero value for a given numeric kind. + */ + static JavaConstant zero(JavaKind kind) { + switch (kind) { + case Boolean: + return FALSE; + case Byte: + return forByte((byte) 0); + case Char: + return forChar((char) 0); + case Double: + return DOUBLE_0; + case Float: + return FLOAT_0; + case Int: + return INT_0; + case Long: + return LONG_0; + case Short: + return forShort((short) 0); + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Returns the one value for a given numeric kind. + */ + static JavaConstant one(JavaKind kind) { + switch (kind) { + case Boolean: + return TRUE; + case Byte: + return forByte((byte) 1); + case Char: + return forChar((char) 1); + case Double: + return DOUBLE_1; + case Float: + return FLOAT_1; + case Int: + return INT_1; + case Long: + return LONG_1; + case Short: + return forShort((short) 1); + default: + throw new IllegalArgumentException(kind.toString()); + } + } + + /** + * Adds two numeric constants. + */ + static JavaConstant add(JavaConstant x, JavaConstant y) { + assert x.getJavaKind() == y.getJavaKind(); + switch (x.getJavaKind()) { + case Byte: + return forByte((byte) (x.asInt() + y.asInt())); + case Char: + return forChar((char) (x.asInt() + y.asInt())); + case Double: + return forDouble(x.asDouble() + y.asDouble()); + case Float: + return forFloat(x.asFloat() + y.asFloat()); + case Int: + return forInt(x.asInt() + y.asInt()); + case Long: + return forLong(x.asLong() + y.asLong()); + case Short: + return forShort((short) (x.asInt() + y.asInt())); + default: + throw new IllegalArgumentException(x.getJavaKind().toString()); + } + } + + /** + * Multiplies two numeric constants. + */ + static PrimitiveConstant mul(JavaConstant x, JavaConstant y) { + assert x.getJavaKind() == y.getJavaKind(); + switch (x.getJavaKind()) { + case Byte: + return forByte((byte) (x.asInt() * y.asInt())); + case Char: + return forChar((char) (x.asInt() * y.asInt())); + case Double: + return forDouble(x.asDouble() * y.asDouble()); + case Float: + return forFloat(x.asFloat() * y.asFloat()); + case Int: + return forInt(x.asInt() * y.asInt()); + case Long: + return forLong(x.asLong() * y.asLong()); + case Short: + return forShort((short) (x.asInt() * y.asInt())); + default: + throw new IllegalArgumentException(x.getJavaKind().toString()); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaField.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.util.*; + +/** + * Represents a reference to a Java field, either resolved or unresolved fields. Fields, like + * methods and types, are resolved through {@link ConstantPool constant pools}. + */ +public interface JavaField extends TrustedInterface { + + /** + * Returns the name of this field. + */ + String getName(); + + /** + * Returns a {@link JavaType} object that identifies the declared type for this field. + */ + JavaType getType(); + + /** + * Returns the kind of this field. This is the same as calling {@link #getType}. + * {@link JavaType#getJavaKind getJavaKind}. + */ + default JavaKind getJavaKind() { + return getType().getJavaKind(); + } + + /** + * Returns the {@link JavaType} object representing the class or interface that declares this + * field. + */ + JavaType getDeclaringClass(); + + /** + * Gets a string for this field formatted according to a given format specification. A format + * specification is composed of characters that are to be copied verbatim to the result and + * specifiers that denote an attribute of this field that is to be copied to the result. A + * specifier is a single character preceded by a '%' character. The accepted specifiers and the + * field attributes they denote are described below: + * + *
+     *     Specifier | Description                                          | Example(s)
+     *     ----------+------------------------------------------------------------------------------------------
+     *     'T'       | Qualified type                                       | "int" "java.lang.String"
+     *     't'       | Unqualified type                                     | "int" "String"
+     *     'H'       | Qualified holder                                     | "java.util.Map.Entry"
+     *     'h'       | Unqualified holder                                   | "Entry"
+     *     'n'       | Field name                                           | "age"
+     *     'f'       | Indicator if field is unresolved, static or instance | "unresolved" "static" "instance"
+     *     '%'       | A '%' character                                      | "%"
+     * 
+ * + * @param format a format specification + * @return the result of formatting this field according to {@code format} + * @throws IllegalFormatException if an illegal specifier is encountered in {@code format} + */ + @SuppressWarnings("fallthrough") + default String format(String format) throws IllegalFormatException { + StringBuilder sb = new StringBuilder(); + int index = 0; + JavaType type = getType(); + while (index < format.length()) { + char ch = format.charAt(index++); + if (ch == '%') { + if (index >= format.length()) { + throw new UnknownFormatConversionException("An unquoted '%' character cannot terminate a field format specification"); + } + char specifier = format.charAt(index++); + switch (specifier) { + case 'T': + case 't': { + sb.append(type.toJavaName(specifier == 'T')); + break; + } + case 'H': + case 'h': { + sb.append(getDeclaringClass().toJavaName(specifier == 'H')); + break; + } + case 'n': { + sb.append(getName()); + break; + } + case 'f': { + sb.append(!(this instanceof ResolvedJavaField) ? "unresolved" : ((ResolvedJavaField) this).isStatic() ? "static" : "instance"); + break; + } + case '%': { + sb.append('%'); + break; + } + default: { + throw new UnknownFormatConversionException(String.valueOf(specifier)); + } + } + } else { + sb.append(ch); + } + } + return sb.toString(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.lang.reflect.*; + +//JaCoCo Exclude + +/** + * Denotes the basic kinds of types in CRI, including the all the Java primitive types, for example, + * {@link JavaKind#Int} for {@code int} and {@link JavaKind#Object} for all object types. A kind has + * a single character short name, a Java name, and a set of flags further describing its behavior. + */ +public enum JavaKind implements PlatformKind { + /** The primitive boolean kind, represented as an int on the stack. */ + Boolean('z', "boolean", 1, true, java.lang.Boolean.TYPE, java.lang.Boolean.class), + + /** The primitive byte kind, represented as an int on the stack. */ + Byte('b', "byte", 1, true, java.lang.Byte.TYPE, java.lang.Byte.class), + + /** The primitive short kind, represented as an int on the stack. */ + Short('s', "short", 1, true, java.lang.Short.TYPE, java.lang.Short.class), + + /** The primitive char kind, represented as an int on the stack. */ + Char('c', "char", 1, true, java.lang.Character.TYPE, java.lang.Character.class), + + /** The primitive int kind, represented as an int on the stack. */ + Int('i', "int", 1, true, java.lang.Integer.TYPE, java.lang.Integer.class), + + /** The primitive float kind. */ + Float('f', "float", 1, false, java.lang.Float.TYPE, java.lang.Float.class), + + /** The primitive long kind. */ + Long('j', "long", 2, false, java.lang.Long.TYPE, java.lang.Long.class), + + /** The primitive double kind. */ + Double('d', "double", 2, false, java.lang.Double.TYPE, java.lang.Double.class), + + /** The Object kind, also used for arrays. */ + Object('a', "Object", 1, false, null, null), + + /** The void float kind. */ + Void('v', "void", 0, false, java.lang.Void.TYPE, java.lang.Void.class), + + /** The non-type. */ + Illegal('-', "illegal", 0, false, null, null); + + private final char typeChar; + private final String javaName; + private final boolean isStackInt; + private final Class primitiveJavaClass; + private final Class boxedJavaClass; + private final EnumKey key = new EnumKey<>(this); + private final int slotCount; + + private JavaKind(char typeChar, String javaName, int slotCount, boolean isStackInt, Class primitiveJavaClass, Class boxedJavaClass) { + this.typeChar = typeChar; + this.javaName = javaName; + this.slotCount = slotCount; + this.isStackInt = isStackInt; + this.primitiveJavaClass = primitiveJavaClass; + this.boxedJavaClass = boxedJavaClass; + assert primitiveJavaClass == null || javaName.equals(primitiveJavaClass.getName()); + } + + /** + * Returns the number of stack slots occupied by this kind according to the Java bytecodes + * specification. + */ + public int getSlotCount() { + return this.slotCount; + } + + /** + * Returns whether this kind occupied two stack slots. + */ + public boolean needsTwoSlots() { + return this.slotCount == 2; + } + + /** + * Returns the name of the kind as a single character. + */ + public char getTypeChar() { + return typeChar; + } + + /** + * Returns the name of this kind which will also be it Java programming language name if it is + * {@linkplain #isPrimitive() primitive} or {@code void}. + */ + public String getJavaName() { + return javaName; + } + + public Key getKey() { + return key; + } + + /** + * Checks whether this type is a Java primitive type. + * + * @return {@code true} if this is {@link #Boolean}, {@link #Byte}, {@link #Char}, + * {@link #Short}, {@link #Int}, {@link #Long}, {@link #Float}, {@link #Double}, or + * {@link #Void}. + */ + public boolean isPrimitive() { + return primitiveJavaClass != null; + } + + /** + * Returns the kind that represents this kind when on the Java operand stack. + * + * @return the kind used on the operand stack + */ + public JavaKind getStackKind() { + if (isStackInt) { + return Int; + } + return this; + } + + /** + * Checks whether this type is a Java primitive type representing an integer number. + * + * @return {@code true} if the stack kind is {@link #Int} or {@link #Long}. + */ + public boolean isNumericInteger() { + return isStackInt || this == JavaKind.Long; + } + + /** + * Checks whether this type is a Java primitive type representing an unsigned number. + * + * @return {@code true} if the kind is {@link #Boolean} or {@link #Char}. + */ + public boolean isUnsigned() { + return this == JavaKind.Boolean || this == JavaKind.Char; + } + + /** + * Checks whether this type is a Java primitive type representing a floating point number. + * + * @return {@code true} if this is {@link #Float} or {@link #Double}. + */ + public boolean isNumericFloat() { + return this == JavaKind.Float || this == JavaKind.Double; + } + + /** + * Checks whether this represent an Object of some sort. + * + * @return {@code true} if this is {@link #Object}. + */ + public boolean isObject() { + return this == JavaKind.Object; + } + + /** + * Returns the kind corresponding to the Java type string. + * + * @param typeString the Java type string + * @return the kind + */ + public static JavaKind fromTypeString(String typeString) { + assert typeString.length() > 0; + final char first = typeString.charAt(0); + if (first == '[' || first == 'L') { + return JavaKind.Object; + } + return JavaKind.fromPrimitiveOrVoidTypeChar(first); + } + + /** + * Returns the kind of a word given the size of a word in bytes. + * + * @param wordSizeInBytes the size of a word in bytes + * @return the kind representing a word value + */ + public static JavaKind fromWordSize(int wordSizeInBytes) { + if (wordSizeInBytes == 8) { + return JavaKind.Long; + } else { + assert wordSizeInBytes == 4 : "Unsupported word size!"; + return JavaKind.Int; + } + } + + /** + * Returns the kind from the character describing a primitive or void. + * + * @param ch the character + * @return the kind + */ + public static JavaKind fromPrimitiveOrVoidTypeChar(char ch) { + switch (ch) { + case 'Z': + return Boolean; + case 'C': + return Char; + case 'F': + return Float; + case 'D': + return Double; + case 'B': + return Byte; + case 'S': + return Short; + case 'I': + return Int; + case 'J': + return Long; + case 'V': + return Void; + } + throw new IllegalArgumentException("unknown primitive or void type character: " + ch); + } + + /** + * Returns the Kind representing the given Java class. + * + * @param klass the class + * @return the kind + */ + public static JavaKind fromJavaClass(Class klass) { + if (klass == Boolean.primitiveJavaClass) { + return Boolean; + } else if (klass == Byte.primitiveJavaClass) { + return Byte; + } else if (klass == Short.primitiveJavaClass) { + return Short; + } else if (klass == Char.primitiveJavaClass) { + return Char; + } else if (klass == Int.primitiveJavaClass) { + return Int; + } else if (klass == Long.primitiveJavaClass) { + return Long; + } else if (klass == Float.primitiveJavaClass) { + return Float; + } else if (klass == Double.primitiveJavaClass) { + return Double; + } else if (klass == Void.primitiveJavaClass) { + return Void; + } else { + return Object; + } + } + + /** + * Returns the Java class representing this kind. + * + * @return the Java class + */ + public Class toJavaClass() { + return primitiveJavaClass; + } + + /** + * Returns the Java class for instances of boxed values of this kind. + * + * @return the Java class + */ + public Class toBoxedJavaClass() { + return boxedJavaClass; + } + + /** + * Converts this value type to a string. + */ + @Override + public String toString() { + return javaName; + } + + /** + * Marker interface for types that should be {@linkplain JavaKind#format(Object) formatted} with + * their {@link Object#toString()} value. Calling {@link Object#toString()} on other objects + * poses a security risk because it can potentially call user code. + */ + public interface FormatWithToString { + } + + /** + * Classes for which invoking {@link Object#toString()} does not run user code. + */ + private static boolean isToStringSafe(Class c) { + return c == Boolean.class || c == Byte.class || c == Character.class || c == Short.class || c == Integer.class || c == Float.class || c == Long.class || c == Double.class; + } + + /** + * Gets a formatted string for a given value of this kind. + * + * @param value a value of this kind + * @return a formatted string for {@code value} based on this kind + */ + public String format(Object value) { + if (isPrimitive()) { + assert isToStringSafe(value.getClass()); + return value.toString(); + } else { + if (value == null) { + return "null"; + } else { + if (value instanceof String) { + String s = (String) value; + if (s.length() > 50) { + return "String:\"" + s.substring(0, 30) + "...\""; + } else { + return "String:\"" + s + '"'; + } + } else if (value instanceof JavaType) { + return "JavaType:" + ((JavaType) value).toJavaName(); + } else if (value instanceof Enum) { + return MetaUtil.getSimpleName(value.getClass(), true) + ":" + ((Enum) value).name(); + } else if (value instanceof FormatWithToString) { + return MetaUtil.getSimpleName(value.getClass(), true) + ":" + String.valueOf(value); + } else if (value instanceof Class) { + return "Class:" + ((Class) value).getName(); + } else if (isToStringSafe(value.getClass())) { + return value.toString(); + } else if (value.getClass().isArray()) { + return formatArray(value); + } else { + return MetaUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value); + } + } + } + } + + private static final int MAX_FORMAT_ARRAY_LENGTH = 5; + + private static String formatArray(Object array) { + Class componentType = array.getClass().getComponentType(); + assert componentType != null; + int arrayLength = Array.getLength(array); + StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{"); + int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength); + boolean primitive = componentType.isPrimitive(); + for (int i = 0; i < length; i++) { + if (primitive) { + buf.append(Array.get(array, i)); + } else { + Object o = ((Object[]) array)[i]; + buf.append(JavaKind.Object.format(o)); + } + if (i != length - 1) { + buf.append(", "); + } + } + if (arrayLength != length) { + buf.append(", ..."); + } + return buf.append('}').toString(); + } + + /** + * The minimum value that can be represented as a value of this kind. + * + * @return the minimum value + */ + public long getMinValue() { + switch (this) { + case Boolean: + return 0; + case Byte: + return java.lang.Byte.MIN_VALUE; + case Char: + return java.lang.Character.MIN_VALUE; + case Short: + return java.lang.Short.MIN_VALUE; + case Int: + return java.lang.Integer.MIN_VALUE; + case Long: + return java.lang.Long.MIN_VALUE; + default: + throw new IllegalArgumentException("illegal call to minValue on " + this); + } + } + + /** + * The maximum value that can be represented as a value of this kind. + * + * @return the maximum value + */ + public long getMaxValue() { + switch (this) { + case Boolean: + return 1; + case Byte: + return java.lang.Byte.MAX_VALUE; + case Char: + return java.lang.Character.MAX_VALUE; + case Short: + return java.lang.Short.MAX_VALUE; + case Int: + return java.lang.Integer.MAX_VALUE; + case Long: + return java.lang.Long.MAX_VALUE; + default: + throw new IllegalArgumentException("illegal call to maxValue on " + this); + } + } + + /** + * Number of bytes that are necessary to represent a value of this kind. + * + * @return the number of bytes + */ + public int getByteCount() { + if (this == Boolean) { + return 1; + } else { + return getBitCount() >> 3; + } + } + + /** + * Number of bits that are necessary to represent a value of this kind. + * + * @return the number of bits + */ + public int getBitCount() { + switch (this) { + case Boolean: + return 1; + case Byte: + return 8; + case Char: + case Short: + return 16; + case Float: + return 32; + case Int: + return 32; + case Double: + return 64; + case Long: + return 64; + default: + throw new IllegalArgumentException("illegal call to bits on " + this); + } + } + + public JavaConstant getDefaultValue() { + switch (this) { + case Boolean: + return JavaConstant.FALSE; + case Int: + return JavaConstant.INT_0; + case Long: + return JavaConstant.LONG_0; + case Float: + return JavaConstant.FLOAT_0; + case Double: + return JavaConstant.DOUBLE_0; + case Object: + return JavaConstant.NULL_POINTER; + case Byte: + case Char: + case Short: + return new PrimitiveConstant(this, 0); + default: + throw new IllegalArgumentException("illegal call to getDefaultValue on " + this); + } + } + + @Override + public int getSizeInBytes() { + return getByteCount(); + } + + @Override + public int getVectorLength() { + return 1; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethod.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +/** + * Represents a reference to a Java method, either resolved or unresolved. Methods, like fields and + * types, are resolved through {@link ConstantPool constant pools}. + */ +public interface JavaMethod extends TrustedInterface { + + /** + * Returns the name of this method. + */ + String getName(); + + /** + * Returns the {@link JavaType} object representing the class or interface that declares this + * method. + */ + JavaType getDeclaringClass(); + + /** + * Returns the signature of this method. + */ + Signature getSignature(); + + /** + * Gets a string for this method formatted according to a given format specification. A format + * specification is composed of characters that are to be copied verbatim to the result and + * specifiers that denote an attribute of this method that is to be copied to the result. A + * specifier is a single character preceded by a '%' character. The accepted specifiers and the + * method attributes they denote are described below: + * + *
+     *     Specifier | Description                                          | Example(s)
+     *     ----------+------------------------------------------------------------------------------------------
+     *     'R'       | Qualified return type                                | "int" "java.lang.String"
+     *     'r'       | Unqualified return type                              | "int" "String"
+     *     'H'       | Qualified holder                                     | "java.util.Map.Entry"
+     *     'h'       | Unqualified holder                                   | "Entry"
+     *     'n'       | Method name                                          | "add"
+     *     'P'       | Qualified parameter types, separated by ', '         | "int, java.lang.String"
+     *     'p'       | Unqualified parameter types, separated by ', '       | "int, String"
+     *     'f'       | Indicator if method is unresolved, static or virtual | "unresolved" "static" "virtual"
+     *     '%'       | A '%' character                                      | "%"
+     * 
+ * + * @param format a format specification + * @return the result of formatting this method according to {@code format} + * @throws IllegalFormatException if an illegal specifier is encountered in {@code format} + */ + @SuppressWarnings("fallthrough") + default String format(String format) throws IllegalFormatException { + StringBuilder sb = new StringBuilder(); + int index = 0; + Signature sig = null; + while (index < format.length()) { + char ch = format.charAt(index++); + if (ch == '%') { + if (index >= format.length()) { + throw new UnknownFormatConversionException("An unquoted '%' character cannot terminate a method format specification"); + } + char specifier = format.charAt(index++); + switch (specifier) { + case 'R': + case 'r': { + if (sig == null) { + sig = getSignature(); + } + sb.append(sig.getReturnType(null).toJavaName(specifier == 'R')); + break; + } + case 'H': + case 'h': { + sb.append(getDeclaringClass().toJavaName(specifier == 'H')); + break; + } + case 'n': { + sb.append(getName()); + break; + } + case 'P': + case 'p': { + if (sig == null) { + sig = getSignature(); + } + for (int i = 0; i < sig.getParameterCount(false); i++) { + if (i != 0) { + sb.append(", "); + } + sb.append(sig.getParameterType(i, null).toJavaName(specifier == 'P')); + } + break; + } + case 'f': { + sb.append(!(this instanceof ResolvedJavaMethod) ? "unresolved" : ((ResolvedJavaMethod) this).isStatic() ? "static" : "virtual"); + break; + } + case '%': { + sb.append('%'); + break; + } + default: { + throw new UnknownFormatConversionException(String.valueOf(specifier)); + } + } + } else { + sb.append(ch); + } + } + return sb.toString(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethodProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethodProfile.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import jdk.vm.ci.meta.JavaMethodProfile.*; + +/** + * This profile object represents the method profile at a specific BCI. The precision of the + * supplied values may vary, but a runtime that provides this information should be aware that it + * will be used to guide performance-critical decisions like speculative inlining, etc. + */ +public final class JavaMethodProfile extends AbstractJavaProfile { + + public JavaMethodProfile(double notRecordedProbability, ProfiledMethod[] pitems) { + super(notRecordedProbability, pitems); + } + + public ProfiledMethod[] getMethods() { + return super.getItems(); + } + + public static class ProfiledMethod extends AbstractProfiledItem { + + public ProfiledMethod(ResolvedJavaMethod method, double probability) { + super(method, probability); + } + + /** + * Returns the type for this profile entry. + */ + public ResolvedJavaMethod getMethod() { + return getItem(); + } + + @Override + public String toString() { + return "{" + item.getName() + ", " + probability + "}"; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import static jdk.vm.ci.meta.MetaUtil.*; + +/** + * Represents a resolved or unresolved type. Types include primitives, objects, {@code void}, and + * arrays thereof. + */ +public interface JavaType extends TrustedInterface { + + /** + * Returns the name of this type in internal form. The following are examples of strings + * returned by this method: + * + *
+     *     "Ljava/lang/Object;"
+     *     "I"
+     *     "[[B"
+     * 
+ */ + String getName(); + + /** + * Returns an unqualified name of this type. + * + *
+     *     "Object"
+     *     "Integer"
+     * 
+ */ + default String getUnqualifiedName() { + String name = getName(); + if (name.indexOf('/') != -1) { + name = name.substring(name.lastIndexOf('/') + 1); + } + if (name.endsWith(";")) { + name = name.substring(0, name.length() - 1); + } + return name; + } + + /** + * For array types, gets the type of the components, or {@code null} if this is not an array + * type. This method is analogous to {@link Class#getComponentType()}. + */ + JavaType getComponentType(); + + /** + * Gets the elemental type for this given type. The elemental type is the corresponding zero + * dimensional type of an array type. For example, the elemental type of {@code int[][][]} is + * {@code int}. A non-array type is its own elemental type. + */ + default JavaType getElementalType() { + JavaType t = this; + while (t.getComponentType() != null) { + t = t.getComponentType(); + } + return t; + } + + /** + * Gets the array class type representing an array with elements of this type. + */ + JavaType getArrayClass(); + + /** + * Gets the {@link JavaKind} of this type. + */ + JavaKind getJavaKind(); + + /** + * Resolves this type to a {@link ResolvedJavaType}. + * + * @param accessingClass the context of resolution (must not be null) + * @return the resolved Java type + * @throws LinkageError if the resolution failed + * @throws NullPointerException if {@code accessingClass} is {@code null} + */ + ResolvedJavaType resolve(ResolvedJavaType accessingClass); + + /** + * Gets the Java programming language name for this type. The following are examples of strings + * returned by this method: + * + *
+     *      java.lang.Object
+     *      int
+     *      boolean[][]
+     * 
+ * + * @return the Java name corresponding to this type + */ + default String toJavaName() { + return internalNameToJava(getName(), true, false); + } + + /** + * Gets the Java programming language name for this type. The following are examples of strings + * returned by this method: + * + *
+     *     qualified == true:
+     *         java.lang.Object
+     *         int
+     *         boolean[][]
+     *     qualified == false:
+     *         Object
+     *         int
+     *         boolean[][]
+     * 
+ * + * @param qualified specifies if the package prefix of this type should be included in the + * returned name + * @return the Java name corresponding to this type + */ + default String toJavaName(boolean qualified) { + JavaKind kind = getJavaKind(); + if (kind == JavaKind.Object) { + return internalNameToJava(getName(), qualified, false); + } + return getJavaKind().getJavaName(); + } + + /** + * Returns this type's name in the same format as {@link Class#getName()}. + */ + default String toClassName() { + return internalNameToJava(getName(), true, true); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +import jdk.vm.ci.meta.JavaTypeProfile.*; + +/** + * This profile object represents the type profile at a specific BCI. The precision of the supplied + * values may vary, but a runtime that provides this information should be aware that it will be + * used to guide performance-critical decisions like speculative inlining, etc. + */ +public final class JavaTypeProfile extends AbstractJavaProfile { + + private static final ProfiledType[] EMPTY_ARRAY = new ProfiledType[0]; + + private final TriState nullSeen; + + public JavaTypeProfile(TriState nullSeen, double notRecordedProbability, ProfiledType[] pitems) { + super(notRecordedProbability, pitems); + this.nullSeen = nullSeen; + } + + /** + * Returns whether a null value was at the type check. + */ + public TriState getNullSeen() { + return nullSeen; + } + + /** + * A list of types for which the runtime has recorded probability information. Note that this + * includes both positive and negative types where a positive type is a subtype of the checked + * type and a negative type is not. + */ + public ProfiledType[] getTypes() { + return getItems(); + } + + public JavaTypeProfile restrict(JavaTypeProfile otherProfile) { + if (otherProfile.getNotRecordedProbability() > 0.0) { + // Not useful for restricting since there is an unknown set of types occurring. + return this; + } + + if (this.getNotRecordedProbability() > 0.0) { + // We are unrestricted, so the other profile is always a better estimate. + return otherProfile; + } + + ArrayList result = new ArrayList<>(); + for (int i = 0; i < getItems().length; i++) { + ProfiledType ptype = getItems()[i]; + ResolvedJavaType type = ptype.getItem(); + if (otherProfile.isIncluded(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (otherProfile.getNullSeen() == TriState.FALSE) ? TriState.FALSE : getNullSeen(); + double newNotRecorded = getNotRecordedProbability(); + return createAdjustedProfile(result, newNullSeen, newNotRecorded); + } + + public JavaTypeProfile restrict(ResolvedJavaType declaredType, boolean nonNull) { + ArrayList result = new ArrayList<>(); + for (int i = 0; i < getItems().length; i++) { + ProfiledType ptype = getItems()[i]; + ResolvedJavaType type = ptype.getItem(); + if (declaredType.isAssignableFrom(type)) { + result.add(ptype); + } + } + + TriState newNullSeen = (nonNull) ? TriState.FALSE : getNullSeen(); + double newNotRecorded = this.getNotRecordedProbability(); + // Assume for the types not recorded, the incompatibility rate is the same. + if (getItems().length != 0) { + newNotRecorded *= ((double) result.size() / (double) getItems().length); + } + return createAdjustedProfile(result, newNullSeen, newNotRecorded); + } + + private JavaTypeProfile createAdjustedProfile(ArrayList result, TriState newNullSeen, double newNotRecorded) { + if (result.size() != this.getItems().length || newNotRecorded != getNotRecordedProbability() || newNullSeen != getNullSeen()) { + if (result.size() == 0) { + return new JavaTypeProfile(newNullSeen, 1.0, EMPTY_ARRAY); + } + double factor; + if (result.size() == this.getItems().length) { + /* List of types did not change, no need to recompute probabilities. */ + factor = 1.0; + } else { + double probabilitySum = 0.0; + for (int i = 0; i < result.size(); i++) { + probabilitySum += result.get(i).getProbability(); + } + probabilitySum += newNotRecorded; + + factor = 1.0 / probabilitySum; // Normalize to 1.0 + assert factor >= 1.0; + } + ProfiledType[] newResult = new ProfiledType[result.size()]; + for (int i = 0; i < newResult.length; ++i) { + ProfiledType curType = result.get(i); + newResult[i] = new ProfiledType(curType.getItem(), Math.min(1.0, curType.getProbability() * factor)); + } + double newNotRecordedTypeProbability = Math.min(1.0, newNotRecorded * factor); + return new JavaTypeProfile(newNullSeen, newNotRecordedTypeProbability, newResult); + } + return this; + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && nullSeen.equals(((JavaTypeProfile) other).nullSeen); + } + + @Override + public int hashCode() { + return nullSeen.hashCode() + super.hashCode(); + } + + public static class ProfiledType extends AbstractProfiledItem { + + public ProfiledType(ResolvedJavaType type, double probability) { + super(type, probability); + assert type.isArray() || type.isConcrete() : type; + } + + /** + * Returns the type for this profile entry. + */ + public ResolvedJavaType getType() { + return getItem(); + } + + @Override + public String toString() { + return String.format("%.6f#%s", probability, item); + } + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder("JavaTypeProfile", getNotRecordedProbability())).toString(); + } + + /** + * Returns {@code true} if all types seen at this location have been recorded in the profile. + */ + public boolean allTypesRecorded() { + return this.getNotRecordedProbability() == 0.0; + } + + /** + * Returns the single monormorphic type representing this profile or {@code null} if no such + * type exists. + */ + public ResolvedJavaType asSingleType() { + if (allTypesRecorded() && this.getTypes().length == 1) { + return getTypes()[0].getType(); + } + return null; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Marker interface for things that represent a Java value. + */ +public interface JavaValue { +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LIRKind.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LIRKind.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.util.*; + +/** + * Represents the type of values in the LIR. It is composed of a {@link PlatformKind} that gives the + * low level representation of the value, and a {@link #referenceMask} that describes the location + * of object references in the value, and optionally a {@link #derivedReferenceBase}. + * + *

Constructing {@link LIRKind} instances

+ * + * During LIR generation, every new {@link Value} should get a {@link LIRKind} of the correct + * {@link PlatformKind} that also contains the correct reference information. {@linkplain LIRKind + * LIRKinds} should be created as follows: + * + *

+ * If the result value is created from one or more input values, the {@link LIRKind} should be + * created with {@link LIRKind#combine}(inputs). If the result has a different {@link PlatformKind} + * than the inputs, {@link LIRKind#combine}(inputs).{@link #changeType}(resultKind) should be used. + *

+ * If the result is an exact copy of one of the inputs, {@link Value#getLIRKind()} can be used. Note + * that this is only correct for move-like operations, like conditional move or compare-and-swap. + * For convert operations, {@link LIRKind#combine} should be used. + *

+ * If it is known that the result will be a reference (e.g. pointer arithmetic where the end result + * is a valid oop), {@link LIRKind#reference} should be used. + *

+ * If it is known that the result will neither be a reference nor be derived from a reference, + * {@link LIRKind#value} can be used. If the operation producing this value has inputs, this is very + * likely wrong, and {@link LIRKind#combine} should be used instead. + *

+ * If it is known that the result is derived from a reference in a way that the garbage collector + * can not track, {@link LIRKind#unknownReference} can be used. In most cases, + * {@link LIRKind#combine} should be used instead, since it is able to detect this automatically. + */ +public final class LIRKind { + + /** + * The non-type. This uses {@link #unknownReference}, so it can never be part of an oop map. + */ + public static final LIRKind Illegal = unknownReference(JavaKind.Illegal); + + private final PlatformKind platformKind; + private final int referenceMask; + + private AllocatableValue derivedReferenceBase; + + private static final int UNKNOWN_REFERENCE = -1; + + private LIRKind(PlatformKind platformKind, int referenceMask, AllocatableValue derivedReferenceBase) { + assert platformKind != JavaKind.Object : "Kind.Object shouldn't be used in the backend"; + this.platformKind = platformKind; + this.referenceMask = referenceMask; + this.derivedReferenceBase = derivedReferenceBase; + + assert derivedReferenceBase == null || !derivedReferenceBase.getLIRKind().isDerivedReference() : "derived reference can't have another derived reference as base"; + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a primitive value. Should + * be only used when it's guaranteed that the value is not even indirectly derived from a + * reference. Otherwise, {@link #combine(Value...)} should be used instead. + */ + public static LIRKind value(PlatformKind platformKind) { + return new LIRKind(platformKind, 0, null); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a single tracked oop + * reference. + */ + public static LIRKind reference(PlatformKind platformKind) { + return derivedReference(platformKind, null); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a derived reference. + */ + public static LIRKind derivedReference(PlatformKind platformKind, AllocatableValue base) { + int length = platformKind.getVectorLength(); + assert 0 < length && length < 32 : "vector of " + length + " references not supported"; + return new LIRKind(platformKind, (1 << length) - 1, base); + } + + /** + * Create a {@link LIRKind} of type {@code platformKind} that contains a value that is derived + * from a reference in a non-linear way. Values of this {@link LIRKind} can not be live at + * safepoints. In most cases, this should not be called directly. {@link #combine} should be + * used instead to automatically propagate this information. + */ + public static LIRKind unknownReference(PlatformKind platformKind) { + return new LIRKind(platformKind, UNKNOWN_REFERENCE, null); + } + + /** + * Create a derived reference. + * + * @param base An {@link AllocatableValue} containing the base pointer of the derived reference. + */ + public LIRKind makeDerivedReference(AllocatableValue base) { + assert !isUnknownReference() && derivedReferenceBase == null; + if (Value.ILLEGAL.equals(base)) { + return makeUnknownReference(); + } else { + if (isValue()) { + return derivedReference(platformKind, base); + } else { + return new LIRKind(platformKind, referenceMask, base); + } + } + } + + /** + * Derive a new type from inputs. The result will have the {@link PlatformKind} of one of the + * inputs. If all inputs are values, the result is a value. Otherwise, the result is an unknown + * reference. + * + * This method should be used to construct the result {@link LIRKind} of any operation that + * modifies values (e.g. arithmetics). + */ + public static LIRKind combine(Value... inputs) { + assert inputs.length > 0; + for (Value input : inputs) { + LIRKind kind = input.getLIRKind(); + if (kind.isUnknownReference()) { + return kind; + } else if (!kind.isValue()) { + return kind.makeUnknownReference(); + } + } + + // all inputs are values, just return one of them + return inputs[0].getLIRKind(); + } + + /** + * Merge the types of the inputs. The result will have the {@link PlatformKind} of one of the + * inputs. If all inputs are values (references), the result is a value (reference). Otherwise, + * the result is an unknown reference. + * + * This method should be used to construct the result {@link LIRKind} of merge operation that + * does not modify values (e.g. phis). + */ + public static LIRKind merge(Value... inputs) { + assert inputs.length > 0; + ArrayList kinds = new ArrayList<>(inputs.length); + for (int i = 0; i < inputs.length; i++) { + kinds.add(inputs[i].getLIRKind()); + } + return merge(kinds); + } + + /** + * Helper method to construct derived reference kinds. Returns the base value of a reference or + * derived reference. For values it returns {@code null}, and for unknown references it returns + * {@link Value#ILLEGAL}. + */ + public static AllocatableValue derivedBaseFromValue(AllocatableValue value) { + LIRKind kind = value.getLIRKind(); + if (kind.isValue()) { + return null; + } else if (kind.isDerivedReference()) { + return kind.getDerivedReferenceBase(); + } else if (kind.isUnknownReference()) { + return Value.ILLEGAL; + } else { + // kind is a reference + return value; + } + } + + /** + * Helper method to construct derived reference kinds. If one of {@code base1} or {@code base2} + * are set, it creates a derived reference using it as the base. If both are set, the result is + * an unknown reference. + */ + public static LIRKind combineDerived(LIRKind kind, AllocatableValue base1, AllocatableValue base2) { + if (base1 == null && base2 == null) { + return kind; + } else if (base1 == null) { + return kind.makeDerivedReference(base2); + } else if (base2 == null) { + return kind.makeDerivedReference(base1); + } else { + return kind.makeUnknownReference(); + } + } + + /** + * @see #merge(Value...) + */ + public static LIRKind merge(Iterable kinds) { + LIRKind mergeKind = null; + + for (LIRKind kind : kinds) { + + if (kind.isUnknownReference()) { + /** + * Kind is an unknown reference, therefore the result can only be also an unknown + * reference. + */ + mergeKind = kind; + break; + } + if (mergeKind == null) { + mergeKind = kind; + continue; + } + + if (kind.isValue()) { + /* Kind is a value. */ + if (mergeKind.referenceMask != 0) { + /* + * Inputs consists of values and references. Make the result an unknown + * reference. + */ + mergeKind = mergeKind.makeUnknownReference(); + break; + } + /* Check that other inputs are also values. */ + } else { + /* Kind is a reference. */ + if (mergeKind.referenceMask != kind.referenceMask) { + /* + * Reference maps do not match so the result can only be an unknown reference. + */ + mergeKind = mergeKind.makeUnknownReference(); + break; + } + } + + } + assert mergeKind != null && verifyMerge(mergeKind, kinds); + + // all inputs are values or references, just return one of them + return mergeKind; + } + + private static boolean verifyMerge(LIRKind mergeKind, Iterable kinds) { + for (LIRKind kind : kinds) { + assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind); + } + return true; + } + + /** + * Create a new {@link LIRKind} with the same reference information and a new + * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this, + * the new elements are marked as untracked values. + */ + public LIRKind changeType(PlatformKind newPlatformKind) { + if (newPlatformKind == platformKind) { + return this; + } else if (isUnknownReference()) { + return unknownReference(newPlatformKind); + } else if (referenceMask == 0) { + // value type + return LIRKind.value(newPlatformKind); + } else { + // reference type + int newLength = Math.min(32, newPlatformKind.getVectorLength()); + int newReferenceMask = referenceMask & (0xFFFFFFFF >>> (32 - newLength)); + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); + } + } + + /** + * Create a new {@link LIRKind} with a new {@linkplain #getPlatformKind platform kind}. If the + * new kind is longer than this, the reference positions are repeated to fill the vector. + */ + public LIRKind repeat(PlatformKind newPlatformKind) { + if (isUnknownReference()) { + return unknownReference(newPlatformKind); + } else if (referenceMask == 0) { + // value type + return LIRKind.value(newPlatformKind); + } else { + // reference type + int oldLength = platformKind.getVectorLength(); + int newLength = newPlatformKind.getVectorLength(); + assert oldLength <= newLength && newLength < 32 && (newLength % oldLength) == 0; + + // repeat reference mask to fill new kind + int newReferenceMask = 0; + for (int i = 0; i < newLength; i += platformKind.getVectorLength()) { + newReferenceMask |= referenceMask << i; + } + + assert newReferenceMask != UNKNOWN_REFERENCE; + return new LIRKind(newPlatformKind, newReferenceMask, derivedReferenceBase); + } + } + + /** + * Create a new {@link LIRKind} with the same type, but marked as containing an + * {@link LIRKind#unknownReference}. + */ + public LIRKind makeUnknownReference() { + return new LIRKind(platformKind, UNKNOWN_REFERENCE, null); + } + + /** + * Get the low level type that is used in code generation. + */ + public PlatformKind getPlatformKind() { + return platformKind; + } + + /** + * Check whether this value is a derived reference. + */ + public boolean isDerivedReference() { + return getDerivedReferenceBase() != null; + } + + /** + * Get the base value of a derived reference. + */ + public AllocatableValue getDerivedReferenceBase() { + return derivedReferenceBase; + } + + /** + * Change the base value of a derived reference. This must be called on derived references only. + */ + public void setDerivedReferenceBase(AllocatableValue derivedReferenceBase) { + assert isDerivedReference(); + this.derivedReferenceBase = derivedReferenceBase; + } + + /** + * Check whether this value is derived from a reference in a non-linear way. If this returns + * {@code true}, this value must not be live at safepoints. + */ + public boolean isUnknownReference() { + return referenceMask == UNKNOWN_REFERENCE; + } + + public int getReferenceCount() { + assert !isUnknownReference(); + return Integer.bitCount(referenceMask); + } + + /** + * Check whether the {@code idx}th part of this value is a reference that must be tracked at + * safepoints. + * + * @param idx The index into the vector if this is a vector kind. Must be 0 if this is a scalar + * kind. + */ + public boolean isReference(int idx) { + assert 0 <= idx && idx < platformKind.getVectorLength() : "invalid index " + idx + " in " + this; + return !isUnknownReference() && (referenceMask & 1 << idx) != 0; + } + + /** + * Check whether this kind is a value type that doesn't need to be tracked at safepoints. + */ + public boolean isValue() { + return referenceMask == 0; + } + + @Override + public String toString() { + if (isValue()) { + return platformKind.name(); + } else if (isUnknownReference()) { + return platformKind.name() + "[*]"; + } else { + StringBuilder ret = new StringBuilder(); + ret.append(platformKind.name()); + ret.append('['); + for (int i = 0; i < platformKind.getVectorLength(); i++) { + if (isReference(i)) { + ret.append('.'); + } else { + ret.append(' '); + } + } + ret.append(']'); + return ret.toString(); + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((platformKind == null) ? 0 : platformKind.hashCode()); + result = prime * result + referenceMask; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof LIRKind)) { + return false; + } + + LIRKind other = (LIRKind) obj; + return platformKind == other.platformKind && referenceMask == other.referenceMask; + } + + public static boolean verifyMoveKinds(LIRKind dst, LIRKind src) { + if (src.equals(dst)) { + return true; + } + /* + * TODO(je,rs) What we actually want is toStackKind(src.getPlatformKind()).equals( + * dst.getPlatformKind()) but due to the handling of sub-integer at the current point + * (phi-)moves from e.g. integer to short can happen. Therefore we compare stack kinds. + */ + if (toStackKind(src.getPlatformKind()).equals(toStackKind(dst.getPlatformKind()))) { + return !src.isUnknownReference() || dst.isUnknownReference(); + } + return false; + } + + private static PlatformKind toStackKind(PlatformKind platformKind) { + if (platformKind instanceof JavaKind) { + return ((JavaKind) platformKind).getStackKind(); + } + return platformKind; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTable.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public interface LineNumberTable { + + int[] getLineNumberEntries(); + + int[] getBciEntries(); + + int getLineNumber(int bci); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTableImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTableImpl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public class LineNumberTableImpl implements LineNumberTable { + + private final int[] lineNumbers; + private final int[] bci; + + public LineNumberTableImpl(int[] lineNumbers, int[] bci) { + this.lineNumbers = lineNumbers; + this.bci = bci; + } + + @Override + public int[] getLineNumberEntries() { + return lineNumbers; + } + + @Override + public int[] getBciEntries() { + return bci; + } + + @Override + public int getLineNumber(@SuppressWarnings("hiding") int bci) { + for (int i = 0; i < this.bci.length - 1; i++) { + if (this.bci[i] <= bci && bci < this.bci[i + 1]) { + return lineNumbers[i]; + } + } + return lineNumbers[lineNumbers.length - 1]; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Local.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Local.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public interface Local { + + int getStartBCI(); + + int getEndBCI(); + + int getSlot(); + + String getName(); + + JavaType getType(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalImpl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public class LocalImpl implements Local { + + private final String name; + private final int startBci; + private final int endBci; + private final int slot; + private final JavaType type; + + public LocalImpl(String name, JavaType type, int startBci, int endBci, int slot) { + this.name = name; + this.startBci = startBci; + this.endBci = endBci; + this.slot = slot; + this.type = type; + } + + @Override + public int getStartBCI() { + return startBci; + } + + @Override + public int getEndBCI() { + return endBci; + } + + @Override + public String getName() { + return name; + } + + @Override + public JavaType getType() { + return type; + } + + @Override + public int getSlot() { + return slot; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof LocalImpl)) { + return false; + } + LocalImpl that = (LocalImpl) obj; + return this.name.equals(that.name) && this.startBci == that.startBci && this.endBci == that.endBci && this.slot == that.slot && this.type.equals(that.type); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public String toString() { + return "LocalImpl"; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTable.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +public interface LocalVariableTable { + + Local[] getLocals(); + + Local[] getLocalsAt(int bci); + + Local getLocal(int slot, int bci); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTableImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTableImpl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +public class LocalVariableTableImpl implements LocalVariableTable { + + private final Local[] locals; + + public LocalVariableTableImpl(Local[] locals) { + this.locals = locals; + } + + @Override + public Local getLocal(int slot, int bci) { + Local result = null; + for (Local local : locals) { + if (local.getSlot() == slot && local.getStartBCI() <= bci && local.getEndBCI() >= bci) { + if (result == null) { + result = local; + } else { + throw new IllegalStateException("Locals overlap!"); + } + } + } + return result; + } + + @Override + public Local[] getLocals() { + return locals; + } + + @Override + public Local[] getLocalsAt(int bci) { + List result = new ArrayList<>(); + for (Local l : locals) { + if (l.getStartBCI() <= bci && bci <= l.getEndBCI()) { + result.add(l); + } + } + return result.toArray(new Local[result.size()]); + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocationIdentity.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocationIdentity.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +import java.util.*; + +// JaCoCo Exclude + +/** + * Marker interface for location identities. A different location identity of two memory accesses + * guarantees that the two accesses do not interfere. + * + * Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when + * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use + * {@link IdentityHashMap}s with {@link LocationIdentity} values as keys. + */ +public abstract class LocationIdentity { + + private static final class AnyLocationIdentity extends LocationIdentity { + @Override + public boolean isImmutable() { + return false; + } + + @Override + public String toString() { + return "ANY_LOCATION"; + } + } + + public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity(); + + public static LocationIdentity any() { + return ANY_LOCATION; + } + + /** + * Denotes a location is unchanging in all cases. Not that this is different than the Java + * notion of final which only requires definite assignment. + */ + public abstract boolean isImmutable(); + + public final boolean isMutable() { + return !isImmutable(); + } + + public final boolean isAny() { + return this == ANY_LOCATION; + } + + public final boolean isSingle() { + return this != ANY_LOCATION; + } + + public final boolean overlaps(LocationIdentity other) { + return isAny() || other.isAny() || this.equals(other); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Provides memory access operations for the target VM. + */ +public interface MemoryAccessProvider { + + /** + * Reads a value of this kind using a base address and a displacement. No bounds checking or + * type checking is performed. Returns {@code null} if the value is not available at this point. + * + * @param base the base address from which the value is read. + * @param displacement the displacement within the object in bytes + * @return the read value encapsulated in a {@link JavaConstant} object, or {@code null} if the + * value cannot be read. + */ + JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant base, long displacement); + + /** + * Reads a primitive value using a base address and a displacement. + * + * @param kind the {@link JavaKind} of the returned {@link JavaConstant} object + * @param base the base address from which the value is read + * @param displacement the displacement within the object in bytes + * @param bits the number of bits to read from memory + * @return the read value encapsulated in a {@link JavaConstant} object of {@link JavaKind} kind + */ + JavaConstant readPrimitiveConstant(JavaKind kind, Constant base, long displacement, int bits); + + /** + * Reads a Java {@link Object} value using a base address and a displacement. + * + * @param base the base address from which the value is read + * @param displacement the displacement within the object in bytes + * @return the read value encapsulated in a {@link Constant} object + */ + JavaConstant readObjectConstant(Constant base, long displacement); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.lang.reflect.*; + +/** + * Provides access to the metadata of a class typically provided in a class file. + */ +public interface MetaAccessProvider { + + /** + * Returns the resolved Java type representing a given Java class. + * + * @param clazz the Java class object + * @return the resolved Java type object + */ + ResolvedJavaType lookupJavaType(Class clazz); + + /** + * Returns the resolved Java types representing some given Java classes. + * + * @param classes the Java class objects + * @return the resolved Java type objects + */ + default ResolvedJavaType[] lookupJavaTypes(Class[] classes) { + ResolvedJavaType[] result = new ResolvedJavaType[classes.length]; + for (int i = 0; i < result.length; i++) { + result[i] = lookupJavaType(classes[i]); + } + return result; + } + + /** + * Provides the {@link ResolvedJavaMethod} for a {@link Method} or {@link Constructor} obtained + * via reflection. + */ + ResolvedJavaMethod lookupJavaMethod(Executable reflectionMethod); + + /** + * Provides the {@link ResolvedJavaField} for a {@link Field} obtained via reflection. + */ + ResolvedJavaField lookupJavaField(Field reflectionField); + + /** + * Returns the resolved Java type of the given {@link JavaConstant} object. + * + * @return {@code null} if {@code constant.isNull() || !constant.kind.isObject()} + */ + ResolvedJavaType lookupJavaType(JavaConstant constant); + + /** + * Returns the number of bytes occupied by this constant value or constant object. + * + * @param constant the constant whose bytes should be measured + * @return the number of bytes occupied by this constant + */ + long getMemorySize(JavaConstant constant); + + /** + * Parses a method + * descriptor into a {@link Signature}. The behavior of this method is undefined if the + * method descriptor is not well formed. + */ + Signature parseMethodDescriptor(String methodDescriptor); + + /** + * Encodes a deoptimization action and a deoptimization reason in an integer value. + * + * @param debugId an integer that can be used to track the origin of a deoptimization at + * runtime. There is no guarantee that the runtime will use this value. The runtime + * may even keep fewer than 32 bits. + * + * @return the encoded value as an integer + */ + JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId); + + DeoptimizationReason decodeDeoptReason(JavaConstant constant); + + DeoptimizationAction decodeDeoptAction(JavaConstant constant); + + int decodeDebugId(JavaConstant constant); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +/** + * Miscellaneous collection of utility methods used by {@code jdk.vm.ci.meta} and its clients. + */ +public class MetaUtil { + + private static class ClassInfo { + public long totalSize; + public long instanceCount; + + @Override + public String toString() { + return "totalSize=" + totalSize + ", instanceCount=" + instanceCount; + } + } + + /** + * Returns the number of bytes occupied by this constant value or constant object and + * recursively all values reachable from this value. + * + * @param constant the constant whose bytes should be measured + * @param printTopN print total size and instance count of the top n classes is desired + * @return the number of bytes occupied by this constant + */ + public static long getMemorySizeRecursive(MetaAccessProvider access, ConstantReflectionProvider constantReflection, JavaConstant constant, PrintStream out, int printTopN) { + Set marked = new HashSet<>(); + Deque stack = new ArrayDeque<>(); + if (constant.getJavaKind() == JavaKind.Object && constant.isNonNull()) { + marked.add(constant); + } + final HashMap histogram = new HashMap<>(); + stack.push(constant); + long sum = 0; + while (!stack.isEmpty()) { + JavaConstant c = stack.pop(); + long memorySize = access.getMemorySize(constant); + sum += memorySize; + if (c.getJavaKind() == JavaKind.Object && c.isNonNull()) { + ResolvedJavaType clazz = access.lookupJavaType(c); + if (!histogram.containsKey(clazz)) { + histogram.put(clazz, new ClassInfo()); + } + ClassInfo info = histogram.get(clazz); + info.instanceCount++; + info.totalSize += memorySize; + ResolvedJavaType type = access.lookupJavaType(c); + if (type.isArray()) { + if (!type.getComponentType().isPrimitive()) { + int length = constantReflection.readArrayLength(c); + for (int i = 0; i < length; i++) { + JavaConstant value = constantReflection.readArrayElement(c, i); + pushConstant(marked, stack, value); + } + } + } else { + ResolvedJavaField[] instanceFields = type.getInstanceFields(true); + for (ResolvedJavaField f : instanceFields) { + if (f.getJavaKind() == JavaKind.Object) { + JavaConstant value = constantReflection.readFieldValue(f, c); + pushConstant(marked, stack, value); + } + } + } + } + } + ArrayList clazzes = new ArrayList<>(); + clazzes.addAll(histogram.keySet()); + Collections.sort(clazzes, new Comparator() { + + @Override + public int compare(ResolvedJavaType o1, ResolvedJavaType o2) { + long l1 = histogram.get(o1).totalSize; + long l2 = histogram.get(o2).totalSize; + if (l1 > l2) { + return -1; + } else if (l1 == l2) { + return 0; + } else { + return 1; + } + } + }); + + int z = 0; + for (ResolvedJavaType c : clazzes) { + if (z > printTopN) { + break; + } + out.println("Class " + c + ", " + histogram.get(c)); + ++z; + } + + return sum; + } + + private static void pushConstant(Set marked, Deque stack, JavaConstant value) { + if (value.isNonNull()) { + if (!marked.contains(value)) { + marked.add(value); + stack.push(value); + } + } + } + + /** + * Calls {@link JavaType#resolve(ResolvedJavaType)} on an array of types. + */ + public static ResolvedJavaType[] resolveJavaTypes(JavaType[] types, ResolvedJavaType accessingClass) { + ResolvedJavaType[] result = new ResolvedJavaType[types.length]; + for (int i = 0; i < result.length; i++) { + result[i] = types[i].resolve(accessingClass); + } + return result; + } + + /** + * Extends the functionality of {@link Class#getSimpleName()} to include a non-empty string for + * anonymous and local classes. + * + * @param clazz the class for which the simple name is being requested + * @param withEnclosingClass specifies if the returned name should be qualified with the name(s) + * of the enclosing class/classes of {@code clazz} (if any). This option is ignored + * if {@code clazz} denotes an anonymous or local class. + * @return the simple name + */ + public static String getSimpleName(Class clazz, boolean withEnclosingClass) { + final String simpleName = clazz.getSimpleName(); + if (simpleName.length() != 0) { + if (withEnclosingClass) { + String prefix = ""; + Class enclosingClass = clazz; + while ((enclosingClass = enclosingClass.getEnclosingClass()) != null) { + prefix = enclosingClass.getSimpleName() + "." + prefix; + } + return prefix + simpleName; + } + return simpleName; + } + // Must be an anonymous or local class + final String name = clazz.getName(); + int index = name.indexOf('$'); + if (index == -1) { + return name; + } + index = name.lastIndexOf('.', index); + if (index == -1) { + return name; + } + return name.substring(index + 1); + } + + static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) { + switch (name.charAt(0)) { + case 'L': { + String result = name.substring(1, name.length() - 1).replace('/', '.'); + if (!qualified) { + final int lastDot = result.lastIndexOf('.'); + if (lastDot != -1) { + result = result.substring(lastDot + 1); + } + } + return result; + } + case '[': + return classForNameCompatible ? name.replace('/', '.') : internalNameToJava(name.substring(1), qualified, classForNameCompatible) + "[]"; + default: + if (name.length() != 1) { + throw new IllegalArgumentException("Illegal internal name: " + name); + } + return JavaKind.fromPrimitiveOrVoidTypeChar(name.charAt(0)).getJavaName(); + } + } + + /** + * Turns an class name in internal format into a resolved Java type. + */ + public static ResolvedJavaType classForName(String internal, MetaAccessProvider metaAccess, ClassLoader cl) { + JavaKind k = JavaKind.fromTypeString(internal); + try { + String n = internalNameToJava(internal, true, true); + return metaAccess.lookupJavaType(k.isPrimitive() ? k.toJavaClass() : Class.forName(n, true, cl)); + } catch (ClassNotFoundException cnfe) { + throw new IllegalArgumentException("could not instantiate class described by " + internal, cnfe); + } + } + + /** + * Convenient shortcut for calling + * {@link #appendLocation(StringBuilder, ResolvedJavaMethod, int)} without having to supply a + * {@link StringBuilder} instance and convert the result to a string. + */ + public static String toLocation(ResolvedJavaMethod method, int bci) { + return appendLocation(new StringBuilder(), method, bci).toString(); + } + + /** + * Appends a string representation of a location specified by a given method and bci to a given + * {@link StringBuilder}. If a stack trace element with a non-null file name and non-negative + * line number is {@linkplain ResolvedJavaMethod#asStackTraceElement(int) available} for the + * given method, then the string returned is the {@link StackTraceElement#toString()} value of + * the stack trace element, suffixed by the bci location. For example: + * + *

+     *     java.lang.String.valueOf(String.java:2930) [bci: 12]
+     * 
+ * + * Otherwise, the string returned is the value of applying {@link JavaMethod#format(String)} + * with the format string {@code "%H.%n(%p)"}, suffixed by the bci location. For example: + * + *
+     *     java.lang.String.valueOf(int) [bci: 12]
+     * 
+ * + * @param sb + * @param method + * @param bci + */ + public static StringBuilder appendLocation(StringBuilder sb, ResolvedJavaMethod method, int bci) { + if (method != null) { + StackTraceElement ste = method.asStackTraceElement(bci); + if (ste.getFileName() != null && ste.getLineNumber() > 0) { + sb.append(ste); + } else { + sb.append(method.format("%H.%n(%p)")); + } + } else { + sb.append("Null method"); + } + return sb.append(" [bci: ").append(bci).append(']'); + } + + static void appendProfile(StringBuilder buf, AbstractJavaProfile profile, int bci, String type, String sep) { + if (profile != null) { + AbstractProfiledItem[] pitems = profile.getItems(); + if (pitems != null) { + buf.append(String.format("%s@%d:", type, bci)); + for (int j = 0; j < pitems.length; j++) { + AbstractProfiledItem pitem = pitems[j]; + buf.append(String.format(" %.6f (%s)%s", pitem.getProbability(), pitem.getItem(), sep)); + } + if (profile.getNotRecordedProbability() != 0) { + buf.append(String.format(" %.6f %s", profile.getNotRecordedProbability(), type, sep)); + } else { + buf.append(String.format(" %s", type, sep)); + } + } + } + } + + /** + * Converts a Java source-language class name into the internal form. + * + * @param className the class name + * @return the internal name form of the class name + */ + public static String toInternalName(String className) { + if (className.startsWith("[")) { + /* Already in the correct array style. */ + return className.replace('.', '/'); + } + + StringBuilder result = new StringBuilder(); + String base = className; + while (base.endsWith("[]")) { + result.append("["); + base = base.substring(0, base.length() - 2); + } + + switch (base) { + case "boolean": + result.append("Z"); + break; + case "byte": + result.append("B"); + break; + case "short": + result.append("S"); + break; + case "char": + result.append("C"); + break; + case "int": + result.append("I"); + break; + case "float": + result.append("F"); + break; + case "long": + result.append("J"); + break; + case "double": + result.append("D"); + break; + case "void": + result.append("V"); + break; + default: + result.append("L").append(base.replace('.', '/')).append(";"); + break; + } + return result.toString(); + } + + /** + * Prepends the String {@code indentation} to every line in String {@code lines}, including a + * possibly non-empty line following the final newline. + */ + public static String indent(String lines, String indentation) { + if (lines.length() == 0) { + return lines; + } + final String newLine = "\n"; + if (lines.endsWith(newLine)) { + return indentation + (lines.substring(0, lines.length() - 1)).replace(newLine, newLine + indentation) + newLine; + } + return indentation + lines.replace(newLine, newLine + indentation); + } + + /** + * Gets a string representation of an object based soley on its class and its + * {@linkplain System#identityHashCode(Object) identity hash code}. This avoids and calls to + * virtual methods on the object such as {@link Object#hashCode()}. + */ + public static String identityHashCodeString(Object obj) { + if (obj == null) { + return "null"; + } + return obj.getClass().getName() + "@" + System.identityHashCode(obj); + } + + /** + * Used to lookup constants from {@link Modifier} that are not public (VARARGS, SYNTHETIC etc.). + */ + static int getNonPublicModifierStaticField(String name) { + try { + Field field = Modifier.class.getDeclaredField(name); + field.setAccessible(true); + return field.getInt(null); + } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { + throw new InternalError(e); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.lang.invoke.*; + +/** + * Interface to access the internals of the {@link MethodHandle} implementation of the VM. An + * implementation of this interface is usually required to access non-public classes, methods, and + * fields of {@link MethodHandle}, i.e., data that is not standardized by the Java specification. + */ +public interface MethodHandleAccessProvider { + + /** + * Identification for methods defined on the class {@link MethodHandle} that are processed by + * the {@link MethodHandleAccessProvider}. + */ + public enum IntrinsicMethod { + /** The method {@code MethodHandle.invokeBasic}. */ + INVOKE_BASIC, + /** The method {@code MethodHandle.linkToStatic}. */ + LINK_TO_STATIC, + /** The method {@code MethodHandle.linkToSpecial}. */ + LINK_TO_SPECIAL, + /** The method {@code MethodHandle.linkToVirtual}. */ + LINK_TO_VIRTUAL, + /** The method {@code MethodHandle.linkToInterface}. */ + LINK_TO_INTERFACE + } + + /** + * Returns the method handle method intrinsic identifier for the provided method, or + * {@code null} if the method is not an intrinsic processed by this interface. + */ + IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method); + + /** + * Resolves the invocation target for an invocation of {@link IntrinsicMethod#INVOKE_BASIC + * MethodHandle.invokeBasic} with the given constant receiver {@link MethodHandle}. Returns + * {@code null} if the invocation target is not available at this time. + *

+ * The first invocations of a method handle can use an interpreter to lookup the actual invoked + * method; frequently executed method handles can use Java bytecode generation to avoid the + * interpreter overhead. If the parameter forceBytecodeGeneration is set to true, the VM should + * try to generate bytecodes before this method returns. + */ + ResolvedJavaMethod resolveInvokeBasicTarget(JavaConstant methodHandle, boolean forceBytecodeGeneration); + + /** + * Resolves the invocation target for an invocation of a {@code MethodHandle.linkTo*} method + * with the given constant member name. The member name is the last parameter of the + * {@code linkTo*} method. Returns {@code null} if the invocation target is not available at + * this time. + */ + ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ModifiersProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ModifiersProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import static java.lang.reflect.Modifier.*; + +import java.lang.reflect.*; + +/** + * A Java element (i.e., a class, interface, field or method) that is described by a set of Java + * language {@linkplain #getModifiers() modifiers}. + */ +public interface ModifiersProvider { + int BRIDGE = MetaUtil.getNonPublicModifierStaticField("BRIDGE"); + int VARARGS = MetaUtil.getNonPublicModifierStaticField("VARARGS"); + int SYNTHETIC = MetaUtil.getNonPublicModifierStaticField("SYNTHETIC"); + int ANNOTATION = MetaUtil.getNonPublicModifierStaticField("ANNOTATION"); + int ENUM = MetaUtil.getNonPublicModifierStaticField("ENUM"); + int MANDATED = MetaUtil.getNonPublicModifierStaticField("MANDATED"); + + /** + * Returns the Java Virtual Machine modifiers for this element. Note that this can differ from + * standard Java Reflection modifiers. For example at the JVM level, classes ( + * {@link ResolvedJavaType}) can not be private or protected. + */ + int getModifiers(); + + /** + * @see Modifier#isInterface(int) + */ + default boolean isInterface() { + return Modifier.isInterface(getModifiers()); + } + + /** + * @see Modifier#isSynchronized(int) + */ + default boolean isSynchronized() { + return Modifier.isSynchronized(getModifiers()); + } + + /** + * @see Modifier#isStatic(int) + */ + default boolean isStatic() { + return Modifier.isStatic(getModifiers()); + } + + /** + * The setting of the final modifier bit for types is somewhat confusing, so don't export + * isFinal by default. Subclasses like {@link ResolvedJavaField} and {@link ResolvedJavaMethod} + * can export it as isFinal, but {@link ResolvedJavaType} can provide a more sensible equivalent + * like {@link ResolvedJavaType#isLeaf}. + * + * @see Modifier#isFinal(int) + */ + default boolean isFinalFlagSet() { + return Modifier.isFinal(getModifiers()); + } + + /** + * @see Modifier#isPublic(int) + */ + default boolean isPublic() { + return Modifier.isPublic(getModifiers()); + } + + /** + * Determines if this element is neither {@linkplain #isPublic() public}, + * {@linkplain #isProtected() protected} nor {@linkplain #isPrivate() private}. + */ + default boolean isPackagePrivate() { + return ((PUBLIC | PROTECTED | PRIVATE) & getModifiers()) == 0; + } + + /** + * @see Modifier#isPrivate(int) + */ + default boolean isPrivate() { + return Modifier.isPrivate(getModifiers()); + } + + /** + * @see Modifier#isProtected(int) + */ + default boolean isProtected() { + return Modifier.isProtected(getModifiers()); + } + + /** + * @see Modifier#isTransient(int) + */ + default boolean isTransient() { + return Modifier.isTransient(getModifiers()); + } + + /** + * @see Modifier#isStrict(int) + */ + default boolean isStrict() { + return Modifier.isStrict(getModifiers()); + } + + /** + * @see Modifier#isVolatile(int) + */ + default boolean isVolatile() { + return Modifier.isVolatile(getModifiers()); + } + + /** + * @see Modifier#isNative(int) + */ + default boolean isNative() { + return Modifier.isNative(getModifiers()); + } + + /** + * @see Modifier#isAbstract(int) + */ + default boolean isAbstract() { + return Modifier.isAbstract(getModifiers()); + } + + /** + * Checks that the method is concrete and not abstract. + * + * @return whether the method is a concrete method + */ + default boolean isConcrete() { + return !isAbstract(); + } + + static int jvmClassModifiers() { + // no SUPER + return PUBLIC | FINAL | INTERFACE | ABSTRACT | ANNOTATION | ENUM | SYNTHETIC; + } + + static int jvmMethodModifiers() { + return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | SYNCHRONIZED | BRIDGE | VARARGS | NATIVE | ABSTRACT | STRICT | SYNTHETIC; + } + + static int jvmFieldModifiers() { + return PUBLIC | PRIVATE | PROTECTED | STATIC | FINAL | VOLATILE | TRANSIENT | ENUM | SYNTHETIC; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/NullConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/NullConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * The implementation type of the {@link JavaConstant#NULL_POINTER null constant}. + */ +final class NullConstant implements JavaConstant { + + protected NullConstant() { + } + + @Override + public JavaKind getJavaKind() { + return JavaKind.Object; + } + + @Override + public boolean isNull() { + return true; + } + + @Override + public boolean isDefaultForKind() { + return true; + } + + @Override + public Object asBoxedPrimitive() { + throw new IllegalArgumentException(); + } + + @Override + public int asInt() { + throw new IllegalArgumentException(); + } + + @Override + public boolean asBoolean() { + throw new IllegalArgumentException(); + } + + @Override + public long asLong() { + throw new IllegalArgumentException(); + } + + @Override + public float asFloat() { + throw new IllegalArgumentException(); + } + + @Override + public double asDouble() { + throw new IllegalArgumentException(); + } + + @Override + public String toString() { + return JavaConstant.toString(this); + } + + @Override + public String toValueString() { + return "null"; + } + + @Override + public int hashCode() { + return 13; + } + + @Override + public boolean equals(Object o) { + return o instanceof NullConstant; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PlatformKind.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PlatformKind.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Represents a platform-specific low-level type for values. + */ +public interface PlatformKind { + + String name(); + + JavaConstant getDefaultValue(); + + public interface Key { + + } + + public class EnumKey> implements Key { + private final Enum e; + + public EnumKey(Enum e) { + this.e = e; + } + + @Override + public int hashCode() { + return e.ordinal() ^ e.name().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof EnumKey) { + EnumKey that = (EnumKey) obj; + return this.e == that.e; + } + return false; + } + } + + /** + * Gets a value associated with this object that can be used as a stable key in a map. The + * {@link Object#hashCode()} implementation of the returned value should be stable between VM + * executions. + */ + Key getKey(); + + /** + * Get the size in bytes of this {@link PlatformKind}. + */ + int getSizeInBytes(); + + /** + * Returns how many primitive values fit in this {@link PlatformKind}. For scalar types this is + * one, for SIMD types it may be higher. + */ + int getVectorLength(); + + /** + * Gets a single type char that identifies this type for use in debug output. + */ + char getTypeChar(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.nio.*; + +/** + * Represents a primitive constant value, such as an integer or floating point number, within the + * compiler and across the compiler/runtime interface. + */ +public class PrimitiveConstant implements JavaConstant, SerializableConstant { + + private final JavaKind kind; + + /** + * The boxed primitive value as a {@code long}. For {@code float} and {@code double} values, + * this value is the result of {@link Float#floatToRawIntBits(float)} and + * {@link Double#doubleToRawLongBits(double)} respectively. + */ + private final long primitive; + + protected PrimitiveConstant(JavaKind kind, long primitive) { + this.primitive = primitive; + this.kind = kind; + + assert kind.isPrimitive() || kind == JavaKind.Illegal; + } + + @Override + public JavaKind getJavaKind() { + return kind; + } + + @Override + public boolean isNull() { + return false; + } + + @Override + public boolean isDefaultForKind() { + return primitive == 0; + } + + @Override + public boolean asBoolean() { + assert getJavaKind() == JavaKind.Boolean; + return primitive != 0L; + } + + @Override + public int asInt() { + assert getJavaKind().getStackKind() == JavaKind.Int : getJavaKind().getStackKind(); + return (int) primitive; + } + + @Override + public long asLong() { + assert getJavaKind().isNumericInteger(); + return primitive; + } + + @Override + public float asFloat() { + assert getJavaKind() == JavaKind.Float; + return Float.intBitsToFloat((int) primitive); + } + + @Override + public double asDouble() { + assert getJavaKind() == JavaKind.Double; + return Double.longBitsToDouble(primitive); + } + + @Override + public Object asBoxedPrimitive() { + switch (getJavaKind()) { + case Byte: + return Byte.valueOf((byte) primitive); + case Boolean: + return Boolean.valueOf(asBoolean()); + case Short: + return Short.valueOf((short) primitive); + case Char: + return Character.valueOf((char) primitive); + case Int: + return Integer.valueOf(asInt()); + case Long: + return Long.valueOf(asLong()); + case Float: + return Float.valueOf(asFloat()); + case Double: + return Double.valueOf(asDouble()); + default: + throw new IllegalArgumentException("unexpected kind " + getJavaKind()); + } + } + + @Override + public int getSerializedSize() { + return getJavaKind().getByteCount(); + } + + @Override + public void serialize(ByteBuffer buffer) { + switch (getJavaKind()) { + case Byte: + case Boolean: + buffer.put((byte) primitive); + break; + case Short: + buffer.putShort((short) primitive); + break; + case Char: + buffer.putChar((char) primitive); + break; + case Int: + buffer.putInt(asInt()); + break; + case Long: + buffer.putLong(asLong()); + break; + case Float: + buffer.putFloat(asFloat()); + break; + case Double: + buffer.putDouble(asDouble()); + break; + default: + throw new IllegalArgumentException("unexpected kind " + getJavaKind()); + } + } + + @Override + public int hashCode() { + return (int) (primitive ^ (primitive >>> 32)) * (getJavaKind().ordinal() + 31); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof PrimitiveConstant)) { + return false; + } + PrimitiveConstant other = (PrimitiveConstant) o; + return this.kind.equals(other.kind) && this.primitive == other.primitive; + } + + @Override + public String toString() { + if (getJavaKind() == JavaKind.Illegal) { + return "illegal"; + } else { + return getJavaKind().getJavaName() + "[" + asBoxedPrimitive() + "|0x" + Long.toHexString(primitive) + "]"; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.meta; + +/** + * Provides access to the profiling information of one specific method. Every accessor method + * returns the information that is available at the time of invocation. If a method is invoked + * multiple times, it may return significantly different results for every invocation as the + * profiling information may be changed by other Java threads at any time. + */ +public interface ProfilingInfo { + + /** + * Returns the length of the bytecodes associated with this profile. + */ + int getCodeSize(); + + /** + * Returns an estimate of how often the branch at the given byte code was taken. + * + * @return The estimated probability, with 0.0 meaning never and 1.0 meaning always, or -1 if + * this information is not available. + */ + double getBranchTakenProbability(int bci); + + /** + * Returns an estimate of how often the switch cases are taken at the given BCI. The default + * case is stored as the last entry. + * + * @return A double value that contains the estimated probabilities, with 0.0 meaning never and + * 1.0 meaning always, or -1 if this information is not available. + */ + double[] getSwitchProbabilities(int bci); + + /** + * Returns the TypeProfile for the given BCI. + * + * @return Returns a JavaTypeProfile object, or null if not available. + */ + JavaTypeProfile getTypeProfile(int bci); + + /** + * Returns the MethodProfile for the given BCI. + * + * @return Returns a JavaMethodProfile object, or null if not available. + */ + JavaMethodProfile getMethodProfile(int bci); + + /** + * Returns information if the given BCI did ever throw an exception. + * + * @return {@link TriState#TRUE} if the instruction has thrown an exception at least once, + * {@link TriState#FALSE} if it never threw an exception, and {@link TriState#UNKNOWN} + * if this information was not recorded. + */ + TriState getExceptionSeen(int bci); + + /** + * Returns information if null was ever seen for the given BCI. This information is collected + * for the aastore, checkcast and instanceof bytecodes. + * + * @return {@link TriState#TRUE} if null was seen for the instruction, {@link TriState#FALSE} if + * null was NOT seen, and {@link TriState#UNKNOWN} if this information was not recorded. + */ + TriState getNullSeen(int bci); + + /** + * Returns an estimate how often the current BCI was executed. Avoid comparing execution counts + * to each other, as the returned value highly depends on the time of invocation. + * + * @return the estimated execution count or -1 if not available. + */ + int getExecutionCount(int bci); + + /** + * Returns how frequently a method was deoptimized for the given deoptimization reason. This + * only indicates how often the method did fall back to the interpreter for the execution and + * does not indicate how often it was recompiled. + * + * @param reason the reason for which the number of deoptimizations should be queried + * @return the number of times the compiled method deoptimized for the given reason. + */ + int getDeoptimizationCount(DeoptimizationReason reason); + + /** + * Records the size of the compiler intermediate representation (IR) associated with this + * method. + * + * @param irType the IR type for which the size is being recorded + * @param irSize the IR size to be recorded. The unit depends on the IR. + * @return whether recording this information for {@code irType} is supported + */ + boolean setCompilerIRSize(Class irType, int irSize); + + /** + * Gets the size of the compiler intermediate representation (IR) associated with this method + * last recorded by {@link #setCompilerIRSize(Class, int)}. + * + * @param irType the IR type for which the size is being requested + * @return the requested IR size or -1 if it is unavailable for {@code irType} + */ + int getCompilerIRSize(Class irType); + + /** + * Returns true if the profiling information can be assumed as sufficiently accurate. + * + * @return true if the profiling information was recorded often enough mature enough, false + * otherwise. + */ + boolean isMature(); + + /** + * Force data to be treated as mature if possible. + */ + void setMature(); + + /** + * Formats this profiling information to a string. + * + * @param method an optional method that augments the profile string returned + * @param sep the separator to use for each separate profile record + */ + default String toString(ResolvedJavaMethod method, String sep) { + StringBuilder buf = new StringBuilder(100); + if (method != null) { + buf.append(String.format("canBeStaticallyBound: %b%s", method.canBeStaticallyBound(), sep)); + } + for (int i = 0; i < getCodeSize(); i++) { + if (getExecutionCount(i) != -1) { + buf.append(String.format("executionCount@%d: %d%s", i, getExecutionCount(i), sep)); + } + + if (getBranchTakenProbability(i) != -1) { + buf.append(String.format("branchProbability@%d: %.6f%s", i, getBranchTakenProbability(i), sep)); + } + + double[] switchProbabilities = getSwitchProbabilities(i); + if (switchProbabilities != null) { + buf.append(String.format("switchProbabilities@%d:", i)); + for (int j = 0; j < switchProbabilities.length; j++) { + buf.append(String.format(" %.6f", switchProbabilities[j])); + } + buf.append(sep); + } + + if (getExceptionSeen(i) != TriState.UNKNOWN) { + buf.append(String.format("exceptionSeen@%d: %s%s", i, getExceptionSeen(i).name(), sep)); + } + + if (getNullSeen(i) != TriState.UNKNOWN) { + buf.append(String.format("nullSeen@%d: %s%s", i, getNullSeen(i).name(), sep)); + } + + JavaTypeProfile typeProfile = getTypeProfile(i); + MetaUtil.appendProfile(buf, typeProfile, i, "types", sep); + + JavaMethodProfile methodProfile = getMethodProfile(i); + MetaUtil.appendProfile(buf, methodProfile, i, "methods", sep); + } + + boolean firstDeoptReason = true; + for (DeoptimizationReason reason : DeoptimizationReason.values()) { + int count = getDeoptimizationCount(reason); + if (count > 0) { + if (firstDeoptReason) { + buf.append("deoptimization history").append(sep); + firstDeoptReason = false; + } + buf.append(String.format(" %s: %d%s", reason.name(), count, sep)); + } + } + if (buf.length() == 0) { + return ""; + } + String s = buf.toString(); + return s.substring(0, s.length() - sep.length()); + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/RawConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/RawConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +public class RawConstant extends PrimitiveConstant { + + public RawConstant(long rawValue) { + super(JavaKind.Int, rawValue); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaField.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.lang.annotation.*; +import java.lang.reflect.*; + +/** + * Represents a reference to a resolved Java field. Fields, like methods and types, are resolved + * through {@link ConstantPool constant pools}. + */ +public interface ResolvedJavaField extends JavaField, ModifiersProvider { + + /** + * {@inheritDoc} + *

+ * Only the {@linkplain Modifier#fieldModifiers() field flags} specified in the JVM + * specification will be included in the returned mask. + */ + int getModifiers(); + + default boolean isFinal() { + return ModifiersProvider.super.isFinalFlagSet(); + } + + /** + * Determines if this field was injected by the VM. Such a field, for example, is not derived + * from a class file. + */ + boolean isInternal(); + + /** + * Determines if this field is a synthetic field as defined by the Java Language Specification. + */ + boolean isSynthetic(); + + /** + * Returns the {@link ResolvedJavaType} object representing the class or interface that declares + * this field. + */ + ResolvedJavaType getDeclaringClass(); + + /** + * Returns all annotations of this field. If no annotations are present, an array of length 0 is + * returned. + */ + Annotation[] getAnnotations(); + + /** + * Returns the annotation for the specified type of this field, if such an annotation is + * present. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return this element's annotation for the specified annotation type if present on this field, + * else {@code null} + */ + T getAnnotation(Class annotationClass); + + /** + * Returns an object representing the unique location identity of this resolved Java field. + * + * @return the location identity of the field + */ + LocationIdentity getLocationIdentity(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.lang.annotation.*; +import java.lang.invoke.*; +import java.lang.reflect.*; +import java.util.*; + +/** + * Represents a resolved Java method. Methods, like fields and types, are resolved through + * {@link ConstantPool constant pools}. + */ +public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersProvider { + + /** + * Returns the bytecode of this method, if the method has code. The returned byte array does not + * contain breakpoints or non-Java bytecodes. This may return null if the + * {@link #getDeclaringClass() holder} is not {@link ResolvedJavaType#isLinked() linked}. + * + * The contained constant pool indices may not be the ones found in the original class file but + * they can be used with the JVMCI API (e.g. methods in {@link ConstantPool}). + * + * @return the bytecode of the method, or {@code null} if {@code getCodeSize() == 0} or if the + * code is not ready. + */ + byte[] getCode(); + + /** + * Returns the size of the bytecode of this method, if the method has code. This is equivalent + * to {@link #getCode()}. {@code length} if the method has code. + * + * @return the size of the bytecode in bytes, or 0 if no bytecode is available + */ + int getCodeSize(); + + /** + * Returns the {@link ResolvedJavaType} object representing the class or interface that declares + * this method. + */ + ResolvedJavaType getDeclaringClass(); + + /** + * Returns the maximum number of locals used in this method's bytecodes. + */ + int getMaxLocals(); + + /** + * Returns the maximum number of stack slots used in this method's bytecodes. + */ + int getMaxStackSize(); + + /** + * {@inheritDoc} + *

+ * Only the {@linkplain Modifier#methodModifiers() method flags} specified in the JVM + * specification will be included in the returned mask. + */ + int getModifiers(); + + default boolean isFinal() { + return ModifiersProvider.super.isFinalFlagSet(); + } + + /** + * Determines if this method is a synthetic method as defined by the Java Language + * Specification. + */ + default boolean isSynthetic() { + return (SYNTHETIC & getModifiers()) == SYNTHETIC; + } + + /** + * Checks that the method is a varargs + * method. + * + * @return whether the method is a varargs method + */ + default boolean isVarArgs() { + return (VARARGS & getModifiers()) == VARARGS; + } + + /** + * Checks that the method is a bridge + * method. + * + * @return whether the method is a bridge method + */ + default boolean isBridge() { + return (BRIDGE & getModifiers()) == BRIDGE; + } + + /** + * Returns {@code true} if this method is a default method; returns {@code false} otherwise. + * + * A default method is a public non-abstract instance method, that is, a non-static method with + * a body, declared in an interface type. + * + * @return true if and only if this method is a default method as defined by the Java Language + * Specification. + */ + boolean isDefault(); + + /** + * Checks whether this method is a class initializer. + * + * @return {@code true} if the method is a class initializer + */ + boolean isClassInitializer(); + + /** + * Checks whether this method is a constructor. + * + * @return {@code true} if the method is a constructor + */ + boolean isConstructor(); + + /** + * Checks whether this method can be statically bound (usually, that means it is final or + * private or static, but not abstract, or the declaring class is final). + * + * @return {@code true} if this method can be statically bound + */ + boolean canBeStaticallyBound(); + + /** + * Returns the list of exception handlers for this method. + */ + ExceptionHandler[] getExceptionHandlers(); + + /** + * Returns a stack trace element for this method and a given bytecode index. + */ + StackTraceElement asStackTraceElement(int bci); + + /** + * Returns an object that provides access to the profiling information recorded for this method. + */ + default ProfilingInfo getProfilingInfo() { + return getProfilingInfo(true, true); + } + + /** + * Returns an object that provides access to the profiling information recorded for this method. + * + * @param includeNormal if true, + * {@linkplain ProfilingInfo#getDeoptimizationCount(DeoptimizationReason) + * deoptimization counts} will include deoptimization that happened during execution + * of standard non-osr methods. + * @param includeOSR if true, + * {@linkplain ProfilingInfo#getDeoptimizationCount(DeoptimizationReason) + * deoptimization counts} will include deoptimization that happened during execution + * of on-stack-replacement methods. + */ + ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR); + + /** + * Invalidates the profiling information and restarts profiling upon the next invocation. + */ + void reprofile(); + + /** + * Returns the constant pool of this method. + */ + ConstantPool getConstantPool(); + + /** + * Returns all annotations of this method. If no annotations are present, an array of length 0 + * is returned. + */ + Annotation[] getAnnotations(); + + /** + * Returns the annotation for the specified type of this method, if such an annotation is + * present. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return this element's annotation for the specified annotation type if present on this + * method, else {@code null} + */ + T getAnnotation(Class annotationClass); + + /** + * Returns an array of arrays that represent the annotations on the formal parameters, in + * declaration order, of this method. + * + * @see Method#getParameterAnnotations() + */ + Annotation[][] getParameterAnnotations(); + + /** + * Returns an array of {@link Type} objects that represent the formal parameter types, in + * declaration order, of this method. + * + * @see Method#getGenericParameterTypes() + */ + Type[] getGenericParameterTypes(); + + /** + * Returns {@code true} if this method is not excluded from inlining and has associated Java + * bytecodes (@see {@link ResolvedJavaMethod#hasBytecodes()}). + */ + boolean canBeInlined(); + + /** + * Returns {@code true} if the inlining of this method should be forced. + */ + boolean shouldBeInlined(); + + /** + * Returns the LineNumberTable of this method or null if this method does not have a line + * numbers table. + */ + LineNumberTable getLineNumberTable(); + + /** + * Returns the local variable table of this method or null if this method does not have a local + * variable table. + */ + LocalVariableTable getLocalVariableTable(); + + /** + * Invokes the underlying method represented by this object, on the specified object with the + * specified parameters. This method is similar to a reflective method invocation by + * {@link Method#invoke}. + * + * @param receiver The receiver for the invocation, or {@code null} if it is a static method. + * @param arguments The arguments for the invocation. + * @return The value returned by the method invocation, or {@code null} if the return type is + * {@code void}. + */ + JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments); + + /** + * Gets the encoding of (that is, a constant representing the value of) this method. + * + * @return a constant representing a reference to this method + */ + Constant getEncoding(); + + /** + * Checks if this method is present in the virtual table for subtypes of the specified + * {@linkplain ResolvedJavaType type}. + * + * @return true is this method is present in the virtual table for subtypes of this type. + */ + boolean isInVirtualMethodTable(ResolvedJavaType resolved); + + /** + * Gets the annotation of a particular type for a formal parameter of this method. + * + * @param annotationClass the Class object corresponding to the annotation type + * @param parameterIndex the index of a formal parameter of {@code method} + * @return the annotation of type {@code annotationClass} for the formal parameter present, else + * null + * @throws IndexOutOfBoundsException if {@code parameterIndex} does not denote a formal + * parameter + */ + default T getParameterAnnotation(Class annotationClass, int parameterIndex) { + if (parameterIndex >= 0) { + Annotation[][] parameterAnnotations = getParameterAnnotations(); + for (Annotation a : parameterAnnotations[parameterIndex]) { + if (a.annotationType() == annotationClass) { + return annotationClass.cast(a); + } + } + } + return null; + } + + default JavaType[] toParameterTypes() { + JavaType receiver = isStatic() || isConstructor() ? null : getDeclaringClass(); + return getSignature().toParameterTypes(receiver); + } + + /** + * Gets the annotations of a particular type for the formal parameters of this method. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return the annotation of type {@code annotationClass} (if any) for each formal parameter + * present + */ + @SuppressWarnings("unchecked") + default T[] getParameterAnnotations(Class annotationClass) { + Annotation[][] parameterAnnotations = getParameterAnnotations(); + T[] result = (T[]) Array.newInstance(annotationClass, parameterAnnotations.length); + for (int i = 0; i < parameterAnnotations.length; i++) { + for (Annotation a : parameterAnnotations[i]) { + if (a.annotationType() == annotationClass) { + result[i] = annotationClass.cast(a); + } + } + } + return result; + } + + /** + * Checks whether the method has bytecodes associated with it. Methods without bytecodes are + * either abstract or native methods. + * + * @return whether the definition of this method is Java bytecodes + */ + default boolean hasBytecodes() { + return isConcrete() && !isNative(); + } + + /** + * Checks whether the method has a receiver parameter - i.e., whether it is not static. + * + * @return whether the method has a receiver parameter + */ + default boolean hasReceiver() { + return !isStatic(); + } + + /** + * Determines if this method is {@link java.lang.Object#Object()}. + */ + default boolean isJavaLangObjectInit() { + return getDeclaringClass().isJavaLangObject() && getName().equals(""); + } + + SpeculationLog getSpeculationLog(); + + /** + * Determines if the method identified by its holder and name is a signature + * polymorphic method. + */ + static boolean isSignaturePolymorphic(JavaType holder, String name, MetaAccessProvider metaAccess) { + if (!holder.getName().equals("Ljava/lang/invoke/MethodHandle;")) { + return false; + } + ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); + Signature signature = metaAccess.parseMethodDescriptor("([Ljava/lang/Object;)Ljava/lang/Object;"); + ResolvedJavaMethod method = methodHandleType.findMethod(name, signature); + if (method == null) { + return false; + } + return method.isNative() && method.isVarArgs(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.lang.annotation.*; +import java.net.*; + +import jdk.vm.ci.meta.Assumptions.*; + +/** + * Represents a resolved Java type. Types include primitives, objects, {@code void}, and arrays + * thereof. Types, like fields and methods, are resolved through {@link ConstantPool constant pools} + * . + */ +public interface ResolvedJavaType extends JavaType, ModifiersProvider { + /** + * Gets the runtime representation of the Java class object of this type. + */ + JavaConstant getJavaClass(); + + /** + * Gets the runtime representation of the "hub" of this type--that is, the closest part of the + * type representation which is typically stored in the object header. + */ + Constant getObjectHub(); + + /** + * Checks whether this type has a finalizer method. + * + * @return {@code true} if this class has a finalizer + */ + boolean hasFinalizer(); + + /** + * Checks whether this type has any finalizable subclasses so far. Any decisions based on this + * information require the registration of a dependency, since this information may change. + * + * @return {@code true} if this class has any subclasses with finalizers + */ + AssumptionResult hasFinalizableSubclass(); + + /** + * Checks whether this type is an interface. + * + * @return {@code true} if this type is an interface + */ + boolean isInterface(); + + /** + * Checks whether this type is an instance class. + * + * @return {@code true} if this type is an instance class + */ + boolean isInstanceClass(); + + /** + * Checks whether this type is an array class. + * + * @return {@code true} if this type is an array class + */ + boolean isArray(); + + /** + * Checks whether this type is primitive. + * + * @return {@code true} if this type is primitive + */ + boolean isPrimitive(); + + /** + * {@inheritDoc} + *

+ * Only the flags specified in the JVM specification will be included in the returned mask. This + * method is identical to {@link Class#getModifiers()} in terms of the value return for this + * type. + */ + int getModifiers(); + + /* + * The setting of the final bit for types is a bit confusing since arrays are marked as final. + * This method provides a semantically equivalent test that appropriate for types. + */ + default boolean isLeaf() { + return getElementalType().isFinalFlagSet(); + } + + /** + * Checks whether this type is initialized. If a type is initialized it implies that it was + * {@link #isLinked() linked} and that the static initializer has run. + * + * @return {@code true} if this type is initialized + */ + boolean isInitialized(); + + /** + * Initializes this type. + */ + void initialize(); + + /** + * Checks whether this type is linked and verified. When a type is linked the static initializer + * has not necessarily run. An {@link #isInitialized() initialized} type is always linked. + * + * @return {@code true} if this type is linked + */ + boolean isLinked(); + + /** + * Determines if this type is either the same as, or is a superclass or superinterface of, the + * type represented by the specified parameter. This method is identical to + * {@link Class#isAssignableFrom(Class)} in terms of the value return for this type. + */ + boolean isAssignableFrom(ResolvedJavaType other); + + /** + * Returns true if this type is exactly the type {@link java.lang.Object}. + */ + default boolean isJavaLangObject() { + // Removed assertion due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=434442 + return getSuperclass() == null && !isInterface() && getJavaKind() == JavaKind.Object; + } + + /** + * Checks whether the specified object is an instance of this type. + * + * @param obj the object to test + * @return {@code true} if the object is an instance of this type + */ + boolean isInstance(JavaConstant obj); + + /** + * Returns this type if it is an exact type otherwise returns null. This type is exact if it is + * void, primitive, final, or an array of a final or primitive type. + * + * @return this type if it is exact; {@code null} otherwise + */ + ResolvedJavaType asExactType(); + + /** + * Gets the super class of this type. If this type represents either the {@code Object} class, + * an interface, a primitive type, or void, then null is returned. If this object represents an + * array class then the type object representing the {@code Object} class is returned. + */ + ResolvedJavaType getSuperclass(); + + /** + * Gets the interfaces implemented or extended by this type. This method is analogous to + * {@link Class#getInterfaces()} and as such, only returns the interfaces directly implemented + * or extended by this type. + */ + ResolvedJavaType[] getInterfaces(); + + /** + * Gets the single implementor of this type. Calling this method on a non-interface type causes + * an exception. + *

+ * If the compiler uses the result of this method for its compilation, the usage must be guarded + * because the verifier can not guarantee that the assigned type really implements this + * interface. Additionally, class loading can invalidate the result of this method. + * + * @return {@code null} if there is no implementor, the implementor if there is only one, or + * {@code this} if there are more than one. + */ + ResolvedJavaType getSingleImplementor(); + + /** + * Walks the class hierarchy upwards and returns the least common class that is a superclass of + * both the current and the given type. + * + * @return the least common type that is a super type of both the current and the given type, or + * {@code null} if primitive types are involved. + */ + ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType); + + /** + * Attempts to get a leaf concrete subclass of this type. + *

+ * For an {@linkplain #isArray() array} type A, the leaf concrete subclass is A if the + * {@linkplain #getElementalType() elemental} type of A is final (which includes primitive + * types). Otherwise {@code null} is returned for A. + *

+ * For a non-array type T, the result is the leaf concrete type in the current hierarchy of T. + *

+ * A runtime may decide not to manage or walk a large hierarchy and so the result is + * conservative. That is, a non-null result is guaranteed to be the leaf concrete class in T's + * hierarchy at the current point in time but a null result does not necessarily imply + * that there is no leaf concrete class in T's hierarchy. + *

+ * If the compiler uses the result of this method for its compilation, it must register the + * {@link AssumptionResult} in its {@link Assumptions} because dynamic class loading can + * invalidate the result of this method. + * + * @return an {@link AssumptionResult} containing the leaf concrete subclass for this type as + * described above + */ + AssumptionResult findLeafConcreteSubtype(); + + ResolvedJavaType getComponentType(); + + default ResolvedJavaType getElementalType() { + ResolvedJavaType t = this; + while (t.isArray()) { + t = t.getComponentType(); + } + return t; + } + + ResolvedJavaType getArrayClass(); + + /** + * Resolves the method implementation for virtual dispatches on objects of this dynamic type. + * This resolution process only searches "up" the class hierarchy of this type. + * + * @param method the method to select the implementation of + * @param callerType the caller or context type used to perform access checks + * @return the link-time resolved method (might be abstract) or {@code null} if it can not be + * linked + */ + ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType); + + /** + * Resolves the method implementation for virtual dispatches on objects of this dynamic type. + * This resolution process only searches "up" the class hierarchy of this type. A broader search + * that also walks "down" the hierarchy is implemented by + * {@link #findUniqueConcreteMethod(ResolvedJavaMethod)}. + * + * @param method the method to select the implementation of + * @param callerType the caller or context type used to perform access checks + * @return the concrete method that would be selected at runtime, or {@code null} if there is no + * concrete implementation of {@code method} in this type or any of its superclasses + */ + ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType); + + /** + * Given a {@link ResolvedJavaMethod} A, returns a concrete {@link ResolvedJavaMethod} B that is + * the only possible unique target for a virtual call on A(). Returns {@code null} if either no + * such concrete method or more than one such method exists. Returns the method A if A is a + * concrete method that is not overridden. + *

+ * If the compiler uses the result of this method for its compilation, it must register an + * assumption because dynamic class loading can invalidate the result of this method. + * + * @param method the method A for which a unique concrete target is searched + * @return the unique concrete target or {@code null} if no such target exists or assumptions + * are not supported by this runtime + */ + AssumptionResult findUniqueConcreteMethod(ResolvedJavaMethod method); + + /** + * Returns the instance fields of this class, including + * {@linkplain ResolvedJavaField#isInternal() internal} fields. A zero-length array is returned + * for array and primitive types. The order of fields returned by this method is stable. That + * is, for a single JVM execution the same order is returned each time this method is called. It + * is also the "natural" order, which means that the JVM would expect the fields in this order + * if no specific order is given. + * + * @param includeSuperclasses if true, then instance fields for the complete hierarchy of this + * type are included in the result + * @return an array of instance fields + */ + ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses); + + /** + * Returns the static fields of this class, including + * {@linkplain ResolvedJavaField#isInternal() internal} fields. A zero-length array is returned + * for array and primitive types. The order of fields returned by this method is stable. That + * is, for a single JVM execution the same order is returned each time this method is called. + */ + ResolvedJavaField[] getStaticFields(); + + /** + * Returns all annotations of this class. If no annotations are present, an array of length 0 is + * returned. + */ + Annotation[] getAnnotations(); + + /** + * Returns the annotation for the specified type of this class, if such an annotation is + * present. + * + * @param annotationClass the Class object corresponding to the annotation type + * @return this element's annotation for the specified annotation type if present on this class, + * else {@code null} + */ + T getAnnotation(Class annotationClass); + + /** + * Returns the instance field of this class (or one of its super classes) at the given offset, + * or {@code null} if there is no such field. + * + * @param offset the offset of the field to look for + * @return the field with the given offset, or {@code null} if there is no such field. + */ + ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedKind); + + /** + * Returns name of source file of this type. + */ + String getSourceFileName(); + + /** + * Returns the class file path - if available - of this type, or {@code null}. + */ + URL getClassFilePath(); + + /** + * Returns {@code true} if the type is a local type. + */ + boolean isLocal(); + + /** + * Returns {@code true} if the type is a member type. + */ + boolean isMember(); + + /** + * Returns the enclosing type of this type, if it exists, or {@code null}. + */ + ResolvedJavaType getEnclosingType(); + + /** + * Returns an array reflecting all the constructors declared by this type. This method is + * similar to {@link Class#getDeclaredConstructors()} in terms of returned constructors. + */ + ResolvedJavaMethod[] getDeclaredConstructors(); + + /** + * Returns an array reflecting all the methods declared by this type. This method is similar to + * {@link Class#getDeclaredMethods()} in terms of returned methods. + */ + ResolvedJavaMethod[] getDeclaredMethods(); + + /** + * Returns the {@code } method for this class if there is one. + */ + ResolvedJavaMethod getClassInitializer(); + + /** + * Returns true if this type represents an interface and it should be trusted even in places + * where the JVM verifier would not give any guarantees other than {@link Object}. + */ + boolean isTrustedInterfaceType(); + + default ResolvedJavaMethod findMethod(String name, Signature signature) { + for (ResolvedJavaMethod method : getDeclaredMethods()) { + if (method.getName().equals(name) && method.getSignature().equals(signature)) { + return method; + } + } + return null; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SerializableConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SerializableConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.nio.*; + +/** + * Represents a compile-time constant that can be converted to a byte array. + */ +public interface SerializableConstant extends Constant { + + /** + * Return the size in bytes of the serialized representation of this constant. + */ + int getSerializedSize(); + + /** + * Serialize the constant into the ByteBuffer. There must be at least + * {@link #getSerializedSize()} bytes available capacity in the buffer. + */ + void serialize(ByteBuffer buffer); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Signature.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Signature.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Represents a method signature provided by the runtime. + * + * @see Method + * Descriptors + */ +public interface Signature { + + /** + * Returns the number of parameters in this signature, adding 1 for a receiver if requested. + * + * @param receiver true if 1 is to be added to the result for a receiver + * @return the number of parameters; + 1 iff {@code receiver == true} + */ + int getParameterCount(boolean receiver); + + /** + * Gets the parameter type at the specified position. + * + * @param index the index into the parameters, with {@code 0} indicating the first parameter + * @param accessingClass the context of the type lookup. If non-null, its class loader is used + * for resolving the type. If {@code null}, then the type returned is either + * unresolved or a resolved type whose resolution is context free (e.g., a primitive + * type or a type in a java.* package). + * @return the {@code index}'th parameter type + * @throws LinkageError if {@code accessingClass != null} and resolution fails + * + */ + JavaType getParameterType(int index, ResolvedJavaType accessingClass); + + /** + * Gets the parameter kind at the specified position. This is the same as calling + * {@link #getParameterType}. {@link JavaType#getJavaKind getJavaKind}. + * + * @param index the index into the parameters, with {@code 0} indicating the first parameter + * @return the kind of the parameter at the specified position + */ + default JavaKind getParameterKind(int index) { + return getParameterType(index, null).getJavaKind(); + } + + /** + * Gets the return type of this signature. + * + * @param accessingClass the context of the type lookup. If non-null, its class loader is used + * for resolving the type. If {@code null}, then the type returned is either + * unresolved or a resolved type whose resolution is context free (e.g., a primitive + * type or a type in a java.* package). + * @return the return type + * @throws LinkageError if {@code accessingClass != null} and resolution fails + */ + JavaType getReturnType(ResolvedJavaType accessingClass); + + /** + * Gets the return kind of this signature. This is the same as calling {@link #getReturnType}. + * {@link JavaType#getJavaKind getJavaKind}. + */ + default JavaKind getReturnKind() { + return getReturnType(null).getJavaKind(); + } + + /** + * Gets the method + * descriptor corresponding to this signature. For example: + * + *

+     * (ILjava/lang/String;D)V
+     * 
+ * + * @return the signature as a string + */ + default String toMethodDescriptor() { + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < getParameterCount(false); ++i) { + sb.append(getParameterType(i, null).getName()); + } + sb.append(')').append(getReturnType(null).getName()); + return sb.toString(); + } + + default JavaType[] toParameterTypes(JavaType receiverType) { + int args = getParameterCount(false); + JavaType[] result; + int i = 0; + if (receiverType != null) { + result = new JavaType[args + 1]; + result[0] = receiverType; + i = 1; + } else { + result = new JavaType[args]; + } + for (int j = 0; j < args; j++) { + result[i + j] = getParameterType(j, null); + } + return result; + } + + default JavaKind[] toParameterKinds(boolean receiver) { + int args = getParameterCount(false); + JavaKind[] result; + int i = 0; + if (receiver) { + result = new JavaKind[args + 1]; + result[0] = JavaKind.Object; + i = 1; + } else { + result = new JavaKind[args]; + } + for (int j = 0; j < args; j++) { + result[i + j] = getParameterKind(j); + } + return result; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +import java.util.*; +import java.util.concurrent.*; + +/** + * Manages a list of unique deoptimization reasons. + * + */ +public abstract class SpeculationLog { + private volatile Object lastFailed; + private volatile Collection speculations; + private Set failedSpeculations; + + public synchronized void collectFailedSpeculations() { + if (lastFailed != null) { + if (failedSpeculations == null) { + failedSpeculations = new HashSet<>(2); + } + failedSpeculations.add(lastFailed); + lastFailed = null; + speculations = null; + } + } + + public boolean maySpeculate(Object reason) { + if (failedSpeculations != null && failedSpeculations.contains(reason)) { + return false; + } + return true; + } + + protected void addSpeculation(Object reason) { + assert maySpeculate(reason); + if (speculations == null) { + synchronized (this) { + if (speculations == null) { + speculations = new ConcurrentLinkedQueue<>(); + } + } + } + speculations.add(reason); + } + + public abstract JavaConstant speculate(Object reason); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TriState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TriState.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Represents a logic value that can be either {@link #TRUE}, {@link #FALSE}, or {@link #UNKNOWN}. + */ +public enum TriState { + TRUE, + FALSE, + UNKNOWN; + + public static TriState get(boolean value) { + return value ? TRUE : FALSE; + } + + /** + * This is optimistic about {@link #UNKNOWN} (it prefers known values over {@link #UNKNOWN}) and + * pesimistic about known (it perfers {@link #TRUE} over {@link #FALSE}). + */ + public static TriState merge(TriState a, TriState b) { + if (a == TRUE || b == TRUE) { + return TRUE; + } + if (a == FALSE || b == FALSE) { + return FALSE; + } + assert a == UNKNOWN && b == UNKNOWN; + return UNKNOWN; + } + + public boolean isTrue() { + return this == TRUE; + } + + public boolean isFalse() { + return this == FALSE; + } + + public boolean isUnknown() { + return this == UNKNOWN; + } + + public boolean isKnown() { + return this != UNKNOWN; + } + + public boolean toBoolean() { + if (isTrue()) { + return true; + } else if (isFalse()) { + return false; + } else { + throw new IllegalStateException("Cannot convert to boolean, TriState is in an unknown state"); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TrustedInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TrustedInterface.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Interfaces extending this interface should be trusted by the compiler. See + * {@link ResolvedJavaType#isTrustedInterfaceType()}. + * + */ +public interface TrustedInterface { + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +public interface VMConstant extends Constant { +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Value.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Value.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.meta; + +/** + * Abstract base class for values. + */ +public abstract class Value { + + public static final Value[] NO_VALUES = new Value[0]; + + public static final AllocatableValue ILLEGAL = new IllegalValue(); + + private static final class IllegalValue extends AllocatableValue { + private IllegalValue() { + super(LIRKind.Illegal); + } + + @Override + public String toString() { + return "-"; + } + + @Override + public boolean equals(Object other) { + // Due to de-serialization this object may exist multiple times. So we compare classes + // instead of the individual objects. (This anonymous class has always the same meaning) + return other instanceof IllegalValue; + } + } + + private final LIRKind lirKind; + + /** + * Initializes a new value of the specified kind. + * + * @param lirKind the kind + */ + protected Value(LIRKind lirKind) { + this.lirKind = lirKind; + } + + /** + * Returns a String representation of the kind, which should be the end of all + * {@link #toString()} implementation of subclasses. + */ + protected final String getKindSuffix() { + return "|" + getPlatformKind().getTypeChar(); + } + + public final LIRKind getLIRKind() { + return lirKind; + } + + /** + * Returns the platform specific kind used to store this value. + */ + public final PlatformKind getPlatformKind() { + return lirKind.getPlatformKind(); + } + + @Override + public int hashCode() { + return 41 + lirKind.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Value) { + Value that = (Value) obj; + return lirKind.equals(that.lirKind); + } + return false; + } + + /** + * Checks if this value is identical to {@code other}. + * + * Warning: Use with caution! Usually equivalence {@link #equals(Object)} is sufficient and + * should be used. + */ + public final boolean identityEquals(Value other) { + return this == other; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/package-info.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Package that defines the interface between a runtime and a Java application that wants to access meta information. The runtime + * provides an implementation of the {@link jdk.vm.ci.meta.MetaAccessProvider} interface. + */ +package jdk.vm.ci.meta; + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/META-INF/services/javax.annotation.processing.Processor --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/META-INF/services/javax.annotation.processing.Processor Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +jdk.vm.ci.options.processor.OptionProcessor diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/jdk/vm/ci/options/processor/OptionProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options.processor/src/jdk/vm/ci/options/processor/OptionProcessor.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options.processor; + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import javax.tools.Diagnostic.Kind; + +import jdk.vm.ci.options.*; + +import javax.tools.*; + +/** + * Processes static fields annotated with {@link Option}. An {@link OptionDescriptors} + * implementation is generated for each top level class containing at least one such field. The name + * of the generated class for top level class {@code com.foo.Bar} is + * {@code com.foo.Bar_OptionDescriptors}. + */ +@SupportedAnnotationTypes({"jdk.vm.ci.options.Option"}) +public class OptionProcessor extends AbstractProcessor { + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private final Set processed = new HashSet<>(); + + private void processElement(Element element, OptionsInfo info) { + + if (!element.getModifiers().contains(Modifier.STATIC)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element); + return; + } + + Option annotation = element.getAnnotation(Option.class); + assert annotation != null; + assert element instanceof VariableElement; + assert element.getKind() == ElementKind.FIELD; + VariableElement field = (VariableElement) element; + String fieldName = field.getSimpleName().toString(); + + Elements elements = processingEnv.getElementUtils(); + Types types = processingEnv.getTypeUtils(); + + TypeMirror fieldType = field.asType(); + if (fieldType.getKind() != TypeKind.DECLARED) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + OptionValue.class.getName(), element); + return; + } + DeclaredType declaredFieldType = (DeclaredType) fieldType; + + TypeMirror optionValueType = elements.getTypeElement(OptionValue.class.getName()).asType(); + if (!types.isSubtype(fieldType, types.erasure(optionValueType))) { + String msg = String.format("Option field type %s is not a subclass of %s", fieldType, optionValueType); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + return; + } + + if (!field.getModifiers().contains(Modifier.STATIC)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be static", element); + return; + } + + String help = annotation.help(); + if (help.length() != 0) { + char firstChar = help.charAt(0); + if (!Character.isUpperCase(firstChar)) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Option help text must start with upper case letter", element); + return; + } + } + + String optionName = annotation.name(); + if (optionName.equals("")) { + optionName = fieldName; + } + + DeclaredType declaredOptionValueType = declaredFieldType; + while (!types.isSameType(types.erasure(declaredOptionValueType), types.erasure(optionValueType))) { + List directSupertypes = types.directSupertypes(declaredFieldType); + assert!directSupertypes.isEmpty(); + declaredOptionValueType = (DeclaredType) directSupertypes.get(0); + } + + assert!declaredOptionValueType.getTypeArguments().isEmpty(); + String optionType = declaredOptionValueType.getTypeArguments().get(0).toString(); + if (optionType.startsWith("java.lang.")) { + optionType = optionType.substring("java.lang.".length()); + } + + Element enclosing = element.getEnclosingElement(); + String declaringClass = ""; + String separator = ""; + Set originatingElementsList = info.originatingElements; + originatingElementsList.add(field); + while (enclosing != null) { + if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { + if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { + String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); + return; + } + originatingElementsList.add(enclosing); + declaringClass = enclosing.getSimpleName() + separator + declaringClass; + separator = "."; + } else { + assert enclosing.getKind() == ElementKind.PACKAGE; + } + enclosing = enclosing.getEnclosingElement(); + } + + info.options.add(new OptionInfo(optionName, help, optionType, declaringClass, field)); + } + + private void createFiles(OptionsInfo info) { + String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); + Name topDeclaringClass = info.topDeclaringType.getSimpleName(); + Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); + + createOptionsDescriptorsFile(info, pkg, topDeclaringClass, originatingElements); + } + + private void createOptionsDescriptorsFile(OptionsInfo info, String pkg, Name topDeclaringClass, Element[] originatingElements) { + String optionsClassName = topDeclaringClass + "_" + OptionDescriptors.class.getSimpleName(); + + Filer filer = processingEnv.getFiler(); + try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) { + + out.println("// CheckStyle: stop header check"); + out.println("// CheckStyle: stop line length check"); + out.println("// GENERATED CONTENT - DO NOT EDIT"); + out.println("// Source: " + topDeclaringClass + ".java"); + out.println("package " + pkg + ";"); + out.println(""); + out.println("import java.util.*;"); + out.println("import " + OptionDescriptors.class.getPackage().getName() + ".*;"); + out.println(""); + out.println("public class " + optionsClassName + " implements " + OptionDescriptors.class.getSimpleName() + " {"); + + String desc = OptionDescriptor.class.getSimpleName(); + + boolean needPrivateFieldAccessor = false; + int i = 0; + Collections.sort(info.options); + + out.println(" @Override"); + out.println(" public OptionDescriptor get(String value) {"); + out.println(" // CheckStyle: stop line length check"); + if (info.options.size() == 1) { + out.println(" if (value.equals(\"" + info.options.get(0).name + "\")) {"); + } else { + out.println(" switch (value) {"); + } + for (OptionInfo option : info.options) { + String name = option.name; + String optionValue; + if (option.field.getModifiers().contains(Modifier.PRIVATE)) { + needPrivateFieldAccessor = true; + optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; + } else { + optionValue = option.declaringClass + "." + option.field.getSimpleName(); + } + String type = option.type; + String help = option.help; + String declaringClass = option.declaringClass; + Name fieldName = option.field.getSimpleName(); + if (info.options.size() == 1) { + out.printf(" return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, optionValue); + } else { + out.printf(" case \"" + name + "\": return %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s);\n", desc, name, type, help, declaringClass, fieldName, + optionValue); + } + } + out.println(" }"); + out.println(" // CheckStyle: resume line length check"); + out.println(" return null;"); + out.println(" }"); + out.println(); + out.println(" @Override"); + out.println(" public Iterator<" + desc + "> iterator() {"); + out.println(" // CheckStyle: stop line length check"); + out.println(" List<" + desc + "> options = Arrays.asList("); + for (OptionInfo option : info.options) { + String optionValue; + if (option.field.getModifiers().contains(Modifier.PRIVATE)) { + needPrivateFieldAccessor = true; + optionValue = "field(" + option.declaringClass + ".class, \"" + option.field.getSimpleName() + "\")"; + } else { + optionValue = option.declaringClass + "." + option.field.getSimpleName(); + } + String name = option.name; + String type = option.type; + String help = option.help; + String declaringClass = option.declaringClass; + Name fieldName = option.field.getSimpleName(); + String comma = i == info.options.size() - 1 ? "" : ","; + out.printf(" %s.create(\"%s\", %s.class, \"%s\", %s.class, \"%s\", %s)%s\n", desc, name, type, help, declaringClass, fieldName, optionValue, comma); + i++; + } + out.println(" );"); + out.println(" // CheckStyle: resume line length check"); + out.println(" return options.iterator();"); + out.println(" }"); + if (needPrivateFieldAccessor) { + out.println(" private static " + OptionValue.class.getSimpleName() + " field(Class declaringClass, String fieldName) {"); + out.println(" try {"); + out.println(" java.lang.reflect.Field field = declaringClass.getDeclaredField(fieldName);"); + out.println(" field.setAccessible(true);"); + out.println(" return (" + OptionValue.class.getSimpleName() + ") field.get(null);"); + out.println(" } catch (Exception e) {"); + out.println(" throw (InternalError) new InternalError().initCause(e);"); + out.println(" }"); + out.println(" }"); + } + out.println("}"); + } + + try { + createOptionsFile(pkg, topDeclaringClass.toString(), originatingElements); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), info.topDeclaringType); + } + } + + private void createOptionsFile(String pkg, String relativeName, Element... originatingElements) throws IOException { + String filename = "META-INF/jvmci.options/" + pkg + "." + relativeName; + FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8")); + writer.close(); + } + + protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) { + try { + // Ensure Unix line endings to comply with code style guide checked by Checkstyle + JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements); + return new PrintWriter(sourceFile.openWriter()) { + + @Override + public void println() { + print("\n"); + } + }; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + static class OptionInfo implements Comparable { + + final String name; + final String help; + final String type; + final String declaringClass; + final VariableElement field; + + public OptionInfo(String name, String help, String type, String declaringClass, VariableElement field) { + this.name = name; + this.help = help; + this.type = type; + this.declaringClass = declaringClass; + this.field = field; + } + + @Override + public int compareTo(OptionInfo other) { + return name.compareTo(other.name); + } + + @Override + public String toString() { + return declaringClass + "." + field; + } + } + + static class OptionsInfo { + + final Element topDeclaringType; + final List options = new ArrayList<>(); + final Set originatingElements = new HashSet<>(); + + public OptionsInfo(Element topDeclaringType) { + this.topDeclaringType = topDeclaringType; + } + } + + private static Element topDeclaringType(Element element) { + Element enclosing = element.getEnclosingElement(); + if (enclosing == null || enclosing.getKind() == ElementKind.PACKAGE) { + assert element.getKind() == ElementKind.CLASS || element.getKind() == ElementKind.INTERFACE; + return element; + } + return topDeclaringType(enclosing); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return true; + } + + Map map = new HashMap<>(); + for (Element element : roundEnv.getElementsAnnotatedWith(Option.class)) { + if (!processed.contains(element)) { + processed.add(element); + Element topDeclaringType = topDeclaringType(element); + OptionsInfo options = map.get(topDeclaringType); + if (options == null) { + options = new OptionsInfo(topDeclaringType); + map.put(topDeclaringType, options); + } + processElement(element, options); + } + } + + boolean ok = true; + Map uniqueness = new HashMap<>(); + for (OptionsInfo info : map.values()) { + for (OptionInfo option : info.options) { + OptionInfo conflict = uniqueness.put(option.name, option); + if (conflict != null) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Duplicate option names for " + option + " and " + conflict, option.field); + ok = false; + } + } + } + + if (ok) { + for (OptionsInfo info : map.values()) { + createFiles(info); + } + } + + return true; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/DerivedOptionValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/DerivedOptionValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.options; + +import java.io.*; +import java.util.function.*; + +import jdk.vm.ci.options.OptionValue.*; + +/** + * A cached value that needs to be recomputed when an option changes. + */ +public class DerivedOptionValue { + + public interface OptionSupplier extends Supplier, Serializable { + } + + private final T initialValue; + private final OptionSupplier supplier; + + public DerivedOptionValue(OptionSupplier supplier) { + this.supplier = supplier; + assert OptionValue.getOverrideScope() == null : "derived option value should be initialized outside any override scope"; + this.initialValue = createValue(); + } + + public T getValue() { + OverrideScope overrideScope = OptionValue.getOverrideScope(); + if (overrideScope != null) { + return overrideScope.getDerived(this); + } else { + return initialValue; + } + } + + T createValue() { + return supplier.get(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/JVMCIJarsOptionDescriptorsProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/JVMCIJarsOptionDescriptorsProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.options; + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import java.util.zip.*; + +import jdk.vm.ci.options.OptionsParser.*; + +/** + * Access to the {@link OptionDescriptors} declared by + * {@code META-INF/services/jdk.vm.ci.options.OptionDescriptors} files in {@code + * /lib/jvmci/*.jar}. + */ +class JVMCIJarsOptionDescriptorsProvider implements OptionDescriptorsProvider { + + static final String OptionDescriptorsServiceFile = "META-INF/services/" + OptionDescriptors.class.getName(); + + private final Iterator jars; + private final List optionsDescriptorsList; + + JVMCIJarsOptionDescriptorsProvider() { + List jarsList = findJVMCIJars(); + this.jars = jarsList.iterator(); + this.optionsDescriptorsList = new ArrayList<>(jarsList.size() * 3); + } + + /** + * Finds the list of JVMCI jars. + */ + private static List findJVMCIJars() { + File javaHome = new File(System.getProperty("java.home")); + File lib = new File(javaHome, "lib"); + File jvmci = new File(lib, "jvmci"); + + List jarFiles = new ArrayList<>(); + if (jvmci.exists()) { + for (String fileName : jvmci.list()) { + if (fileName.endsWith(".jar")) { + File file = new File(jvmci, fileName); + if (file.isDirectory()) { + continue; + } + jarFiles.add(file); + } + } + } + return jarFiles; + } + + public OptionDescriptor get(String name) { + // Look up loaded option descriptors first + for (OptionDescriptors optionDescriptors : optionsDescriptorsList) { + OptionDescriptor desc = optionDescriptors.get(name); + if (desc != null) { + return desc; + } + } + while (jars.hasNext()) { + File path = jars.next(); + try (JarFile jar = new JarFile(path)) { + ZipEntry entry = jar.getEntry(OptionDescriptorsServiceFile); + if (entry != null) { + BufferedReader br = new BufferedReader(new InputStreamReader(jar.getInputStream(entry))); + String line = null; + OptionDescriptor desc = null; + while ((line = br.readLine()) != null) { + OptionDescriptors options; + try { + options = (OptionDescriptors) Class.forName(line).newInstance(); + optionsDescriptorsList.add(options); + if (desc == null) { + desc = options.get(name); + } + } catch (Exception e) { + throw new InternalError("Error instantiating class " + line + " read from " + path, e); + } + } + if (desc != null) { + return desc; + } + } + } catch (IOException e) { + throw new InternalError("Error reading " + path, e); + } + } + return null; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/NestedBooleanOptionValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/NestedBooleanOptionValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.options; + +/** + * A nested Boolean {@link OptionValue} that can be overridden by a {@link #masterOption master + * option}. + *

+ *

  • If the option is present on the command line the specified value is used. + *
  • Otherwise {@link #getValue()} depends on the {@link #masterOption} and evaluates as follows: + *
      + *
    • If {@link #masterOption} is set, this value equals to {@link #initialValue}. + *
    • Otherwise, if {@link #masterOption} is {@code false}, this option is {@code false}. + */ +public class NestedBooleanOptionValue extends OptionValue { + private final OptionValue masterOption; + private final Boolean initialValue; + + public NestedBooleanOptionValue(OptionValue masterOption, Boolean initialValue) { + super(null); + this.masterOption = masterOption; + this.initialValue = initialValue; + } + + public OptionValue getMasterOption() { + return masterOption; + } + + @Override + public Boolean getValue() { + Boolean v = super.getValue(); + if (v == null) { + return initialValue && masterOption.getValue(); + } + return v; + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/Option.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/Option.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +import java.lang.annotation.*; + +/** + * Describes the attributes of an option whose {@link OptionValue value} is in a static field + * annotated by this annotation type. + * + * @see OptionDescriptor + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.FIELD) +public @interface Option { + + /** + * Gets a help message for the option. New lines can be embedded in the message with + * {@code "%n"}. + */ + String help(); + + /** + * The name of the option. By default, the name of the annotated field should be used. + */ + String name() default ""; + + /** + * Specifies the type of the option. + */ + OptionType type() default OptionType.Debug; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptor.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +/** + * Describes the attributes of a static field {@linkplain Option option} and provides access to its + * {@linkplain OptionValue value}. + */ +public final class OptionDescriptor { + + protected final String name; + protected final Class type; + protected final String help; + protected final OptionValue option; + protected final Class declaringClass; + protected final String fieldName; + + public static OptionDescriptor create(String name, Class type, String help, Class declaringClass, String fieldName, OptionValue option) { + OptionDescriptor result = option.getDescriptor(); + if (result == null) { + result = new OptionDescriptor(name, type, help, declaringClass, fieldName, option); + option.setDescriptor(result); + } + assert result.name.equals(name) && result.type == type && result.declaringClass == declaringClass && result.fieldName.equals(fieldName) && result.option == option; + return result; + } + + private OptionDescriptor(String name, Class type, String help, Class declaringClass, String fieldName, OptionValue option) { + this.name = name; + this.type = type; + this.help = help; + this.option = option; + this.declaringClass = declaringClass; + this.fieldName = fieldName; + assert !type.isPrimitive() : "must used boxed type instead of " + type; + } + + /** + * Gets the type of values stored in the option. This will be the boxed type for a primitive + * option. + */ + public Class getType() { + return type; + } + + /** + * Gets a descriptive help message for the option. + */ + public String getHelp() { + return help; + } + + /** + * Gets the name of the option. It's up to the client of this object how to use the name to get + * a user specified value for the option from the environment. + */ + public String getName() { + return name; + } + + /** + * Gets the boxed option value. + */ + public OptionValue getOptionValue() { + return option; + } + + public Class getDeclaringClass() { + return declaringClass; + } + + public String getFieldName() { + return fieldName; + } + + /** + * Gets a description of the location where this option is stored. + */ + public String getLocation() { + return getDeclaringClass().getName() + "." + getFieldName(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptors.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionDescriptors.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +/** + * An interface to a set of {@link OptionDescriptor}s. + */ +public interface OptionDescriptors extends Iterable { + /** + * Gets the {@link OptionDescriptor} matching a given option name or {@code null} if this option + * descriptor set doesn't contain a matching option. + */ + OptionDescriptor get(String value); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.options; + +/** + * Classifies JVMCI options in several categories depending on who this option is relevant for. + * + */ +public enum OptionType { + /** + * An option common for users to apply. + */ + User, + + /** + * An option only relevant in corner cases and for fine-tuning. + */ + Expert, + + /** + * An option only relevant when debugging the compiler. + */ + Debug +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +import java.io.*; +import java.util.*; +import java.util.Map.Entry; + +/** + * An option value. + */ +public class OptionValue { + /** + * Temporarily changes the value for an option. The {@linkplain OptionValue#getValue() value} of + * {@code option} is set to {@code value} until {@link OverrideScope#close()} is called on the + * object returned by this method. + *

      + * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be + * used: + * + *

      +     * try (OverrideScope s = OptionValue.override(myOption, myValue) {
      +     *     // code that depends on myOption == myValue
      +     * }
      +     * 
      + */ + public static OverrideScope override(OptionValue option, Object value) { + OverrideScope current = getOverrideScope(); + if (current == null) { + if (!value.equals(option.getValue())) { + return new SingleOverrideScope(option, value); + } + Map, Object> overrides = Collections.emptyMap(); + return new MultipleOverridesScope(current, overrides); + } + return new MultipleOverridesScope(current, option, value); + } + + /** + * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() + * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} + * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by + * this method. + *

      + * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be + * used: + * + *

      +     * Map<OptionValue, Object> overrides = new HashMap<>();
      +     * overrides.put(myOption1, myValue1);
      +     * overrides.put(myOption2, myValue2);
      +     * try (OverrideScope s = OptionValue.override(overrides) {
      +     *     // code that depends on myOption == myValue
      +     * }
      +     * 
      + */ + public static OverrideScope override(Map, Object> overrides) { + OverrideScope current = getOverrideScope(); + if (current == null && overrides.size() == 1) { + Entry, Object> single = overrides.entrySet().iterator().next(); + OptionValue option = single.getKey(); + Object overrideValue = single.getValue(); + if (!overrideValue.equals(option.getValue())) { + return new SingleOverrideScope(option, overrideValue); + } + } + return new MultipleOverridesScope(current, overrides); + } + + /** + * Temporarily changes the values for a set of options. The {@linkplain OptionValue#getValue() + * value} of each {@code option} in {@code overrides} is set to the corresponding {@code value} + * in {@code overrides} until {@link OverrideScope#close()} is called on the object returned by + * this method. + *

      + * Since the returned object is {@link AutoCloseable} the try-with-resource construct can be + * used: + * + *

      +     * try (OverrideScope s = OptionValue.override(myOption1, myValue1, myOption2, myValue2) {
      +     *     // code that depends on myOption == myValue
      +     * }
      +     * 
      + * + * @param overrides overrides in the form {@code [option1, override1, option2, override2, ...]} + */ + public static OverrideScope override(Object... overrides) { + OverrideScope current = getOverrideScope(); + if (current == null && overrides.length == 2) { + OptionValue option = (OptionValue) overrides[0]; + Object overrideValue = overrides[1]; + if (!overrideValue.equals(option.getValue())) { + return new SingleOverrideScope(option, overrideValue); + } + } + Map, Object> map = Collections.emptyMap(); + for (int i = 0; i < overrides.length; i += 2) { + OptionValue option = (OptionValue) overrides[i]; + Object overrideValue = overrides[i + 1]; + if (!overrideValue.equals(option.getValue())) { + if (map.isEmpty()) { + map = new HashMap<>(); + } + map.put(option, overrideValue); + } + } + return new MultipleOverridesScope(current, map); + } + + private static final ThreadLocal overrideScopeTL = new ThreadLocal<>(); + + protected static OverrideScope getOverrideScope() { + return overrideScopeTL.get(); + } + + protected static void setOverrideScope(OverrideScope overrideScope) { + overrideScopeTL.set(overrideScope); + } + + private T defaultValue; + + /** + * The raw option value. + */ + protected T value; + + private OptionDescriptor descriptor; + + private long reads; + private OptionValue next; + private static OptionValue head; + + private static final boolean ShowReadsHistogram = Boolean.getBoolean("jvmci.showOptionValueReadsHistogram"); + + private static void addToHistogram(OptionValue option) { + if (ShowReadsHistogram) { + synchronized (OptionValue.class) { + option.next = head; + head = option; + } + } + } + + @SuppressWarnings("unchecked") + public OptionValue(T value) { + this.defaultValue = value; + this.value = (T) DEFAULT; + addToHistogram(this); + } + + private static final Object DEFAULT = "DEFAULT"; + private static final Object UNINITIALIZED = "UNINITIALIZED"; + + /** + * Creates an uninitialized option value for a subclass that initializes itself + * {@link #defaultValue() lazily}. + */ + @SuppressWarnings("unchecked") + protected OptionValue() { + this.defaultValue = (T) UNINITIALIZED; + this.value = (T) DEFAULT; + addToHistogram(this); + } + + /** + * Lazy initialization of default value. + */ + protected T defaultValue() { + throw new InternalError("Option without a default value value must override defaultValue()"); + } + + /** + * Sets the descriptor for this option. + */ + public void setDescriptor(OptionDescriptor descriptor) { + assert this.descriptor == null : "Overwriting existing descriptor"; + this.descriptor = descriptor; + } + + /** + * Returns the descriptor for this option, if it has been set by + * {@link #setDescriptor(OptionDescriptor)}. + */ + public OptionDescriptor getDescriptor() { + return descriptor; + } + + /** + * Gets the name of this option. The name for an option value with a null + * {@linkplain #setDescriptor(OptionDescriptor) descriptor} is the value of + * {@link Object#toString()}. + */ + public String getName() { + return descriptor == null ? super.toString() : (descriptor.getDeclaringClass().getName() + "." + descriptor.getName()); + } + + @Override + public String toString() { + return getName() + "=" + getValue(); + } + + /** + * The initial value specified in source code. The returned value is not affected by calls to + * {@link #setValue(Object)} or registering {@link OverrideScope}s. Therefore, it is also not + * affected by options set on the command line. + */ + public T getDefaultValue() { + if (defaultValue == UNINITIALIZED) { + defaultValue = defaultValue(); + } + return defaultValue; + } + + /** + * Returns true if the option has the same value that was set in the source code. + */ + public boolean hasDefaultValue() { + if (!(this instanceof StableOptionValue)) { + getValue(); // ensure initialized + } + return value == DEFAULT || Objects.equals(value, getDefaultValue()); + } + + /** + * Gets the value of this option. + */ + public T getValue() { + if (ShowReadsHistogram) { + reads++; + } + if (!(this instanceof StableOptionValue)) { + OverrideScope overrideScope = getOverrideScope(); + if (overrideScope != null) { + T override = overrideScope.getOverride(this); + if (override != null) { + return override; + } + } + } + if (value != DEFAULT) { + return value; + } else { + return getDefaultValue(); + } + } + + /** + * Gets the values of this option including overridden values. + * + * @param c the collection to which the values are added. If null, one is allocated. + * @return the collection to which the values were added in order from most overridden to + * current value + */ + @SuppressWarnings("unchecked") + public Collection getValues(Collection c) { + Collection values = c == null ? new ArrayList<>() : c; + if (!(this instanceof StableOptionValue)) { + OverrideScope overrideScope = getOverrideScope(); + if (overrideScope != null) { + overrideScope.getOverrides(this, (Collection) values); + } + } + if (value != DEFAULT) { + values.add(value); + } else { + values.add(getDefaultValue()); + } + return values; + } + + /** + * Sets the value of this option. + */ + @SuppressWarnings("unchecked") + public void setValue(Object v) { + this.value = (T) v; + } + + /** + * An object whose {@link #close()} method reverts the option value overriding initiated by + * {@link OptionValue#override(OptionValue, Object)} or {@link OptionValue#override(Map)}. + */ + public abstract static class OverrideScope implements AutoCloseable { + + private Map, Object> derivedCache = null; + + public T getDerived(DerivedOptionValue key) { + if (derivedCache == null) { + derivedCache = new HashMap<>(); + } + @SuppressWarnings("unchecked") + T ret = (T) derivedCache.get(key); + if (ret == null) { + ret = key.createValue(); + derivedCache.put(key, ret); + } + return ret; + } + + abstract void addToInherited(Map, Object> inherited); + + abstract T getOverride(OptionValue option); + + abstract void getOverrides(OptionValue option, Collection c); + + public abstract void close(); + } + + static class SingleOverrideScope extends OverrideScope { + + private final OptionValue option; + private final Object value; + + public SingleOverrideScope(OptionValue option, Object value) { + if (option instanceof StableOptionValue) { + throw new IllegalArgumentException("Cannot override stable option " + option); + } + this.option = option; + this.value = value; + setOverrideScope(this); + } + + @Override + void addToInherited(Map, Object> inherited) { + inherited.put(option, value); + } + + @SuppressWarnings("unchecked") + @Override + T getOverride(OptionValue key) { + if (key == this.option) { + return (T) value; + } + return null; + } + + @Override + void getOverrides(OptionValue key, Collection c) { + if (key == this.option) { + c.add(value); + } + } + + @Override + public void close() { + setOverrideScope(null); + } + } + + static class MultipleOverridesScope extends OverrideScope { + final OverrideScope parent; + final Map, Object> overrides; + + public MultipleOverridesScope(OverrideScope parent, OptionValue option, Object value) { + this.parent = parent; + this.overrides = new HashMap<>(); + if (parent != null) { + parent.addToInherited(overrides); + } + if (option instanceof StableOptionValue) { + throw new IllegalArgumentException("Cannot override stable option " + option); + } + if (!value.equals(option.getValue())) { + this.overrides.put(option, value); + } + if (!overrides.isEmpty()) { + setOverrideScope(this); + } + } + + MultipleOverridesScope(OverrideScope parent, Map, Object> overrides) { + this.parent = parent; + if (overrides.isEmpty() && parent == null) { + this.overrides = Collections.emptyMap(); + return; + } + this.overrides = new HashMap<>(); + if (parent != null) { + parent.addToInherited(this.overrides); + } + for (Map.Entry, Object> e : overrides.entrySet()) { + OptionValue option = e.getKey(); + if (option instanceof StableOptionValue) { + throw new IllegalArgumentException("Cannot override stable option " + option); + } + if (!e.getValue().equals(option.getValue())) { + this.overrides.put(option, e.getValue()); + } + } + if (!this.overrides.isEmpty()) { + setOverrideScope(this); + } + } + + @Override + void addToInherited(Map, Object> inherited) { + if (parent != null) { + parent.addToInherited(inherited); + } + inherited.putAll(overrides); + } + + @SuppressWarnings("unchecked") + @Override + T getOverride(OptionValue option) { + return (T) overrides.get(option); + } + + @Override + void getOverrides(OptionValue option, Collection c) { + Object v = overrides.get(option); + if (v != null) { + c.add(v); + } + if (parent != null) { + parent.getOverrides(option, c); + } + } + + @Override + public void close() { + if (!overrides.isEmpty()) { + setOverrideScope(parent); + } + } + } + + static { + if (ShowReadsHistogram) { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + ArrayList> options = new ArrayList<>(); + for (OptionValue option = head; option != null; option = option.next) { + options.add(option); + } + Collections.sort(options, new Comparator>() { + + public int compare(OptionValue o1, OptionValue o2) { + if (o1.reads < o2.reads) { + return -1; + } else if (o1.reads > o2.reads) { + return 1; + } else { + return o1.getName().compareTo(o2.getName()); + } + } + }); + PrintStream out = System.out; + out.println("=== OptionValue reads histogram ==="); + for (OptionValue option : options) { + out.println(option.reads + "\t" + option); + } + } + }); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsLoader.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.options; + +import java.util.*; + +/** + * Helper class used to load option descriptors. Only to be used in the slow-path. + */ +public class OptionsLoader { + public static final SortedMap options = new TreeMap<>(); + + /** + * Initializes {@link #options} from {@link Options} services. + */ + static { + for (OptionDescriptors opts : ServiceLoader.load(OptionDescriptors.class, OptionsLoader.class.getClassLoader())) { + for (OptionDescriptor desc : opts) { + String name = desc.getName(); + OptionDescriptor existing = options.put(name, desc); + assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation(); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/OptionsParser.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.options; + +import static jdk.vm.ci.inittimer.InitTimer.*; + +import java.io.*; +import java.util.*; + +import jdk.vm.ci.inittimer.*; + +/** + * This class contains methods for parsing JVMCI options and matching them against a set of + * {@link OptionDescriptors}. The {@link OptionDescriptors} are loaded from JVMCI jars, either + * {@linkplain JVMCIJarsOptionDescriptorsProvider directly} or via a {@link ServiceLoader}. + */ +public class OptionsParser { + + private static final OptionValue PrintFlags = new OptionValue<>(false); + + /** + * A service for looking up {@link OptionDescriptor}s. + */ + public interface OptionDescriptorsProvider { + /** + * Gets the {@link OptionDescriptor} matching a given option {@linkplain Option#name() name} + * or null if no option of that name is provided by this object. + */ + OptionDescriptor get(String name); + } + + public interface OptionConsumer { + void set(OptionDescriptor desc, Object value); + } + + /** + * Parses the options in {@code /lib/jvmci/options} if {@code parseOptionsFile == true} and + * the file exists followed by the JVMCI options in {@code options} if {@code options != null}. + * + * Called from VM. This method has an object return type to allow it to be called with a VM + * utility function used to call other static initialization methods. + * + * @param options JVMCI options as serialized (name, value) pairs + * @param parseOptionsFile specifies whether to look for and parse + * {@code /lib/jvmci/options} + */ + @SuppressWarnings("try") + public static Boolean parseOptionsFromVM(String[] options, boolean parseOptionsFile) { + try (InitTimer t = timer("ParseOptions")) { + JVMCIJarsOptionDescriptorsProvider odp = new JVMCIJarsOptionDescriptorsProvider(); + + if (parseOptionsFile) { + File javaHome = new File(System.getProperty("java.home")); + File lib = new File(javaHome, "lib"); + File jvmci = new File(lib, "jvmci"); + File jvmciOptions = new File(jvmci, "options"); + if (jvmciOptions.exists()) { + try (BufferedReader br = new BufferedReader(new FileReader(jvmciOptions))) { + String optionSetting = null; + int lineNo = 1; + while ((optionSetting = br.readLine()) != null) { + if (!optionSetting.isEmpty() && optionSetting.charAt(0) != '#') { + try { + parseOptionSetting(optionSetting, null, odp); + } catch (Throwable e) { + throw new InternalError("Error parsing " + jvmciOptions + ", line " + lineNo, e); + } + } + lineNo++; + } + } catch (IOException e) { + throw new InternalError("Error reading " + jvmciOptions, e); + } + } + } + + if (options != null) { + assert options.length % 2 == 0; + for (int i = 0; i < options.length / 2; i++) { + String name = options[i * 2]; + String value = options[i * 2 + 1]; + parseOption(OptionsLoader.options, name, value, null, odp); + } + } + } + return Boolean.TRUE; + } + + /** + * Parses a given option setting. + * + * @param optionSetting a string matching the pattern {@code =} + * @param setter the object to notify of the parsed option and value + */ + public static void parseOptionSetting(String optionSetting, OptionConsumer setter, OptionDescriptorsProvider odp) { + int eqIndex = optionSetting.indexOf('='); + if (eqIndex == -1) { + throw new InternalError("Option setting has does not match the pattern =: " + optionSetting); + } + String name = optionSetting.substring(0, eqIndex); + String value = optionSetting.substring(eqIndex + 1); + parseOption(OptionsLoader.options, name, value, setter, odp); + } + + /** + * Parses a given option name and value. + * + * @param options + * @param name the option name + * @param valueString the option value as a string + * @param setter the object to notify of the parsed option and value + * @param odp + * + * @throws IllegalArgumentException if there's a problem parsing {@code option} + */ + public static void parseOption(SortedMap options, String name, String valueString, OptionConsumer setter, OptionDescriptorsProvider odp) { + OptionDescriptor desc = options.get(name); + if (desc == null && odp != null) { + desc = odp.get(name); + } + if (desc == null && name.equals("PrintFlags")) { + desc = OptionDescriptor.create("PrintFlags", Boolean.class, "Prints all JVMCI flags and exits", OptionsParser.class, "PrintFlags", PrintFlags); + } + if (desc == null) { + List matches = fuzzyMatch(options, name); + Formatter msg = new Formatter(); + msg.format("Could not find option %s", name); + if (!matches.isEmpty()) { + msg.format("%nDid you mean one of the following?"); + for (OptionDescriptor match : matches) { + msg.format("%n %s=", match.getName()); + } + } + throw new IllegalArgumentException(msg.toString()); + } + + Class optionType = desc.getType(); + Object value; + if (optionType == Boolean.class) { + if ("true".equals(valueString)) { + value = Boolean.TRUE; + } else if ("false".equals(valueString)) { + value = Boolean.FALSE; + } else { + throw new IllegalArgumentException("Boolean option '" + name + "' must have value \"true\" or \"false\", not \"" + valueString + "\""); + } + } else if (optionType == Float.class) { + value = Float.parseFloat(valueString); + } else if (optionType == Double.class) { + value = Double.parseDouble(valueString); + } else if (optionType == Integer.class) { + value = Integer.valueOf((int) parseLong(valueString)); + } else if (optionType == Long.class) { + value = Long.valueOf(parseLong(valueString)); + } else if (optionType == String.class) { + value = valueString; + } else { + throw new IllegalArgumentException("Wrong value for option '" + name + "'"); + } + if (setter == null) { + desc.getOptionValue().setValue(value); + } else { + setter.set(desc, value); + } + + if (PrintFlags.getValue()) { + printFlags(options, "JVMCI", System.out); + System.exit(0); + } + } + + private static long parseLong(String v) { + String valueString = v.toLowerCase(); + long scale = 1; + if (valueString.endsWith("k")) { + scale = 1024L; + } else if (valueString.endsWith("m")) { + scale = 1024L * 1024L; + } else if (valueString.endsWith("g")) { + scale = 1024L * 1024L * 1024L; + } else if (valueString.endsWith("t")) { + scale = 1024L * 1024L * 1024L * 1024L; + } + + if (scale != 1) { + /* Remove trailing scale character. */ + valueString = valueString.substring(0, valueString.length() - 1); + } + + return Long.parseLong(valueString) * scale; + } + + /** + * Wraps some given text to one or more lines of a given maximum width. + * + * @param text text to wrap + * @param width maximum width of an output line, exception for words in {@code text} longer than + * this value + * @return {@code text} broken into lines + */ + private static List wrap(String text, int width) { + List lines = Collections.singletonList(text); + if (text.length() > width) { + String[] chunks = text.split("\\s+"); + lines = new ArrayList<>(); + StringBuilder line = new StringBuilder(); + for (String chunk : chunks) { + if (line.length() + chunk.length() > width) { + lines.add(line.toString()); + line.setLength(0); + } + if (line.length() != 0) { + line.append(' '); + } + String[] embeddedLines = chunk.split("%n", -2); + if (embeddedLines.length == 1) { + line.append(chunk); + } else { + for (int i = 0; i < embeddedLines.length; i++) { + line.append(embeddedLines[i]); + if (i < embeddedLines.length - 1) { + lines.add(line.toString()); + line.setLength(0); + } + } + } + } + if (line.length() != 0) { + lines.add(line.toString()); + } + } + return lines; + } + + public static void printFlags(SortedMap sortedOptions, String prefix, PrintStream out) { + out.println("[List of " + prefix + " options]"); + for (Map.Entry e : sortedOptions.entrySet()) { + e.getKey(); + OptionDescriptor desc = e.getValue(); + Object value = desc.getOptionValue().getValue(); + List helpLines = wrap(desc.getHelp(), 70); + out.println(String.format("%9s %-40s = %-14s %s", desc.getType().getSimpleName(), e.getKey(), value, helpLines.get(0))); + for (int i = 1; i < helpLines.size(); i++) { + out.println(String.format("%67s %s", " ", helpLines.get(i))); + } + } + } + + /** + * Compute string similarity based on Dice's coefficient. + * + * Ported from str_similar() in globals.cpp. + */ + static float stringSimiliarity(String str1, String str2) { + int hit = 0; + for (int i = 0; i < str1.length() - 1; ++i) { + for (int j = 0; j < str2.length() - 1; ++j) { + if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) { + ++hit; + break; + } + } + } + return 2.0f * hit / (str1.length() + str2.length()); + } + + private static final float FUZZY_MATCH_THRESHOLD = 0.7F; + + /** + * Returns the set of options that fuzzy match a given option name. + */ + private static List fuzzyMatch(SortedMap options, String optionName) { + List matches = new ArrayList<>(); + for (Map.Entry e : options.entrySet()) { + float score = stringSimiliarity(e.getKey(), optionName); + if (score >= FUZZY_MATCH_THRESHOLD) { + matches.add(e.getValue()); + } + } + return matches; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/StableOptionValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.options/src/jdk/vm/ci/options/StableOptionValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.options; + +/** + * An option that always returns the same {@linkplain #getValue() value}. + */ +public class StableOptionValue extends OptionValue { + + /** + * Creates a stable option value. + */ + public StableOptionValue(T value) { + super(value); + } + + /** + * Used to assert the invariant for stability. Without using locks, this check is not safe + * against races and so it's only an assertion. + */ + private boolean getValueCalled; + + /** + * Creates an uninitialized stable option value for a subclass that initializes itself + * {@link #defaultValue() lazily}. + */ + public StableOptionValue() { + } + + /** + * Gets the value of this option. + */ + @Override + public final T getValue() { + T result = super.getValue(); + assert initGetValueCalled(); + return result; + } + + private boolean initGetValueCalled() { + getValueCalled = true; + return true; + } + + /** + * {@inheritDoc} + *

      + * This must only be called if {@link #getValue()} has never been called. + */ + @Override + public final void setValue(Object v) { + assert !getValueCalled; + super.setValue(v); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.runtime; + +import java.util.*; + +public class JVMCI { + + private static final JVMCIRuntime runtime; + + private static native JVMCIRuntime initializeRuntime(); + + public static void initialize() { + // force static initializer + } + + /** + * Gets the singleton {@link JVMCIRuntime} instance available to the application. + * + * @throws UnsupportedOperationException if JVMCI is not supported + */ + public static JVMCIRuntime getRuntime() { + if (runtime == null) { + String javaHome = System.getProperty("java.home"); + String vmName = System.getProperty("java.vm.name"); + Formatter errorMessage = new Formatter(); + errorMessage.format("The VM does not support the JVMCI API.%n"); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s", vmName); + throw new UnsupportedOperationException(errorMessage.toString()); + } + return runtime; + } + + static { + JVMCIRuntime rt = null; + try { + rt = initializeRuntime(); + } catch (UnsatisfiedLinkError e) { + } + runtime = rt; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIBackend.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIBackend.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.runtime; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.meta.*; + +/** + * A JVMCI backend encapsulates the capabilities needed by a Java based compiler for compiling and + * installing code for a single compute unit within a JVM. In a JVM with support for heterogeneous + * computing, more than one backend may be exposed. + */ +public class JVMCIBackend { + + private final MetaAccessProvider metaAccess; + private final CodeCacheProvider codeCache; + private final ConstantReflectionProvider constantReflection; + + public JVMCIBackend(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection) { + this.metaAccess = metaAccess; + this.codeCache = codeCache; + this.constantReflection = constantReflection; + } + + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + + public CodeCacheProvider getCodeCache() { + return codeCache; + } + + public ConstantReflectionProvider getConstantReflection() { + return constantReflection; + } + + public TargetDescription getTarget() { + return codeCache.getTarget(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIRuntime.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIRuntime.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.runtime; + +import jdk.vm.ci.code.*; + +/** + * Interface for accessing the {@link JVMCI} APIs supported by the runtime. + */ +public interface JVMCIRuntime { + + /** + * Gets the host JVMCI backend. + */ + JVMCIBackend getHostJVMCIBackend(); + + /** + * Gets the backend for a given architecture. + * + * @param arch a specific architecture class + */ + JVMCIBackend getJVMCIBackend(Class arch); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/META-INF/services/javax.annotation.processing.Processor --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/META-INF/services/javax.annotation.processing.Processor Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +jdk.vm.ci.service.processor.ServiceProviderProcessor diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/jdk/vm/ci/service/processor/ServiceProviderProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service.processor/src/jdk/vm/ci/service/processor/ServiceProviderProcessor.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.service.processor; + +import java.io.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.tools.Diagnostic.Kind; + +import jdk.vm.ci.service.*; + +import javax.tools.*; + +@SupportedAnnotationTypes("jdk.vm.ci.service.ServiceProvider") +public class ServiceProviderProcessor extends AbstractProcessor { + + private final Set processed = new HashSet<>(); + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + private boolean verifyAnnotation(TypeMirror serviceInterface, TypeElement serviceProvider) { + if (!processingEnv.getTypeUtils().isSubtype(serviceProvider.asType(), serviceInterface)) { + String msg = String.format("Service provider class %s must implement service interface %s", serviceProvider.getSimpleName(), serviceInterface); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); + return false; + } + + return true; + } + + private void processElement(TypeElement serviceProvider) { + if (processed.contains(serviceProvider)) { + return; + } + + processed.add(serviceProvider); + ServiceProvider annotation = serviceProvider.getAnnotation(ServiceProvider.class); + if (annotation != null) { + try { + annotation.value(); + } catch (MirroredTypeException ex) { + TypeMirror serviceInterface = ex.getTypeMirror(); + if (verifyAnnotation(serviceInterface, serviceProvider)) { + String interfaceName = ex.getTypeMirror().toString(); + createProviderFile(serviceProvider, interfaceName); + } + } + } + } + + private void createProviderFile(TypeElement serviceProvider, String interfaceName) { + if (serviceProvider.getNestingKind().isNested()) { + // This is a simplifying constraint that means we don't have to + // processed the qualified name to insert '$' characters at + // the relevant positions. + String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); + return; + } + + String filename = "META-INF/jvmci.providers/" + serviceProvider.getQualifiedName(); + try { + FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, serviceProvider); + PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8")); + writer.println(interfaceName); + writer.close(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Kind.ERROR, e.getMessage(), serviceProvider); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return true; + } + + for (Element element : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) { + assert element.getKind().isClass(); + processElement((TypeElement) element); + } + + return true; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/.checkstyle_checks.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/.checkstyle_checks.xml Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/ServiceProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/ServiceProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.service; + +import java.lang.annotation.*; + +/** + * Annotates a service provider than can be loaded via {@linkplain Services#load(Class)} or + * {@link Services#loadSingle(Class, boolean)}. + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface ServiceProvider { + + Class value(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/Services.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.service/src/jdk/vm/ci/service/Services.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.service; + +import java.util.*; + +/** + * A mechanism for accessing service providers via JVMCI. + */ +public final class Services { + + private Services() { + } + + /** + * Gets an {@link Iterable} of the JVMCI providers available for a given service. + */ + public static Iterable load(Class service) { + return ServiceLoader.load(service); + } + + /** + * Gets the JVMCI provider for a given service for which at most one provider must be available. + * + * @param service the service whose provider is being requested + * @param required specifies if an {@link InternalError} should be thrown if no provider of + * {@code service} is available + */ + public static S loadSingle(Class service, boolean required) { + Iterable providers = ServiceLoader.load(service); + S singleProvider = null; + try { + for (Iterator it = providers.iterator(); it.hasNext();) { + singleProvider = it.next(); + if (it.hasNext()) { + throw new InternalError(String.format("Multiple %s providers found", service.getName())); + } + } + } catch (ServiceConfigurationError e) { + // If the service is required we will bail out below. + } + if (singleProvider == null && required) { + String javaHome = System.getProperty("java.home"); + String vmName = System.getProperty("java.vm.name"); + Formatter errorMessage = new Formatter(); + errorMessage.format("The VM does not expose required service %s.%n", service.getName()); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s", vmName); + throw new UnsupportedOperationException(errorMessage.toString()); + } + return singleProvider; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.sparc; + +import static java.nio.ByteOrder.*; +import static jdk.vm.ci.code.MemoryBarriers.*; + +import java.util.*; + +import jdk.vm.ci.code.*; +import jdk.vm.ci.code.Register.RegisterCategory; +import jdk.vm.ci.meta.*; + +/** + * Represents the SPARC architecture. + */ +public class SPARC extends Architecture { + + public static final RegisterCategory CPU = new RegisterCategory("CPU"); + + // General purpose registers + public static final Register r0 = new Register(0, 0, "g0", CPU); + public static final Register r1 = new Register(1, 1, "g1", CPU); + public static final Register r2 = new Register(2, 2, "g2", CPU); + public static final Register r3 = new Register(3, 3, "g3", CPU); + public static final Register r4 = new Register(4, 4, "g4", CPU); + public static final Register r5 = new Register(5, 5, "g5", CPU); + public static final Register r6 = new Register(6, 6, "g6", CPU); + public static final Register r7 = new Register(7, 7, "g7", CPU); + + public static final Register r8 = new Register(8, 8, "o0", CPU); + public static final Register r9 = new Register(9, 9, "o1", CPU); + public static final Register r10 = new Register(10, 10, "o2", CPU); + public static final Register r11 = new Register(11, 11, "o3", CPU); + public static final Register r12 = new Register(12, 12, "o4", CPU); + public static final Register r13 = new Register(13, 13, "o5", CPU); + public static final Register r14 = new Register(14, 14, "o6", CPU); + public static final Register r15 = new Register(15, 15, "o7", CPU); + + public static final Register r16 = new Register(16, 16, "l0", CPU); + public static final Register r17 = new Register(17, 17, "l1", CPU); + public static final Register r18 = new Register(18, 18, "l2", CPU); + public static final Register r19 = new Register(19, 19, "l3", CPU); + public static final Register r20 = new Register(20, 20, "l4", CPU); + public static final Register r21 = new Register(21, 21, "l5", CPU); + public static final Register r22 = new Register(22, 22, "l6", CPU); + public static final Register r23 = new Register(23, 23, "l7", CPU); + + public static final Register r24 = new Register(24, 24, "i0", CPU); + public static final Register r25 = new Register(25, 25, "i1", CPU); + public static final Register r26 = new Register(26, 26, "i2", CPU); + public static final Register r27 = new Register(27, 27, "i3", CPU); + public static final Register r28 = new Register(28, 28, "i4", CPU); + public static final Register r29 = new Register(29, 29, "i5", CPU); + public static final Register r30 = new Register(30, 30, "i6", CPU); + public static final Register r31 = new Register(31, 31, "i7", CPU); + + public static final Register g0 = r0; + public static final Register g1 = r1; + public static final Register g2 = r2; + public static final Register g3 = r3; + public static final Register g4 = r4; + public static final Register g5 = r5; + public static final Register g6 = r6; + public static final Register g7 = r7; + + public static final Register o0 = r8; + public static final Register o1 = r9; + public static final Register o2 = r10; + public static final Register o3 = r11; + public static final Register o4 = r12; + public static final Register o5 = r13; + public static final Register o6 = r14; + public static final Register o7 = r15; + + public static final Register l0 = r16; + public static final Register l1 = r17; + public static final Register l2 = r18; + public static final Register l3 = r19; + public static final Register l4 = r20; + public static final Register l5 = r21; + public static final Register l6 = r22; + public static final Register l7 = r23; + + public static final Register i0 = r24; + public static final Register i1 = r25; + public static final Register i2 = r26; + public static final Register i3 = r27; + public static final Register i4 = r28; + public static final Register i5 = r29; + public static final Register i6 = r30; + public static final Register i7 = r31; + + public static final Register sp = o6; + public static final Register fp = i6; + + // @formatter:off + public static final Register[] cpuRegisters = { + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, r29, r30, r31 + }; + // @formatter:on + + public static final RegisterCategory FPUs = new RegisterCategory("FPUs", cpuRegisters.length); + public static final RegisterCategory FPUd = new RegisterCategory("FPUd", cpuRegisters.length + 32); + + // Floating point registers + public static final Register f0 = new Register(32, 0, "f0", FPUs); + public static final Register f1 = new Register(33, 1, "f1", FPUs); + public static final Register f2 = new Register(34, 2, "f2", FPUs); + public static final Register f3 = new Register(35, 3, "f3", FPUs); + public static final Register f4 = new Register(36, 4, "f4", FPUs); + public static final Register f5 = new Register(37, 5, "f5", FPUs); + public static final Register f6 = new Register(38, 6, "f6", FPUs); + public static final Register f7 = new Register(39, 7, "f7", FPUs); + + public static final Register f8 = new Register(40, 8, "f8", FPUs); + public static final Register f9 = new Register(41, 9, "f9", FPUs); + public static final Register f10 = new Register(42, 10, "f10", FPUs); + public static final Register f11 = new Register(43, 11, "f11", FPUs); + public static final Register f12 = new Register(44, 12, "f12", FPUs); + public static final Register f13 = new Register(45, 13, "f13", FPUs); + public static final Register f14 = new Register(46, 14, "f14", FPUs); + public static final Register f15 = new Register(47, 15, "f15", FPUs); + + public static final Register f16 = new Register(48, 16, "f16", FPUs); + public static final Register f17 = new Register(49, 17, "f17", FPUs); + public static final Register f18 = new Register(50, 18, "f18", FPUs); + public static final Register f19 = new Register(51, 19, "f19", FPUs); + public static final Register f20 = new Register(52, 20, "f20", FPUs); + public static final Register f21 = new Register(53, 21, "f21", FPUs); + public static final Register f22 = new Register(54, 22, "f22", FPUs); + public static final Register f23 = new Register(55, 23, "f23", FPUs); + + public static final Register f24 = new Register(56, 24, "f24", FPUs); + public static final Register f25 = new Register(57, 25, "f25", FPUs); + public static final Register f26 = new Register(58, 26, "f26", FPUs); + public static final Register f27 = new Register(59, 27, "f27", FPUs); + public static final Register f28 = new Register(60, 28, "f28", FPUs); + public static final Register f29 = new Register(61, 29, "f29", FPUs); + public static final Register f30 = new Register(62, 30, "f30", FPUs); + public static final Register f31 = new Register(63, 31, "f31", FPUs); + + public static final Register d0 = new Register(32, getDoubleEncoding(0), "d0", FPUs); + public static final Register d2 = new Register(34, getDoubleEncoding(2), "d2", FPUs); + public static final Register d4 = new Register(36, getDoubleEncoding(4), "d4", FPUs); + public static final Register d6 = new Register(38, getDoubleEncoding(6), "d6", FPUs); + public static final Register d8 = new Register(40, getDoubleEncoding(8), "d8", FPUs); + public static final Register d10 = new Register(42, getDoubleEncoding(10), "d10", FPUs); + public static final Register d12 = new Register(44, getDoubleEncoding(12), "d12", FPUs); + public static final Register d14 = new Register(46, getDoubleEncoding(14), "d14", FPUs); + + public static final Register d16 = new Register(48, getDoubleEncoding(16), "d16", FPUs); + public static final Register d18 = new Register(50, getDoubleEncoding(18), "d18", FPUs); + public static final Register d20 = new Register(52, getDoubleEncoding(20), "d20", FPUs); + public static final Register d22 = new Register(54, getDoubleEncoding(22), "d22", FPUs); + public static final Register d24 = new Register(56, getDoubleEncoding(24), "d24", FPUs); + public static final Register d26 = new Register(58, getDoubleEncoding(26), "d26", FPUs); + public static final Register d28 = new Register(60, getDoubleEncoding(28), "d28", FPUs); + public static final Register d30 = new Register(62, getDoubleEncoding(28), "d28", FPUs); + + public static final Register d32 = new Register(64, getDoubleEncoding(32), "d32", FPUd); + public static final Register d34 = new Register(65, getDoubleEncoding(34), "d34", FPUd); + public static final Register d36 = new Register(66, getDoubleEncoding(36), "d36", FPUd); + public static final Register d38 = new Register(67, getDoubleEncoding(38), "d38", FPUd); + public static final Register d40 = new Register(68, getDoubleEncoding(40), "d40", FPUd); + public static final Register d42 = new Register(69, getDoubleEncoding(42), "d42", FPUd); + public static final Register d44 = new Register(70, getDoubleEncoding(44), "d44", FPUd); + public static final Register d46 = new Register(71, getDoubleEncoding(46), "d46", FPUd); + + public static final Register d48 = new Register(72, getDoubleEncoding(48), "d48", FPUd); + public static final Register d50 = new Register(73, getDoubleEncoding(50), "d50", FPUd); + public static final Register d52 = new Register(74, getDoubleEncoding(52), "d52", FPUd); + public static final Register d54 = new Register(75, getDoubleEncoding(54), "d54", FPUd); + public static final Register d56 = new Register(76, getDoubleEncoding(56), "d56", FPUd); + public static final Register d58 = new Register(77, getDoubleEncoding(58), "d58", FPUd); + public static final Register d60 = new Register(78, getDoubleEncoding(60), "d60", FPUd); + public static final Register d62 = new Register(79, getDoubleEncoding(62), "d62", FPUd); + + // @formatter:off + public static final Register[] fpuRegisters = { + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + + // @formatter:off + public static final Register[] allRegisters = { + // CPU + r0, r1, r2, r3, r4, r5, r6, r7, + r8, r9, r10, r11, r12, r13, r14, r15, + r16, r17, r18, r19, r20, r21, r22, r23, + r24, r25, r26, r27, r28, r29, r30, r31, + // FPU + f0, f1, f2, f3, f4, f5, f6, f7, + f8, f9, f10, f11, f12, f13, f14, f15, + f16, f17, f18, f19, f20, f21, f22, f23, + f24, f25, f26, f27, f28, f29, f30, f31, + d32, d34, d36, d38, d40, d42, d44, d46, + d48, d50, d52, d54, d56, d58, d60, d62 + }; + // @formatter:on + + /** + * Stack bias for stack and frame pointer loads. + */ + public static final int STACK_BIAS = 0x7ff; + /** + * In fact there are 64 single floating point registers, 32 of them could be accessed. TODO: + * Improve handling of these float registers + */ + public static final int FLOAT_REGISTER_COUNT = 64; + + /** + * Alignment for valid memory access. + */ + public static final int MEMORY_ACCESS_ALIGN = 4; + + public static final int INSTRUCTION_SIZE = 4; + + /** + * Size to keep free for flushing the register-window to stack. + */ + public static final int REGISTER_SAFE_AREA_SIZE = 128; + + public final Set features; + + public SPARC(Set features) { + super("SPARC", JavaKind.Long, BIG_ENDIAN, false, allRegisters, LOAD_LOAD | LOAD_STORE | STORE_STORE, 1, r31.encoding + FLOAT_REGISTER_COUNT + 1, 8); + this.features = features; + } + + @Override + public boolean canStoreValue(RegisterCategory category, PlatformKind lirKind) { + if (!(lirKind instanceof JavaKind)) { + return false; + } + + JavaKind kind = (JavaKind) lirKind; + if (category.equals(CPU)) { + switch (kind) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: + case Long: + return true; + } + } else if (category.equals(FPUs) && kind.equals(JavaKind.Float)) { + return true; + } else if (category.equals(FPUd) && kind.equals(JavaKind.Double)) { + return true; + } + return false; + } + + @Override + public PlatformKind getLargestStorableKind(RegisterCategory category) { + if (category.equals(CPU)) { + return JavaKind.Long; + } else if (category.equals(FPUd)) { + return JavaKind.Double; + } else if (category.equals(FPUs)) { + return JavaKind.Float; + } else { + return JavaKind.Illegal; + } + } + + @Override + public PlatformKind getPlatformKind(JavaKind javaKind) { + if (javaKind.isObject()) { + return JavaKind.Long; + } else { + return javaKind; + } + } + + public static int spillSlotSize(TargetDescription td, PlatformKind kind) { + return Math.max(td.getSizeInBytes(kind), MEMORY_ACCESS_ALIGN); + } + + public static int getDoubleEncoding(int reg) { + assert reg < 64 && ((reg & 1) == 0); + // ignore v8 assertion for now + return (reg & 0x1e) | ((reg & 0x20) >> 5); + } + + public static boolean isCPURegister(Register r) { + return r.getRegisterCategory().equals(CPU); + } + + public static boolean isCPURegister(Register... regs) { + for (Register reg : regs) { + if (!isCPURegister(reg)) { + return false; + } + } + return true; + } + + public static boolean isGlobalRegister(Register r) { + return isCPURegister(r) && g0.number <= r.number && r.number <= g7.number; + } + + public static boolean isSingleFloatRegister(Register r) { + return r.name.startsWith("f"); + } + + public static boolean isDoubleFloatRegister(Register r) { + return r.name.startsWith("d"); + } + + public Set getFeatures() { + return features; + } + + public boolean hasFeature(CPUFeature feature) { + return features.contains(feature); + } + + public enum CPUFeature { + VIS1, + VIS2, + VIS3, + CBCOND, + BLOCK_ZEROING + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/aix/vm/os_aix.cpp --- a/hotspot/src/os/aix/vm/os_aix.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/aix/vm/os_aix.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -2286,7 +2286,7 @@ if (!pd_commit_memory(addr, size, exec)) { // Add extra info in product mode for vm_exit_out_of_memory(): PRODUCT_ONLY(warn_fail_commit_memory(addr, size, exec, errno);) - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -3120,8 +3120,8 @@ // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. } else { - fatal(err_msg("Encountered unexpected pre-existing sigaction handler " - "%#lx for signal %d.", (long)oldhand, sig)); + fatal("Encountered unexpected pre-existing sigaction handler " + "%#lx for signal %d.", (long)oldhand, sig); } } @@ -3699,7 +3699,7 @@ void os::make_polling_page_readable(void) { // Changed according to os_linux.cpp. if (!checked_mprotect((char *)_polling_page, Aix::page_size(), PROT_READ)) { - fatal(err_msg("Could not enable polling page at " PTR_FORMAT, _polling_page)); + fatal("Could not enable polling page at " PTR_FORMAT, _polling_page); } }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/aix/vm/vmError_aix.cpp --- a/hotspot/src/os/aix/vm/vmError_aix.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/aix/vm/vmError_aix.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -117,8 +117,7 @@ return; } - VMError err(NULL, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(NULL, sig, pc, info, ucVoid); } void VMError::reset_signal_handlers() { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/aix/vm/vmStructs_aix.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/os/aix/vm/vmStructs_aix.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_AIX_VM_VMSTRUCTS_AIX_HPP +#define OS_AIX_VM_VMSTRUCTS_AIX_HPP + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) + +#endif // OS_AIX_VM_VMSTRUCTS_AIX_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/bsd/vm/os_bsd.cpp --- a/hotspot/src/os/bsd/vm/os_bsd.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -128,8 +128,6 @@ #define LARGEPAGES_BIT (1 << 6) -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - //////////////////////////////////////////////////////////////////////////////// // global variables julong os::Bsd::_physical_memory = 0; @@ -1977,7 +1975,7 @@ OSXSemaphore::OSXSemaphore(uint value) { kern_return_t ret = SEM_INIT(_semaphore, value); - guarantee(ret == KERN_SUCCESS, err_msg("Failed to create semaphore: %s", sem_init_strerror(ret))); + guarantee(ret == KERN_SUCCESS, "Failed to create semaphore: %s", sem_init_strerror(ret)); } OSXSemaphore::~OSXSemaphore() { @@ -2213,7 +2211,7 @@ if (!pd_commit_memory(addr, size, exec)) { // add extra info in product mode for vm_exit_out_of_memory(): PRODUCT_ONLY(warn_fail_commit_memory(addr, size, exec, errno);) - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -3100,8 +3098,8 @@ // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. } else { - fatal(err_msg("Encountered unexpected pre-existing sigaction handler " - "%#lx for signal %d.", (long)oldhand, sig)); + fatal("Encountered unexpected pre-existing sigaction handler " + "%#lx for signal %d.", (long)oldhand, sig); } } @@ -3459,8 +3457,7 @@ Bsd::set_page_size(getpagesize()); if (Bsd::page_size() == -1) { - fatal(err_msg("os_bsd.cpp: os::init: sysconf failed (%s)", - strerror(errno))); + fatal("os_bsd.cpp: os::init: sysconf failed (%s)", strerror(errno)); } init_page_sizes((size_t) Bsd::page_size()); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/bsd/vm/vmError_bsd.cpp --- a/hotspot/src/os/bsd/vm/vmError_bsd.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/bsd/vm/vmError_bsd.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -121,8 +121,7 @@ return; } - VMError err(NULL, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(NULL, sig, pc, info, ucVoid); } void VMError::reset_signal_handlers() { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/bsd/vm/vmStructs_bsd.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/os/bsd/vm/vmStructs_bsd.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_BSD_VM_VMSTRUCTS_BSD_HPP +#define OS_BSD_VM_VMSTRUCTS_BSD_HPP + +#include + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // OS_BSD_VM_VMSTRUCTS_BSD_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/linux/vm/os_linux.cpp --- a/hotspot/src/os/linux/vm/os_linux.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/linux/vm/os_linux.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -106,8 +106,6 @@ # include # include -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // if RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling // getrusage() is prepared to handle the associated failure. #ifndef RUSAGE_THREAD @@ -1969,7 +1967,8 @@ char name[PATH_MAX + 1]; // Parse fields from line - sscanf(line, "%lx-%lx %4s %lx %5s %ld %s", &base, &top, permissions, &offset, device, &inode, name); + sscanf(line, UINT64_FORMAT_X "-" UINT64_FORMAT_X " %4s " UINT64_FORMAT_X " %5s " INT64_FORMAT " %s", + &base, &top, permissions, &offset, device, &inode, name); // Filter by device id '00:00' so that we only get file system mapped files. if (strcmp(device, "00:00") != 0) { @@ -2632,7 +2631,7 @@ static void warn_fail_commit_memory(char* addr, size_t size, bool exec, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT - ", %d) failed; error='%s' (errno=%d)", addr, size, exec, + ", %d) failed; error='%s' (errno=%d)", p2i(addr), size, exec, strerror(err), err); } @@ -2640,7 +2639,7 @@ size_t alignment_hint, bool exec, int err) { warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT - ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, size, + ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", p2i(addr), size, alignment_hint, exec, strerror(err), err); } @@ -2680,7 +2679,7 @@ if (err != 0) { // the caller wants all commit errors to exit with the specified mesg: warn_fail_commit_memory(addr, size, exec, err); - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -2716,7 +2715,7 @@ if (err != 0) { // the caller wants all commit errors to exit with the specified mesg: warn_fail_commit_memory(addr, size, alignment_hint, exec, err); - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -4278,8 +4277,8 @@ // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. } else { - fatal(err_msg("Encountered unexpected pre-existing sigaction handler " - "%#lx for signal %d.", (long)oldhand, sig)); + fatal("Encountered unexpected pre-existing sigaction handler " + "%#lx for signal %d.", (long)oldhand, sig); } } @@ -4611,8 +4610,8 @@ Linux::set_page_size(sysconf(_SC_PAGESIZE)); if (Linux::page_size() == -1) { - fatal(err_msg("os_linux.cpp: os::init: sysconf failed (%s)", - strerror(errno))); + fatal("os_linux.cpp: os::init: sysconf failed (%s)", + strerror(errno)); } init_page_sizes((size_t) Linux::page_size()); @@ -4628,7 +4627,7 @@ int status; pthread_condattr_t* _condattr = os::Linux::condAttr(); if ((status = pthread_condattr_init(_condattr)) != 0) { - fatal(err_msg("pthread_condattr_init: %s", strerror(status))); + fatal("pthread_condattr_init: %s", strerror(status)); } // Only set the clock if CLOCK_MONOTONIC is available if (os::supports_monotonic_clock()) { @@ -4637,7 +4636,7 @@ warning("Unable to use monotonic clock with relative timed-waits" \ " - changes to the time-of-day clock may have adverse affects"); } else { - fatal(err_msg("pthread_condattr_setclock: %s", strerror(status))); + fatal("pthread_condattr_setclock: %s", strerror(status)); } } } @@ -4717,7 +4716,7 @@ if (threadStackSizeInBytes != 0 && threadStackSizeInBytes < os::Linux::min_stack_allowed) { tty->print_cr("\nThe stack size specified is too small, " - "Specify at least %dk", + "Specify at least " SIZE_FORMAT "k", os::Linux::min_stack_allowed/ K); return JNI_ERR; } @@ -4918,12 +4917,12 @@ Dl_info dlinfo; memset(&dlinfo, 0, sizeof(dlinfo)); if (dladdr(addr, &dlinfo) != 0) { - st->print(PTR_FORMAT ": ", addr); + st->print(PTR_FORMAT ": ", p2i(addr)); if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) { - st->print("%s+%#x", dlinfo.dli_sname, - addr - (intptr_t)dlinfo.dli_saddr); + st->print("%s+" PTR_FORMAT, dlinfo.dli_sname, + p2i(addr) - p2i(dlinfo.dli_saddr)); } else if (dlinfo.dli_fbase != NULL) { - st->print("", addr - (intptr_t)dlinfo.dli_fbase); + st->print("", p2i(addr) - p2i(dlinfo.dli_fbase)); } else { st->print(""); } @@ -4931,7 +4930,7 @@ st->print(" in %s", dlinfo.dli_fname); } if (dlinfo.dli_fbase != NULL) { - st->print(" at " PTR_FORMAT, dlinfo.dli_fbase); + st->print(" at " PTR_FORMAT, p2i(dlinfo.dli_fbase)); } st->cr(); @@ -5323,7 +5322,7 @@ void os::pause() { char filename[MAX_PATH]; if (PauseAtStartupFile && PauseAtStartupFile[0]) { - jio_snprintf(filename, MAX_PATH, PauseAtStartupFile); + jio_snprintf(filename, MAX_PATH, "%s", PauseAtStartupFile); } else { jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id()); } @@ -5959,7 +5958,7 @@ int written; if (core_pattern[0] == '/') { - written = jio_snprintf(buffer, bufferSize, core_pattern); + written = jio_snprintf(buffer, bufferSize, "%s", core_pattern); } else { char cwd[PATH_MAX]; @@ -6095,7 +6094,7 @@ for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) { char* p = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, NULL, false); test_log(SIZE_FORMAT_HEX " " SIZE_FORMAT_HEX " -> " PTR_FORMAT " %s", - size, alignment, p, (p != NULL ? "" : "(failed)")); + size, alignment, p2i(p), (p != NULL ? "" : "(failed)")); if (p != NULL) { assert(is_ptr_aligned(p, alignment), "must be"); small_page_write(p, size); @@ -6114,8 +6113,8 @@ char* const req_addr = (char*) align_ptr_up(mapping1, alignment); char* p = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, req_addr, false); test_log(SIZE_FORMAT_HEX " " SIZE_FORMAT_HEX " " PTR_FORMAT " -> " PTR_FORMAT " %s", - size, alignment, req_addr, p, - ((p != NULL ? (p == req_addr ? "(exact match)" : "") : "(failed)"))); + size, alignment, p2i(req_addr), p2i(p), + ((p != NULL ? (p == req_addr ? "(exact match)" : "") : "(failed)"))); if (p != NULL) { assert(p == req_addr, "must be"); small_page_write(p, size); @@ -6134,8 +6133,7 @@ char* const req_addr = (char*) align_ptr_up(mapping2, alignment); char* p = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, req_addr, false); test_log(SIZE_FORMAT_HEX " " SIZE_FORMAT_HEX " " PTR_FORMAT " -> " PTR_FORMAT " %s", - size, alignment, req_addr, p, - ((p != NULL ? "" : "(failed)"))); + size, alignment, p2i(req_addr), p2i(p), ((p != NULL ? "" : "(failed)"))); // as the area around req_addr contains already existing mappings, the API should always // return NULL (as per contract, it cannot return another address) assert(p == NULL, "must be"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/linux/vm/vmError_linux.cpp --- a/hotspot/src/os/linux/vm/vmError_linux.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/linux/vm/vmError_linux.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -121,8 +121,7 @@ return; } - VMError err(NULL, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(NULL, sig, pc, info, ucVoid); } void VMError::reset_signal_handlers() { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/linux/vm/vmStructs_linux.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/os/linux/vm/vmStructs_linux.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_LINUX_VM_VMSTRUCTS_LINUX_HPP +#define OS_LINUX_VM_VMSTRUCTS_LINUX_HPP + +#include + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // OS_LINUX_VM_VMSTRUCTS_LINUX_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/posix/vm/os_posix.cpp --- a/hotspot/src/os/posix/vm/os_posix.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/posix/vm/os_posix.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -38,8 +38,6 @@ #include #include -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Todo: provide a os::get_max_process_id() or similar. Number of processes // may have been configured, can be read more accurately from proc fs etc. #ifndef MAX_PID @@ -194,30 +192,30 @@ st->print(" STACK "); getrlimit(RLIMIT_STACK, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%uk", rlim.rlim_cur >> 10); + else st->print("%luk", rlim.rlim_cur >> 10); st->print(", CORE "); getrlimit(RLIMIT_CORE, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%uk", rlim.rlim_cur >> 10); + else st->print("%luk", rlim.rlim_cur >> 10); // Isn't there on solaris #if !defined(TARGET_OS_FAMILY_solaris) && !defined(TARGET_OS_FAMILY_aix) st->print(", NPROC "); getrlimit(RLIMIT_NPROC, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%d", rlim.rlim_cur); + else st->print("%lu", rlim.rlim_cur); #endif st->print(", NOFILE "); getrlimit(RLIMIT_NOFILE, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%d", rlim.rlim_cur); + else st->print("%lu", rlim.rlim_cur); st->print(", AS "); getrlimit(RLIMIT_AS, &rlim); if (rlim.rlim_cur == RLIM_INFINITY) st->print("infinity"); - else st->print("%uk", rlim.rlim_cur >> 10); + else st->print("%luk", rlim.rlim_cur >> 10); st->cr(); } @@ -961,7 +959,7 @@ } } else if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGTRAP || sig == SIGFPE) { - os->print(", si_addr: " PTR_FORMAT, si->si_addr); + os->print(", si_addr: " PTR_FORMAT, p2i(si->si_addr)); #ifdef SIGPOLL } else if (sig == SIGPOLL) { os->print(", si_band: " PTR64_FORMAT, (uint64_t)si->si_band); @@ -1027,10 +1025,10 @@ } } -#define check_with_errno(check_type, cond, msg) \ - do { \ - int err = errno; \ - check_type(cond, err_msg("%s; error='%s' (errno=%d)", msg, strerror(err), err)); \ +#define check_with_errno(check_type, cond, msg) \ + do { \ + int err = errno; \ + check_type(cond, "%s; error='%s' (errno=%d)", msg, strerror(err), err); \ } while (false) #define assert_with_errno(cond, msg) check_with_errno(assert, cond, msg) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1118,8 +1118,7 @@ void _handle_uncaught_cxx_exception() { - VMError err("An uncaught C++ exception"); - err.report_and_die(); + VMError::report_and_die("An uncaught C++ exception"); } @@ -1330,7 +1329,7 @@ jlong os::javaTimeMillis() { timeval t; if (gettimeofday(&t, NULL) == -1) { - fatal(err_msg("os::javaTimeMillis: gettimeofday (%s)", strerror(errno))); + fatal("os::javaTimeMillis: gettimeofday (%s)", strerror(errno)); } return jlong(t.tv_sec) * 1000 + jlong(t.tv_usec) / 1000; } @@ -1338,7 +1337,7 @@ void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { timeval t; if (gettimeofday(&t, NULL) == -1) { - fatal(err_msg("os::javaTimeSystemUTC: gettimeofday (%s)", strerror(errno))); + fatal("os::javaTimeSystemUTC: gettimeofday (%s)", strerror(errno)); } seconds = jlong(t.tv_sec); nanos = jlong(t.tv_usec) * 1000; @@ -2392,14 +2391,14 @@ if (err != 0) { // the caller wants all commit errors to exit with the specified mesg: warn_fail_commit_memory(addr, bytes, exec, err); - vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); } } size_t os::Solaris::page_size_for_alignment(size_t alignment) { assert(is_size_aligned(alignment, (size_t) vm_page_size()), - err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, - alignment, (size_t) vm_page_size())); + SIZE_FORMAT " is not aligned to " SIZE_FORMAT, + alignment, (size_t) vm_page_size()); for (int i = 0; _page_sizes[i] != 0; i++) { if (is_size_aligned(alignment, _page_sizes[i])) { @@ -2415,7 +2414,7 @@ int err = Solaris::commit_memory_impl(addr, bytes, exec); if (err == 0 && UseLargePages && alignment_hint > 0) { assert(is_size_aligned(bytes, alignment_hint), - err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint)); + SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint); // The syscall memcntl requires an exact page size (see man memcntl for details). size_t page_size = page_size_for_alignment(alignment_hint); @@ -2439,7 +2438,7 @@ if (err != 0) { // the caller wants all commit errors to exit with the specified mesg: warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err); - vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); } } @@ -2969,11 +2968,11 @@ } bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) { - assert(is_valid_page_size(align), err_msg(SIZE_FORMAT " is not a valid page size", align)); + assert(is_valid_page_size(align), SIZE_FORMAT " is not a valid page size", align); assert(is_ptr_aligned((void*) start, align), - err_msg(PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align)); + PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align); assert(is_size_aligned(bytes, align), - err_msg(SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align)); + SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align); // Signal to OS that we want large pages for addresses // from addr, addr + bytes @@ -3956,8 +3955,8 @@ // libjsig also interposes the sigaction() call below and saves the // old sigaction on it own. } else { - fatal(err_msg("Encountered unexpected pre-existing sigaction handler " - "%#lx for signal %d.", (long)oldhand, sig)); + fatal("Encountered unexpected pre-existing sigaction handler " + "%#lx for signal %d.", (long)oldhand, sig); } } @@ -4403,8 +4402,7 @@ page_size = sysconf(_SC_PAGESIZE); if (page_size == -1) { - fatal(err_msg("os_solaris.cpp: os::init: sysconf failed (%s)", - strerror(errno))); + fatal("os_solaris.cpp: os::init: sysconf failed (%s)", strerror(errno)); } init_page_sizes((size_t) page_size); @@ -4416,7 +4414,7 @@ int fd = ::open("/dev/zero", O_RDWR); if (fd < 0) { - fatal(err_msg("os::init: cannot open /dev/zero (%s)", strerror(errno))); + fatal("os::init: cannot open /dev/zero (%s)", strerror(errno)); } else { Solaris::set_dev_zero_fd(fd); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/solaris/vm/threadCritical_solaris.cpp --- a/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -48,8 +48,8 @@ thread_t owner = thr_self(); if (global_mut_owner != owner) { if (os::Solaris::mutex_lock(&global_mut)) - fatal(err_msg("ThreadCritical::ThreadCritical: mutex_lock failed (%s)", - strerror(errno))); + fatal("ThreadCritical::ThreadCritical: mutex_lock failed (%s)", + strerror(errno)); assert(global_mut_count == 0, "must have clean count"); assert(global_mut_owner == -1, "must have clean owner"); } @@ -68,8 +68,7 @@ if (global_mut_count == 0) { global_mut_owner = -1; if (os::Solaris::mutex_unlock(&global_mut)) - fatal(err_msg("ThreadCritical::~ThreadCritical: mutex_unlock failed " - "(%s)", strerror(errno))); + fatal("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", strerror(errno)); } } else { assert (Threads::number_of_threads() == 0, "valid only during initialization"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/solaris/vm/vmError_solaris.cpp --- a/hotspot/src/os/solaris/vm/vmError_solaris.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/solaris/vm/vmError_solaris.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -117,8 +117,7 @@ return; } - VMError err(NULL, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(NULL, sig, pc, info, ucVoid); } void VMError::reset_signal_handlers() { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/solaris/vm/vmStructs_solaris.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/os/solaris/vm/vmStructs_solaris.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_SOLARIS_VM_VMSTRUCTS_SOLARIS_HPP +#define OS_SOLARIS_VM_VMSTRUCTS_SOLARIS_HPP + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_unsigned_integer_type(OSThread::thread_id_t) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) + +#endif // OS_SOLARIS_VM_VMSTRUCTS_SOLARIS_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/windows/vm/os_windows.cpp --- a/hotspot/src/os/windows/vm/os_windows.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/windows/vm/os_windows.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -823,7 +823,7 @@ java_origin.wMilliseconds = 0; FILETIME jot; if (!SystemTimeToFileTime(&java_origin, &jot)) { - fatal(err_msg("Error = %d\nWindows error", GetLastError())); + fatal("Error = %d\nWindows error", GetLastError()); } _calculated_offset = jlong_from(jot.dwHighDateTime, jot.dwLowDateTime); _has_calculated_offset = 1; @@ -1936,7 +1936,7 @@ WindowsSemaphore::WindowsSemaphore(uint value) { _semaphore = ::CreateSemaphore(NULL, value, LONG_MAX, NULL); - guarantee(_semaphore != NULL, err_msg("CreateSemaphore failed with error code: %lu", GetLastError())); + guarantee(_semaphore != NULL, "CreateSemaphore failed with error code: %lu", GetLastError()); } WindowsSemaphore::~WindowsSemaphore() { @@ -1947,14 +1947,14 @@ if (count > 0) { BOOL ret = ::ReleaseSemaphore(_semaphore, count, NULL); - assert(ret != 0, err_msg("ReleaseSemaphore failed with error code: %lu", GetLastError())); + assert(ret != 0, "ReleaseSemaphore failed with error code: %lu", GetLastError()); } } void WindowsSemaphore::wait() { DWORD ret = ::WaitForSingleObject(_semaphore, INFINITE); - assert(ret != WAIT_FAILED, err_msg("WaitForSingleObject failed with error code: %lu", GetLastError())); - assert(ret == WAIT_OBJECT_0, err_msg("WaitForSingleObject failed with return value: %lu", ret)); + assert(ret != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); + assert(ret == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", ret); } // sun.misc.Signal @@ -2272,12 +2272,17 @@ #ifdef _M_AMD64 PCONTEXT ctx = exceptionInfo->ContextRecord; address pc = (address)ctx->Rip; - assert(pc[0] == 0xF7, "not an idiv opcode"); - assert((pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); - assert(ctx->Rax == min_jint, "unexpected idiv exception"); - // set correct result values and continue after idiv instruction - ctx->Rip = (DWORD)pc + 2; // idiv reg, reg is 2 bytes - ctx->Rax = (DWORD)min_jint; // result + assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && pc[1] == 0xF7 || pc[0] == 0xF7, "not an idiv opcode"); + assert(pc[0] >= Assembler::REX && pc[0] <= Assembler::REX_WRXB && (pc[2] & ~0x7) == 0xF8 || (pc[1] & ~0x7) == 0xF8, "cannot handle non-register operands"); + if (pc[0] == 0xF7) { + // set correct result values and continue after idiv instruction + ctx->Rip = (DWORD64)pc + 2; // idiv reg, reg is 2 bytes + } else { + ctx->Rip = (DWORD64)pc + 3; // REX idiv reg, reg is 3 bytes + } + // Do not set ctx->Rax as it already contains the correct value (either 32 or 64 bit, depending on the operation) + // this is the case because the exception only happens for -MinValue/-1 and -MinValue is always in rax because of the + // idiv opcode (0xF7). ctx->Rdx = (DWORD)0; // remainder // Continue the execution #else @@ -2344,8 +2349,7 @@ static inline void report_error(Thread* t, DWORD exception_code, address addr, void* siginfo, void* context) { - VMError err(t, exception_code, addr, siginfo, context); - err.report_and_die(); + VMError::report_and_die(t, exception_code, addr, siginfo, context); // If UseOsErrorReporting, this will return here and save the error file // somewhere where we can find it in the minidump. @@ -3325,7 +3329,7 @@ assert(mesg != NULL, "mesg must be specified"); if (!pd_commit_memory(addr, size, exec)) { warn_fail_commit_memory(addr, size, exec); - vm_exit_out_of_memory(size, OOM_MMAP_ERROR, mesg); + vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "%s", mesg); } } @@ -5259,7 +5263,7 @@ } DWORD err = GetLastError(); if (err != ERROR_NO_MORE_ITEMS && err != ERROR_CALL_NOT_IMPLEMENTED) { - fatal(err_msg("heap walk aborted with error %d", err)); + fatal("heap walk aborted with error %d", err); } HeapUnlock(heap); } @@ -5978,8 +5982,8 @@ os::release_memory_special(actual_location, expected_allocation_size); // only now check, after releasing any memory to avoid any leaks. assert(actual_location == expected_location, - err_msg("Failed to allocate memory at requested location " PTR_FORMAT " of size " SIZE_FORMAT ", is " PTR_FORMAT " instead", - expected_location, expected_allocation_size, actual_location)); + "Failed to allocate memory at requested location " PTR_FORMAT " of size " SIZE_FORMAT ", is " PTR_FORMAT " instead", + expected_location, expected_allocation_size, actual_location); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/windows/vm/vmError_windows.cpp --- a/hotspot/src/os/windows/vm/vmError_windows.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os/windows/vm/vmError_windows.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -70,9 +70,8 @@ LONG WINAPI crash_handler(struct _EXCEPTION_POINTERS* exceptionInfo) { DWORD exception_code = exceptionInfo->ExceptionRecord->ExceptionCode; - VMError err(NULL, exception_code, NULL, - exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); - err.report_and_die(); + VMError::report_and_die(NULL, exception_code, NULL, exceptionInfo->ExceptionRecord, + exceptionInfo->ContextRecord); return EXCEPTION_CONTINUE_SEARCH; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os/windows/vm/vmStructs_windows.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/os/windows/vm/vmStructs_windows.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_WINDOWS_VM_VMSTRUCTS_WINDOWS_HPP +#define OS_WINDOWS_VM_VMSTRUCTS_WINDOWS_HPP + +// These are the OS-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) + +#endif // OS_WINDOWS_VM_VMSTRUCTS_WINDOWS_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp --- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -468,8 +468,7 @@ sigaddset(&newset, sig); sigthreadmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return 0; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -276,8 +276,6 @@ # endif #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - address os::current_stack_pointer() { #if defined(__clang__) || defined(__llvm__) register void *esp; @@ -731,8 +729,7 @@ sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return false; @@ -865,7 +862,7 @@ int rslt = pthread_stackseg_np(pthread_self(), &ss); if (rslt != 0) - fatal(err_msg("pthread_stackseg_np failed with err = %d", rslt)); + fatal("pthread_stackseg_np failed with err = %d", rslt); *bottom = (address)((char *)ss.ss_sp - ss.ss_size); *size = ss.ss_size; @@ -876,12 +873,12 @@ // JVM needs to know exact stack location, abort if it fails if (rslt != 0) - fatal(err_msg("pthread_attr_init failed with err = %d", rslt)); + fatal("pthread_attr_init failed with err = %d", rslt); rslt = pthread_attr_get_np(pthread_self(), &attr); if (rslt != 0) - fatal(err_msg("pthread_attr_get_np failed with err = %d", rslt)); + fatal("pthread_attr_get_np failed with err = %d", rslt); if (pthread_attr_getstackaddr(&attr, (void **)bottom) != 0 || pthread_attr_getstacksize(&attr, size) != 0) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp --- a/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -66,8 +66,8 @@ frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { -#ifdef COMPILER2 - // C2 uses ebp as a general register see if NULL fp helps +#if defined(COMPILER2) || INCLUDE_JVMCI + // C2 and JVMCI use ebp as a general register see if NULL fp helps frame ret_frame2(ret_sp, NULL, addr.pc()); if (!ret_frame2.safe_for_sender(jt)) { // nothing else to try if the frame isn't good @@ -77,7 +77,7 @@ #else // nothing else to try if the frame isn't good return false; -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ } *fr_addr = ret_frame; return true; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp --- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -320,8 +320,7 @@ int rslt = pthread_stackseg_np(pthread_self(), &ss); if (rslt != 0) - fatal(err_msg("pthread_stackseg_np failed with err = " INT32_FORMAT, - rslt)); + fatal("pthread_stackseg_np failed with err = " INT32_FORMAT, rslt); stack_top = (address) ss.ss_sp; stack_bytes = ss.ss_size; @@ -333,13 +332,12 @@ // JVM needs to know exact stack location, abort if it fails if (rslt != 0) - fatal(err_msg("pthread_attr_init failed with err = " INT32_FORMAT, rslt)); + fatal("pthread_attr_init failed with err = " INT32_FORMAT, rslt); rslt = pthread_attr_get_np(pthread_self(), &attr); if (rslt != 0) - fatal(err_msg("pthread_attr_get_np failed with err = " INT32_FORMAT, - rslt)); + fatal("pthread_attr_get_np failed with err = " INT32_FORMAT, rslt); if (pthread_attr_getstackaddr(&attr, (void **) &stack_bottom) != 0 || pthread_attr_getstacksize(&attr, &stack_bytes) != 0) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp --- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -464,8 +464,7 @@ sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return true; // Mute compiler @@ -558,7 +557,7 @@ if (rslt == ENOMEM) { vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt)); + fatal("pthread_getattr_np failed with errno = %d", rslt); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp --- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -439,8 +439,7 @@ sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return false; @@ -531,7 +530,7 @@ if (rslt == ENOMEM) { vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt)); + fatal("pthread_getattr_np failed with errno = %d", rslt); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -172,7 +172,7 @@ if (rslt == ENOMEM) { vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt)); + fatal("pthread_getattr_np failed with errno = %d", rslt); } } @@ -692,8 +692,7 @@ sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -89,8 +89,6 @@ #define SPELL_REG_FP "ebp" #endif // AMD64 -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - address os::current_stack_pointer() { #ifdef SPARC_WORKS register void *esp; @@ -542,8 +540,7 @@ sigaddset(&newset, sig); sigprocmask(SIG_UNBLOCK, &newset, NULL); - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return true; // Mute compiler @@ -689,7 +686,7 @@ if (rslt == ENOMEM) { vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt)); + fatal("pthread_getattr_np failed with errno = %d", rslt); } } @@ -728,32 +725,32 @@ ucontext_t *uc = (ucontext_t*)context; st->print_cr("Registers:"); #ifdef AMD64 - st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); - st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); - st->print(", RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]); - st->print(", RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]); + st->print( "RAX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RAX]); + st->print(", RBX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RBX]); + st->print(", RCX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RCX]); + st->print(", RDX=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RDX]); st->cr(); - st->print( "RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]); - st->print(", RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]); - st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); - st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); + st->print( "RSP=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RSP]); + st->print(", RBP=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RBP]); + st->print(", RSI=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RSI]); + st->print(", RDI=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RDI]); st->cr(); - st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); - st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); - st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); - st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); + st->print( "R8 =" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R8]); + st->print(", R9 =" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R9]); + st->print(", R10=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R10]); + st->print(", R11=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R11]); st->cr(); - st->print( "R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]); - st->print(", R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]); - st->print(", R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]); - st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); + st->print( "R12=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R12]); + st->print(", R13=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R13]); + st->print(", R14=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R14]); + st->print(", R15=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_R15]); st->cr(); - st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); - st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); - st->print(", CSGSFS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_CSGSFS]); - st->print(", ERR=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ERR]); + st->print( "RIP=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_RIP]); + st->print(", EFLAGS=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_EFL]); + st->print(", CSGSFS=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_CSGSFS]); + st->print(", ERR=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_ERR]); st->cr(); - st->print(" TRAPNO=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_TRAPNO]); + st->print(" TRAPNO=" INTPTR_FORMAT, (intptr_t)uc->uc_mcontext.gregs[REG_TRAPNO]); #else st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]); st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]); @@ -767,13 +764,13 @@ st->cr(); st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]); st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); - st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2); + st->print(", CR2=" PTR64_FORMAT, (uint64_t)uc->uc_mcontext.cr2); #endif // AMD64 st->cr(); st->cr(); intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); - st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); + st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", p2i(sp)); print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t)); st->cr(); @@ -781,7 +778,7 @@ // point to garbage if entry point in an nmethod is corrupted. Leave // this at the end, and hope for the best. address pc = os::Linux::ucontext_get_pc(uc); - st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); + st->print_cr("Instructions: (pc=" PTR_FORMAT ")", p2i(pc)); print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp --- a/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -67,8 +67,8 @@ frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { -#ifdef COMPILER2 - // C2 uses ebp as a general register see if NULL fp helps +#if defined(COMPILER2) || INCLUDE_JVMCI + // C2 and JVMCI use ebp as a general register see if NULL fp helps frame ret_frame2(ret_sp, NULL, addr.pc()); if (!ret_frame2.safe_for_sender(jt)) { // nothing else to try if the frame isn't good @@ -78,7 +78,7 @@ #else // nothing else to try if the frame isn't good return false; -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ } *fr_addr = ret_frame; return true; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp --- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -328,7 +328,7 @@ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "pthread_getattr_np"); } else { - fatal(err_msg("pthread_getattr_np failed with errno = %d", res)); + fatal("pthread_getattr_np failed with errno = %d", res); } } @@ -336,7 +336,7 @@ size_t stack_bytes; res = pthread_attr_getstack(&attr, (void **) &stack_bottom, &stack_bytes); if (res != 0) { - fatal(err_msg("pthread_attr_getstack failed with errno = %d", res)); + fatal("pthread_attr_getstack failed with errno = %d", res); } address stack_top = stack_bottom + stack_bytes; @@ -348,7 +348,7 @@ size_t guard_bytes; res = pthread_attr_getguardsize(&attr, &guard_bytes); if (res != 0) { - fatal(err_msg("pthread_attr_getguardsize failed with errno = %d", res)); + fatal("pthread_attr_getguardsize failed with errno = %d", res); } int guard_pages = align_size_up(guard_bytes, page_bytes) / page_bytes; assert(guard_bytes == guard_pages * page_bytes, "unaligned guard"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -24,6 +24,7 @@ // no precompiled headers #include "asm/macroAssembler.hpp" +#include "macroAssembler_sparc.hpp" #include "classfile/classLoader.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -549,8 +550,7 @@ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack."); } - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,29 +30,11 @@ // referenced by vmStructs.cpp. #define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) + nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Solaris Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) - +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ - \ - /************************/ \ - /* JavaThread constants */ \ - /************************/ \ - \ declare_constant(JavaFrameAnchor::flushed) #define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -707,8 +707,7 @@ vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack."); } - VMError err(t, sig, pc, info, ucVoid); - err.report_and_die(); + VMError::report_and_die(t, sig, pc, info, ucVoid); ShouldNotReachHere(); return false; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp --- a/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,21 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Solaris Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp --- a/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -74,8 +74,8 @@ frame ret_frame(ret_sp, ret_fp, addr.pc()); if (!ret_frame.safe_for_sender(jt)) { -#ifdef COMPILER2 - // C2 uses ebp as a general register see if NULL fp helps +#if defined(COMPILER2) || INCLUDE_JVMCI + // C2 and JVMCI use ebp as a general register see if NULL fp helps frame ret_frame2(ret_sp, NULL, addr.pc()); if (!ret_frame2.safe_for_sender(jt)) { // nothing else to try if the frame isn't good @@ -85,7 +85,7 @@ #else // nothing else to try if the frame isn't good return false; -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ } *fr_addr = ret_frame; return true; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/Xusage.txt --- a/hotspot/src/share/vm/Xusage.txt Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/Xusage.txt Thu Oct 22 11:13:08 2015 -0700 @@ -7,6 +7,7 @@ -Xbootclasspath/p: prepend in front of bootstrap class path -Xnoclassgc disable class garbage collection + -Xlog: control JVM logging, use -Xlog:help for details -Xloggc: log GC status to a file with time stamps -Xbatch disable background compilation -Xms set initial Java heap size diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/adlc/formsopt.cpp --- a/hotspot/src/share/vm/adlc/formsopt.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/adlc/formsopt.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -234,7 +234,6 @@ } RegClass::~RegClass() { - delete _classid; } // record a register in this class diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/adlc/formssel.cpp --- a/hotspot/src/share/vm/adlc/formssel.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/adlc/formssel.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -4006,7 +4006,6 @@ strcmp(opType,"DivD")==0 || strcmp(opType,"DivF")==0 || strcmp(opType,"DivI")==0 || - strcmp(opType,"ExpD")==0 || strcmp(opType,"LogD")==0 || strcmp(opType,"Log10D")==0 || strcmp(opType,"ModD")==0 || @@ -4143,6 +4142,8 @@ "SubVB","SubVS","SubVI","SubVL","SubVF","SubVD", "MulVS","MulVI","MulVL","MulVF","MulVD", "DivVF","DivVD", + "AbsVF","AbsVD", + "NegVF","NegVD", "SqrtVD", "AndV" ,"XorV" ,"OrV", "AddReductionVI", "AddReductionVL", diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/asm/assembler.cpp --- a/hotspot/src/share/vm/asm/assembler.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/asm/assembler.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -43,8 +43,7 @@ CodeSection* cs = code->insts(); cs->clear_mark(); // new assembler kills old mark if (cs->start() == NULL) { - vm_exit_out_of_memory(0, OOM_MMAP_ERROR, err_msg("CodeCache: no room for %s", - code->name())); + vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "CodeCache: no room for %s", code->name()); } _code_section = cs; _oop_recorder= code->oop_recorder(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/asm/codeBuffer.cpp --- a/hotspot/src/share/vm/asm/codeBuffer.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -602,21 +602,19 @@ return (csize_t) align_size_up(total, HeapWordSize); } -csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { - address buf = NULL; +csize_t CodeBuffer::copy_relocations_to(address buf, csize_t buf_limit, bool only_inst) const { csize_t buf_offset = 0; - csize_t buf_limit = 0; - if (dest != NULL) { - buf = (address)dest->relocation_begin(); - buf_limit = (address)dest->relocation_end() - buf; - assert((uintptr_t)buf % HeapWordSize == 0, "buf must be fully aligned"); - assert(buf_limit % HeapWordSize == 0, "buf must be evenly sized"); - } - // if dest == NULL, this is just the sizing pass - csize_t code_end_so_far = 0; csize_t code_point_so_far = 0; + + assert((uintptr_t)buf % HeapWordSize == 0, "buf must be fully aligned"); + assert(buf_limit % HeapWordSize == 0, "buf must be evenly sized"); + for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) { + if (only_inst && (n != (int)SECT_INSTS)) { + // Need only relocation info for code. + continue; + } // pull relocs out of each section const CodeSection* cs = code_section(n); assert(!(cs->is_empty() && cs->locs_count() > 0), "sanity"); @@ -683,7 +681,23 @@ buf_offset += sizeof(relocInfo); } - assert(code_end_so_far == total_content_size(), "sanity"); + assert(only_inst || code_end_so_far == total_content_size(), "sanity"); + + return buf_offset; +} + +csize_t CodeBuffer::copy_relocations_to(CodeBlob* dest) const { + address buf = NULL; + csize_t buf_offset = 0; + csize_t buf_limit = 0; + + if (dest != NULL) { + buf = (address)dest->relocation_begin(); + buf_limit = (address)dest->relocation_end() - buf; + } + // if dest == NULL, this is just the sizing pass + // + buf_offset = copy_relocations_to(buf, buf_limit, false); // Account for index: if (buf != NULL) { @@ -1126,7 +1140,8 @@ while (c && c->offset() == offset) { stream->bol(); stream->print("%s", _prefix); - stream->print_cr("%s", c->string()); + // Don't interpret as format strings since it could contain % + stream->print_raw_cr(c->string()); c = c->next_comment(); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/asm/codeBuffer.hpp --- a/hotspot/src/share/vm/asm/codeBuffer.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/asm/codeBuffer.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -173,7 +173,7 @@ bool allocates(address pc) const { return pc >= _start && pc < _limit; } bool allocates2(address pc) const { return pc >= _start && pc <= _limit; } - void set_end(address pc) { assert(allocates2(pc), err_msg("not in CodeBuffer memory: " INTPTR_FORMAT " <= " INTPTR_FORMAT " <= " INTPTR_FORMAT, p2i(_start), p2i(pc), p2i(_limit))); _end = pc; } + void set_end(address pc) { assert(allocates2(pc), "not in CodeBuffer memory: " INTPTR_FORMAT " <= " INTPTR_FORMAT " <= " INTPTR_FORMAT, p2i(_start), p2i(pc), p2i(_limit)); _end = pc; } void set_mark(address pc) { assert(contains2(pc), "not in codeBuffer"); _mark = pc; } void set_mark_off(int offset) { assert(contains2(offset+_start),"not in codeBuffer"); @@ -375,6 +375,8 @@ OopRecorder _default_oop_recorder; // override with initialize_oop_recorder Arena* _overflow_arena; + address _last_membar; // used to merge consecutive memory barriers + address _decode_begin; // start address for decode address decode_begin(); @@ -388,6 +390,7 @@ _decode_begin = NULL; _overflow_arena = NULL; _code_strings = CodeStrings(); + _last_membar = NULL; } void initialize(address code_start, csize_t code_size) { @@ -452,7 +455,6 @@ initialize_misc(name); } - // (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. @@ -553,6 +555,8 @@ // allocated size of all relocation data, including index, rounded up csize_t total_relocation_size() const; + csize_t copy_relocations_to(address buf, csize_t buf_limit, bool only_inst) const; + // allocated size of any and all recorded oops csize_t total_oop_size() const { OopRecorder* recorder = oop_recorder(); @@ -576,6 +580,10 @@ OopRecorder* oop_recorder() const { return _oop_recorder; } CodeStrings& strings() { return _code_strings; } + address last_membar() const { return _last_membar; } + void set_last_membar(address a) { _last_membar = a; } + void clear_last_membar() { set_last_membar(NULL); } + void free_strings() { if (!_code_strings.is_null()) { _code_strings.free(); // sets _strings Null as a side-effect. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/asm/register.hpp --- a/hotspot/src/share/vm/asm/register.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/asm/register.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -121,8 +121,7 @@ ) { assert( a != b, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT "", - p2i(a), p2i(b)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT "", p2i(a), p2i(b) ); } @@ -135,9 +134,9 @@ assert( a != b && a != c && b != c, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c) ); } @@ -152,9 +151,9 @@ a != b && a != c && a != d && b != c && b != d && c != d, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d) ); } @@ -171,9 +170,9 @@ && b != c && b != d && b != e && c != d && c != e && d != e, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e) ); } @@ -192,10 +191,10 @@ && c != d && c != e && c != f && d != e && d != f && e != f, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f) ); } @@ -216,10 +215,10 @@ && d != e && d != f && d != g && e != f && e != g && f != g, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g) ); } @@ -242,10 +241,10 @@ && e != f && e != g && e != h && f != g && f != h && g != h, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h) ); } @@ -270,11 +269,11 @@ && f != g && f != h && f != i && g != h && g != i && h != i, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT - ", i=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i) ); } @@ -300,11 +299,11 @@ && g != h && g != i && g != j && h != i && h != j && i != j, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT - ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j) ); } @@ -332,11 +331,11 @@ && h != i && h != j && h !=k && i != j && i !=k && j !=k, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT - ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k) ); } @@ -366,12 +365,12 @@ && i != j && i !=k && i !=l && j !=k && j !=l && k !=l, - err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT - ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT - ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT - ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT - ", l=" INTPTR_FORMAT "", - p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k), p2i(l)) + "registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT + ", l=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k), p2i(l) ); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_Compilation.cpp --- a/hotspot/src/share/vm/c1/c1_Compilation.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -325,7 +325,8 @@ locs_buffer_size / sizeof(relocInfo)); code->initialize_consts_size(Compilation::desired_max_constant_size()); // Call stubs + two deopt handlers (regular and MH) + exception handler - int stub_size = (call_stub_estimate * LIR_Assembler::call_stub_size) + + int call_stub_size = LIR_Assembler::call_stub_size; + int stub_size = (call_stub_estimate * call_stub_size) + LIR_Assembler::exception_handler_size + (2 * LIR_Assembler::deopt_handler_size); if (stub_size >= code->insts_capacity()) return false; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_GraphBuilder.cpp --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -3363,11 +3363,9 @@ return NULL; } - // negative filter: should callee NOT be inlined? returns NULL, ok to inline, or rejection msg const char* GraphBuilder::should_not_inline(ciMethod* callee) const { - if ( callee->should_exclude()) return "excluded by CompilerOracle"; - if ( callee->should_not_inline()) return "disallowed by CompilerOracle"; + if ( callee->should_not_inline()) return "disallowed by CompileCommand"; if ( callee->dont_inline()) return "don't inline by annotation"; return NULL; } @@ -3698,7 +3696,7 @@ const char* msg = ""; if (callee->force_inline()) msg = "force inline by annotation"; - if (callee->should_inline()) msg = "force inline by CompileOracle"; + if (callee->should_inline()) msg = "force inline by CompileCommand"; print_inlining(callee, msg); } else { // use heuristic controls on inlining @@ -4020,7 +4018,7 @@ break; default: - fatal(err_msg("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } set_state(state_before); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_IR.hpp --- a/hotspot/src/share/vm/c1/c1_IR.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_IR.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -244,7 +244,8 @@ // reexecute allowed only for the topmost frame bool reexecute = topmost ? should_reexecute() : false; bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis. - recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, return_oop, locvals, expvals, monvals); + bool rethrow_exception = false; + recorder->describe_scope(pc_offset, methodHandle(), scope()->method(), bci(), reexecute, rethrow_exception, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_LIR.cpp --- a/hotspot/src/share/vm/c1/c1_LIR.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -732,8 +732,7 @@ case lir_sin: case lir_cos: case lir_log: - case lir_log10: - case lir_exp: { + case lir_log10: { assert(op->as_Op2() != NULL, "must be"); LIR_Op2* op2 = (LIR_Op2*)op; @@ -743,9 +742,6 @@ // overlap with the input. assert(op2->_info == NULL, "not used"); assert(op2->_tmp5->is_illegal(), "not used"); - assert(op2->_tmp2->is_valid() == (op->code() == lir_exp), "not used"); - assert(op2->_tmp3->is_valid() == (op->code() == lir_exp), "not used"); - assert(op2->_tmp4->is_valid() == (op->code() == lir_exp), "not used"); assert(op2->_opr1->is_valid(), "used"); do_input(op2->_opr1); do_temp(op2->_opr1); @@ -1775,7 +1771,6 @@ case lir_tan: s = "tan"; break; case lir_log: s = "log"; break; case lir_log10: s = "log10"; break; - case lir_exp: s = "exp"; break; case lir_pow: s = "pow"; break; case lir_logic_and: s = "logic_and"; break; case lir_logic_or: s = "logic_or"; break; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_LIR.hpp --- a/hotspot/src/share/vm/c1/c1_LIR.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -961,7 +961,6 @@ , lir_tan , lir_log , lir_log10 - , lir_exp , lir_pow , lir_logic_and , lir_logic_or @@ -2199,7 +2198,6 @@ void sin (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_sin , from, tmp1, to, tmp2)); } void cos (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_cos , from, tmp1, to, tmp2)); } void tan (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_tan , from, tmp1, to, tmp2)); } - void exp (LIR_Opr from, LIR_Opr to, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, LIR_Opr tmp4, LIR_Opr tmp5) { append(new LIR_Op2(lir_exp , from, tmp1, to, tmp2, tmp3, tmp4, tmp5)); } void pow (LIR_Opr arg1, LIR_Opr arg2, LIR_Opr res, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, LIR_Opr tmp4, LIR_Opr tmp5) { append(new LIR_Op2(lir_pow, arg1, arg2, res, tmp1, tmp2, tmp3, tmp4, tmp5)); } void add (LIR_Opr left, LIR_Opr right, LIR_Opr res) { append(new LIR_Op2(lir_add, left, right, res)); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_LIRAssembler.cpp --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -405,7 +405,8 @@ if (s == NULL) break; IRScope* scope = s->scope(); //Always pass false for reexecute since these ScopeDescs are never used for deopt - debug_info->describe_scope(pc_offset, scope->method(), s->bci(), false/*reexecute*/); + methodHandle null_mh; + debug_info->describe_scope(pc_offset, null_mh, scope->method(), s->bci(), false/*reexecute*/); } debug_info->end_non_safepoint(pc_offset); @@ -462,7 +463,7 @@ vtable_call(op); break; default: - fatal(err_msg_res("unexpected op code: %s", op->name())); + fatal("unexpected op code: %s", op->name()); break; } @@ -739,7 +740,6 @@ case lir_cos: case lir_log: case lir_log10: - case lir_exp: case lir_pow: intrinsic_op(op->code(), op->in_opr1(), op->in_opr2(), op->result_opr(), op); break; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_LIRGenerator.cpp --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -920,7 +920,7 @@ LIR_Opr LIRGenerator::force_to_spill(LIR_Opr value, BasicType t) { assert(type2size[t] == type2size[value->type()], - err_msg_res("size mismatch: t=%s, value->type()=%s", type2name(t), type2name(value->type()))); + "size mismatch: t=%s, value->type()=%s", type2name(t), type2name(value->type())); if (!value->is_register()) { // force into a register LIR_Opr r = new_register(value->type()); @@ -1630,6 +1630,9 @@ __ move(dirty, card_addr); __ branch_destination(L_already_dirty->label()); } else { + if (UseConcMarkSweepGC && CMSPrecleaningEnabled) { + __ membar_storestore(); + } __ move(dirty, card_addr); } #endif @@ -2829,7 +2832,7 @@ void LIRGenerator::invoke_load_arguments(Invoke* x, LIRItemList* args, const LIR_OprList* arg_list) { assert(args->length() == arg_list->length(), - err_msg_res("args=%d, arg_list=%d", args->length(), arg_list->length())); + "args=%d, arg_list=%d", args->length(), arg_list->length()); for (int i = x->has_receiver() ? 1 : 0; i < args->length(); i++) { LIRItem* param = args->at(i); LIR_Opr loc = arg_list->at(i); @@ -2973,7 +2976,7 @@ break; } default: - fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(x->code()))); + fatal("unexpected bytecode: %s", Bytecodes::name(x->code())); break; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_LIRGenerator.hpp --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -244,6 +244,7 @@ void do_getClass(Intrinsic* x); void do_currentThread(Intrinsic* x); void do_MathIntrinsic(Intrinsic* x); + void do_ExpIntrinsic(Intrinsic* x); void do_ArrayCopy(Intrinsic* x); void do_CompareAndSwap(Intrinsic* x, ValueType* type); void do_NIOCheckIndex(Intrinsic* x); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_LinearScan.cpp --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -6588,7 +6588,6 @@ case lir_log10: case lir_log: case lir_pow: - case lir_exp: case lir_logic_and: case lir_logic_or: case lir_logic_xor: diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_Runtime1.cpp --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -317,6 +317,7 @@ FUNCTION_CASE(entry, TRACE_TIME_METHOD); #endif FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32()); + FUNCTION_CASE(entry, StubRoutines::dexp()); #undef FUNCTION_CASE diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/c1/c1_globals.hpp --- a/hotspot/src/share/vm/c1/c1_globals.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/c1/c1_globals.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -152,6 +152,7 @@ \ product(intx, ValueMapMaxLoopSize, 8, \ "maximum size of a loop optimized by global value numbering") \ + range(0, 128) \ \ develop(bool, EliminateBlocks, true, \ "Eliminate unneccessary basic blocks") \ @@ -220,6 +221,7 @@ \ develop(intx, TraceLinearScanLevel, 0, \ "Debug levels for the linear scan allocator") \ + range(0, 4) \ \ develop(bool, StressLinearScan, false, \ "scramble block order used by LinearScan (stress test)") \ @@ -294,6 +296,7 @@ \ develop(intx, NMethodSizeLimit, (64*K)*wordSize, \ "Maximum size of a compiled method.") \ + range(0, max_jint) \ \ develop(bool, TraceFPUStack, false, \ "Trace emulation of the FPU stack (intel only)") \ @@ -309,6 +312,7 @@ \ develop(intx, InstructionCountCutoff, 37000, \ "If GraphBuilder adds this many instructions, bails out") \ + range(0, max_jint) \ \ develop(bool, ComputeExactFPURegisterUsage, true, \ "Compute additional live set for fpu registers to simplify fpu stack merge (Intel only)") \ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/ci/ciKlass.cpp --- a/hotspot/src/share/vm/ci/ciKlass.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciKlass.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -66,8 +66,8 @@ // ------------------------------------------------------------------ // ciKlass::is_subtype_of bool ciKlass::is_subtype_of(ciKlass* that) { - assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii())); - assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii())); + assert(this->is_loaded(), "must be loaded: %s", this->name()->as_quoted_ascii()); + assert(that->is_loaded(), "must be loaded: %s", that->name()->as_quoted_ascii()); // Check to see if the klasses are identical. if (this == that) { @@ -85,8 +85,8 @@ // ------------------------------------------------------------------ // ciKlass::is_subclass_of bool ciKlass::is_subclass_of(ciKlass* that) { - assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii())); - assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii())); + assert(this->is_loaded(), "must be loaded: %s", this->name()->as_quoted_ascii()); + assert(that->is_loaded(), "must be loaded: %s", that->name()->as_quoted_ascii()); VM_ENTRY_MARK; Klass* this_klass = get_Klass(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -576,13 +576,13 @@ void ciMethod::assert_virtual_call_type_ok(int bci) { assert(java_code_at_bci(bci) == Bytecodes::_invokevirtual || - java_code_at_bci(bci) == Bytecodes::_invokeinterface, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci)))); + java_code_at_bci(bci) == Bytecodes::_invokeinterface, "unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci))); } void ciMethod::assert_call_type_ok(int bci) { assert(java_code_at_bci(bci) == Bytecodes::_invokestatic || java_code_at_bci(bci) == Bytecodes::_invokespecial || - java_code_at_bci(bci) == Bytecodes::_invokedynamic, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci)))); + java_code_at_bci(bci) == Bytecodes::_invokedynamic, "unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci))); } /** @@ -1044,18 +1044,6 @@ } // ------------------------------------------------------------------ -// ciMethod::should_exclude -// -// Should this method be excluded from compilation? -bool ciMethod::should_exclude() { - check_is_loaded(); - VM_ENTRY_MARK; - methodHandle mh(THREAD, get_Method()); - bool ignore; - return CompilerOracle::should_exclude(mh, ignore); -} - -// ------------------------------------------------------------------ // ciMethod::should_inline // // Should this method be inlined during compilation? diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/ci/ciMethod.hpp --- a/hotspot/src/share/vm/ci/ciMethod.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciMethod.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -266,7 +266,6 @@ int resolve_vtable_index(ciKlass* caller, ciKlass* receiver); // Compilation directives - bool should_exclude(); bool should_inline(); bool should_not_inline(); bool should_print_assembly(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/ci/ciMethodData.cpp --- a/hotspot/src/share/vm/ci/ciMethodData.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciMethodData.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -122,7 +122,7 @@ // An empty slot or ArgInfoData entry marks the end of the trap data return; default: - fatal(err_msg("bad tag = %d", dp_dst->tag())); + fatal("bad tag = %d", dp_dst->tag()); } } } @@ -289,7 +289,7 @@ break; } default: - fatal(err_msg("bad tag = %d", dp->tag())); + fatal("bad tag = %d", dp->tag()); } } return NULL; @@ -578,7 +578,7 @@ break; } default: - fatal(err_msg("bad tag = %d", dp->tag())); + fatal("bad tag = %d", dp->tag()); } } } @@ -690,7 +690,7 @@ data = new ciSpeculativeTrapData(dp); break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } st->print("%d", dp_to_di(data->dp())); st->fill_to(6); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/ci/ciReplay.cpp --- a/hotspot/src/share/vm/ci/ciReplay.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciReplay.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -730,7 +730,7 @@ if (parsed_two_word == i) continue; default: - fatal(err_msg_res("Unexpected tag: %d", cp->tag_at(i).value())); + fatal("Unexpected tag: %d", cp->tag_at(i).value()); break; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/ci/ciTypeFlow.cpp --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1964,7 +1964,7 @@ _has_irreducible_entry = false; _osr_bci = osr_bci; _failure_reason = NULL; - assert(0 <= start_bci() && start_bci() < code_size() , err_msg("correct osr_bci argument: 0 <= %d < %d", start_bci(), code_size())); + assert(0 <= start_bci() && start_bci() < code_size() , "correct osr_bci argument: 0 <= %d < %d", start_bci(), code_size()); _work_list = NULL; _ciblock_count = _methodBlocks->num_blocks(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/altHashing.cpp --- a/hotspot/src/share/vm/classfile/altHashing.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/altHashing.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -262,10 +262,9 @@ juint final_hash = murmur3_32(hashes, 4*256); assert (MURMUR3_32_X86_CHECK_VALUE == final_hash, - err_msg( - "Calculated hash result not as expected. Expected %08X got %08X\n", - MURMUR3_32_X86_CHECK_VALUE, - final_hash)); + "Calculated hash result not as expected. Expected %08X got %08X\n", + MURMUR3_32_X86_CHECK_VALUE, + final_hash); } void AltHashing::testEquivalentHashes() { @@ -276,24 +275,24 @@ jbytes = murmur3_32(TWO_BYTE, 2); jchars = murmur3_32(ONE_CHAR, 1); assert (jbytes == jchars, - err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars)); + "Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars); jbytes = murmur3_32(FOUR_BYTE, 4); jchars = murmur3_32(TWO_CHAR, 2); ints = murmur3_32(ONE_INT, 1); assert ((jbytes == jchars) && (jbytes == ints), - err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints)); + "Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints); jbytes = murmur3_32(SIX_BYTE, 6); jchars = murmur3_32(THREE_CHAR, 3); assert (jbytes == jchars, - err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars)); + "Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars); jbytes = murmur3_32(EIGHT_BYTE, 8); jchars = murmur3_32(FOUR_CHAR, 4); ints = murmur3_32(TWO_INT, 2); assert ((jbytes == jchars) && (jbytes == ints), - err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints)); + "Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints); } // Returns true if the alternate hashcode is correct diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -319,12 +319,12 @@ PRAGMA_FORMAT_NONLITERAL_IGNORED void ClassFileParser::report_assert_property_failure(const char* msg, TRAPS) { ResourceMark rm(THREAD); - fatal(err_msg(msg, _class_name->as_C_string())); + fatal(msg, _class_name->as_C_string()); } void ClassFileParser::report_assert_property_failure(const char* msg, int index, TRAPS) { ResourceMark rm(THREAD); - fatal(err_msg(msg, index, _class_name->as_C_string())); + fatal(msg, index, _class_name->as_C_string()); } PRAGMA_DIAG_POP @@ -492,8 +492,7 @@ break; } default: - fatal(err_msg("bad constant pool tag value %u", - cp->tag_at(index).value())); + fatal("bad constant pool tag value %u", cp->tag_at(index).value()); ShouldNotReachHere(); break; } // end of switch @@ -1755,6 +1754,12 @@ if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_HotSpotIntrinsicCandidate; +#if INCLUDE_JVMCI + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_vm_ci_hotspot_Stable_signature): + if (_location != _in_field) break; // only allow for fields + if (!privileged) break; // only allow in privileged code + return _field_Stable; +#endif case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature): if (_location != _in_field) break; // only allow for fields if (!privileged) break; // only allow in privileged code diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/classLoaderData.cpp --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -913,7 +913,7 @@ } // Nothing more for the iterator to hand out. - assert(head == NULL, err_msg("head is " PTR_FORMAT ", expected not null:", p2i(head))); + assert(head == NULL, "head is " PTR_FORMAT ", expected not null:", p2i(head)); return NULL; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/dictionary.cpp --- a/hotspot/src/share/vm/classfile/dictionary.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/dictionary.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,8 +31,6 @@ #include "runtime/orderAccess.inline.hpp" #include "utilities/hashtable.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - DictionaryEntry* Dictionary::_current_class_entry = NULL; int Dictionary::_current_class_index = 0; @@ -558,7 +556,7 @@ void ProtectionDomainCacheEntry::print() { tty->print_cr("entry " PTR_FORMAT " value " PTR_FORMAT " strongly_reachable %d next " PTR_FORMAT, - this, (void*)literal(), _strongly_reachable, next()); + p2i(this), p2i(literal()), _strongly_reachable, p2i(next())); } #endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -53,7 +53,9 @@ #include "runtime/vframe.hpp" #include "utilities/preserveException.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif #define INJECTED_FIELD_COMPUTE_OFFSET(klass, name, signature, may_be_java) \ klass::_##name##_offset = JavaClasses::compute_injected_offset(JavaClasses::klass##_##name##_enum); @@ -1579,7 +1581,7 @@ while (h_throwable.not_null()) { objArrayHandle result (THREAD, objArrayOop(backtrace(h_throwable()))); if (result.is_null()) { - st->print_cr("%s", no_stack_trace_message()); + st->print_raw_cr(no_stack_trace_message()); return; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -157,7 +157,12 @@ if (count_offset > 0) { return java_string->int_field(count_offset); } else { - return ((typeArrayOop)java_string->obj_field(value_offset))->length(); + typeArrayOop value_array = ((typeArrayOop)java_string->obj_field(value_offset)); + if (value_array == NULL) { + return 0; + } else { + return value_array->length(); + } } } static int utf8_length(oop java_string); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/metadataOnStackMark.cpp --- a/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/metadataOnStackMark.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -32,6 +32,9 @@ #include "runtime/thread.hpp" #include "services/threadService.hpp" #include "utilities/chunkedList.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#endif MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; @@ -57,6 +60,9 @@ CompileBroker::mark_on_stack(); JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); ThreadService::metadata_do(Metadata::mark_on_stack); +#if INCLUDE_JVMCI + JVMCIRuntime::metadata_do(Metadata::mark_on_stack); +#endif } } @@ -119,7 +125,7 @@ allocated = new MetadataOnStackBuffer(); } - assert(!allocated->is_full(), err_msg("Should not be full: " PTR_FORMAT, p2i(allocated))); + assert(!allocated->is_full(), "Should not be full: " PTR_FORMAT, p2i(allocated)); return allocated; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/stackMapTable.cpp --- a/hotspot/src/share/vm/classfile/stackMapTable.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/stackMapTable.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -186,7 +186,6 @@ u2 offset = _stream->get_u2(THREAD); if (offset >= _code_length || _code_data[offset] != ClassVerifier::NEW_OFFSET) { - ResourceMark rm(THREAD); _verifier->class_format_error( "StackMapTable format error: bad offset for Uninitialized"); return VerificationType::bogus_type(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/stringTable.cpp --- a/hotspot/src/share/vm/classfile/stringTable.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/stringTable.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -43,8 +43,6 @@ #include "gc/g1/g1StringDedup.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // the number of buckets a thread claims const int ClaimChunkSize = 32; @@ -312,12 +310,12 @@ const int limit = the_table()->table_size(); assert(0 <= start_idx && start_idx <= limit, - err_msg("start_idx (%d) is out of bounds", start_idx)); + "start_idx (%d) is out of bounds", start_idx); assert(0 <= end_idx && end_idx <= limit, - err_msg("end_idx (%d) is out of bounds", end_idx)); + "end_idx (%d) is out of bounds", end_idx); assert(start_idx <= end_idx, - err_msg("Index ordering: start_idx=%d, end_idx=%d", - start_idx, end_idx)); + "Index ordering: start_idx=%d, end_idx=%d", + start_idx, end_idx); for (int i = start_idx; i < end_idx; i += 1) { HashtableEntry* entry = the_table()->bucket(i); @@ -335,12 +333,12 @@ const int limit = the_table()->table_size(); assert(0 <= start_idx && start_idx <= limit, - err_msg("start_idx (%d) is out of bounds", start_idx)); + "start_idx (%d) is out of bounds", start_idx); assert(0 <= end_idx && end_idx <= limit, - err_msg("end_idx (%d) is out of bounds", end_idx)); + "end_idx (%d) is out of bounds", end_idx); assert(start_idx <= end_idx, - err_msg("Index ordering: start_idx=%d, end_idx=%d", - start_idx, end_idx)); + "Index ordering: start_idx=%d, end_idx=%d", + start_idx, end_idx); for (int i = start_idx; i < end_idx; ++i) { HashtableEntry** p = the_table()->bucket_addr(i); @@ -445,7 +443,7 @@ if (str1 == str2) { tty->print_cr("ERROR: identical oop values (0x" PTR_FORMAT ") " "in entry @ bucket[%d][%d] and entry @ bucket[%d][%d]", - (void *)str1, bkt1, e_cnt1, bkt2, e_cnt2); + p2i(str1), bkt1, e_cnt1, bkt2, e_cnt2); return _verify_fail_continue; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/symbolTable.cpp --- a/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -37,8 +37,6 @@ #include "runtime/mutexLocker.hpp" #include "utilities/hashtable.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // -------------------------------------------------------------------------- // the number of buckets a thread claims const int ClaimChunkSize = 32; @@ -623,8 +621,8 @@ ((float)_symbols_removed/(float)_symbols_counted)* 100); } tty->print_cr(" Reference counts %7d", Symbol::_total_count); - tty->print_cr(" Symbol arena used %7dK", arena()->used()/1024); - tty->print_cr(" Symbol arena size %7dK", arena()->size_in_bytes()/1024); + tty->print_cr(" Symbol arena used " SIZE_FORMAT_W(7) "K", arena()->used()/1024); + tty->print_cr(" Symbol arena size " SIZE_FORMAT_W(7) "K", arena()->size_in_bytes()/1024); tty->print_cr(" Total symbol length %7d", total_length); tty->print_cr(" Maximum symbol length %7d", max_length); tty->print_cr(" Average symbol length %7.2f", ((float) total_length / (float) total_count)); @@ -645,7 +643,7 @@ HashtableEntry* entry = the_table()->bucket(i); if (entry != NULL) { while (entry != NULL) { - tty->print(PTR_FORMAT " ", entry->literal()); + tty->print(PTR_FORMAT " ", p2i(entry->literal())); entry->literal()->print(); tty->print(" %d", entry->literal()->refcount()); p = entry->next_addr(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -66,6 +66,9 @@ #include "classfile/sharedClassUtil.hpp" #include "classfile/systemDictionaryShared.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#endif #if INCLUDE_TRACE #include "trace/tracing.hpp" #endif @@ -228,10 +231,10 @@ // Forwards to resolve_instance_class_or_null Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) { - assert(!THREAD->is_Compiler_thread(), - err_msg("can not load classes with compiler thread: class=%s, classloader=%s", - class_name->as_C_string(), - class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string())); + assert(THREAD->can_call_java(), + "can not load classes with compiler thread: class=%s, classloader=%s", + class_name->as_C_string(), + class_loader.is_null() ? "null" : class_loader->klass()->name()->as_C_string()); if (FieldType::is_array(class_name)) { return resolve_array_class_or_null(class_name, class_loader, protection_domain, THREAD); } else if (FieldType::is_obj(class_name)) { @@ -1917,7 +1920,7 @@ WKID jsr292_group_end = WK_KLASS_ENUM_NAME(VolatileCallSite_klass); initialize_wk_klasses_until(jsr292_group_start, scan, CHECK); initialize_wk_klasses_through(jsr292_group_end, scan, CHECK); - initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK); + initialize_wk_klasses_until(NOT_JVMCI(WKID_LIMIT) JVMCI_ONLY(FIRST_JVMCI_WKID), scan, CHECK); _box_klasses[T_BOOLEAN] = WK_KLASS(Boolean_klass); _box_klasses[T_CHAR] = WK_KLASS(Character_klass); @@ -2264,7 +2267,7 @@ assert(MethodHandles::is_signature_polymorphic(iid) && MethodHandles::is_signature_polymorphic_intrinsic(iid) && iid != vmIntrinsics::_invokeGeneric, - err_msg("must be a known MH intrinsic iid=%d: %s", iid, vmIntrinsics::name_at(iid))); + "must be a known MH intrinsic iid=%d: %s", iid, vmIntrinsics::name_at(iid)); unsigned int hash = invoke_method_table()->compute_hash(signature, iid); int index = invoke_method_table()->hash_to_index(hash); @@ -2343,7 +2346,7 @@ Handle *method_type_result, TRAPS) { methodHandle empty; - assert(!THREAD->is_Compiler_thread(), ""); + assert(THREAD->can_call_java() ,""); Handle method_type = SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty)); @@ -2390,7 +2393,7 @@ if (klass->oop_is_typeArray()) { return true; // primitive array } - assert(klass->oop_is_instance(), klass->external_name()); + assert(klass->oop_is_instance(), "%s", klass->external_name()); return klass->is_public() && (InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::Object_klass()) || // java.lang InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::MethodHandle_klass())); // java.lang.invoke @@ -2411,7 +2414,7 @@ if (spe != NULL && spe->method_type() != NULL) { assert(java_lang_invoke_MethodType::is_instance(spe->method_type()), ""); return Handle(THREAD, spe->method_type()); - } else if (THREAD->is_Compiler_thread()) { + } else if (!THREAD->can_call_java()) { warning("SystemDictionary::find_method_handle_type called from compiler thread"); // FIXME return Handle(); // do not attempt from within compiler, unless it was cached } @@ -2443,7 +2446,7 @@ mirror = ss.as_java_mirror(class_loader, protection_domain, SignatureStream::NCDFError, CHECK_(empty)); } - assert(!oopDesc::is_null(mirror), ss.as_symbol(THREAD)->as_C_string()); + assert(!oopDesc::is_null(mirror), "%s", ss.as_symbol(THREAD)->as_C_string()); if (ss.at_return_type()) rt = Handle(THREAD, mirror); else diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -33,6 +33,7 @@ #include "runtime/reflectionUtils.hpp" #include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" +#include "jvmci/systemDictionary_jvmci.hpp" // The system dictionary stores all loaded classes and maps: @@ -192,6 +193,10 @@ do_klass(Short_klass, java_lang_Short, Pre ) \ do_klass(Integer_klass, java_lang_Integer, Pre ) \ do_klass(Long_klass, java_lang_Long, Pre ) \ + \ + /* JVMCI classes. These are loaded on-demand. */ \ + JVMCI_WK_KLASSES_DO(do_klass) \ + /*end*/ @@ -209,6 +214,11 @@ WKID_LIMIT, +#if INCLUDE_JVMCI + FIRST_JVMCI_WKID = WK_KLASS_ENUM_NAME(HotSpotCompiledCode_klass), + LAST_JVMCI_WKID = WK_KLASS_ENUM_NAME(Value_klass), +#endif + FIRST_WKID = NO_WKID + 1 }; @@ -219,6 +229,9 @@ // Options after this point will use resolve_or_null instead. Opt, // preload tried; NULL if not present +#if INCLUDE_JVMCI + Jvmci, // preload tried; error if not present, use only with JVMCI +#endif OPTION_LIMIT, CEIL_LG_OPTION_LIMIT = 2 // OPTION_LIMIT <= (1<") \ @@ -382,6 +385,7 @@ template(bitCount_name, "bitCount") \ template(profile_name, "profile") \ template(equals_name, "equals") \ + template(length_name, "length") \ template(target_name, "target") \ template(toString_name, "toString") \ template(values_name, "values") \ @@ -432,6 +436,7 @@ template(void_long_signature, "()J") \ template(void_float_signature, "()F") \ template(void_double_signature, "()D") \ + template(bool_void_signature, "(Z)V") \ template(int_void_signature, "(I)V") \ template(int_int_signature, "(I)I") \ template(char_char_signature, "(C)C") \ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/codeBlob.hpp --- a/hotspot/src/share/vm/code/codeBlob.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/codeBlob.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -120,6 +120,7 @@ virtual bool is_compiled_by_c2() const { return false; } virtual bool is_compiled_by_c1() const { return false; } + virtual bool is_compiled_by_jvmci() const { return false; } // Casting nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; } @@ -380,6 +381,12 @@ int _unpack_with_exception_in_tls; +#if INCLUDE_JVMCI + // Offsets when JVMCI calls uncommon_trap. + int _uncommon_trap_offset; + int _implicit_exception_uncommon_trap_offset; +#endif + // Creation support DeoptimizationBlob( CodeBuffer* cb, @@ -429,6 +436,21 @@ assert(code_contains(code_begin() + _unpack_with_exception_in_tls), "must be PC inside codeblob"); } address unpack_with_exception_in_tls() const { return code_begin() + _unpack_with_exception_in_tls; } + +#if INCLUDE_JVMCI + // Offsets when JVMCI calls uncommon_trap. + void set_uncommon_trap_offset(int offset) { + _uncommon_trap_offset = offset; + assert(contains(code_begin() + _uncommon_trap_offset), "must be PC inside codeblob"); + } + address uncommon_trap() const { return code_begin() + _uncommon_trap_offset; } + + void set_implicit_exception_uncommon_trap_offset(int offset) { + _implicit_exception_uncommon_trap_offset = offset; + assert(contains(code_begin() + _implicit_exception_uncommon_trap_offset), "must be PC inside codeblob"); + } + address implicit_exception_uncommon_trap() const { return code_begin() + _implicit_exception_uncommon_trap_offset; } +#endif // INCLUDE_JVMCI }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/codeCache.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -365,7 +365,7 @@ // Possibly wakes up the sweeper thread. NMethodSweeper::notify(code_blob_type); assert_locked_or_safepoint(CodeCache_lock); - assert(size > 0, err_msg_res("Code cache allocation request must be > 0 but is %d", size)); + assert(size > 0, "Code cache allocation request must be > 0 but is %d", size); if (size <= 0) { return NULL; } @@ -817,7 +817,7 @@ double max_capacity = (double)heap->max_capacity(); double result = max_capacity / unallocated_capacity; assert (max_capacity >= unallocated_capacity, "Must be"); - assert (result >= 1.0, err_msg_res("reverse_free_ratio must be at least 1. It is %f", result)); + assert (result >= 1.0, "reverse_free_ratio must be at least 1. It is %f", result); return result; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/compiledIC.cpp --- a/hotspot/src/share/vm/code/compiledIC.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/compiledIC.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -280,11 +280,13 @@ bool is_monomorphic = (cb != NULL && cb->is_nmethod()); // Check that the cached_value is a klass for non-optimized monomorphic calls // This assertion is invalid for compiler1: a call that does not look optimized (no static stub) can be used - // for calling directly to vep without using the inline cache (i.e., cached_value == NULL) + // for calling directly to vep without using the inline cache (i.e., cached_value == NULL). + // For JVMCI this occurs because CHA is only used to improve inlining so call sites which could be optimized + // virtuals because there are no currently loaded subclasses of a type are left as virtual call sites. #ifdef ASSERT CodeBlob* caller = CodeCache::find_blob_unsafe(instruction_address()); - bool is_c1_method = caller->is_compiled_by_c1(); - assert( is_c1_method || + bool is_c1_or_jvmci_method = caller->is_compiled_by_c1() || caller->is_compiled_by_jvmci(); + assert( is_c1_or_jvmci_method || !is_monomorphic || is_optimized() || !caller->is_alive() || diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/compiledIC.hpp --- a/hotspot/src/share/vm/code/compiledIC.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/compiledIC.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -306,7 +306,7 @@ friend CompiledStaticCall* compiledStaticCall_at(Relocation* call_site); // Code - static address emit_to_interp_stub(CodeBuffer &cbuf); + static address emit_to_interp_stub(CodeBuffer &cbuf, address mark = NULL); static int to_interp_stub_size(); static int reloc_to_interp_stub(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/debugInfo.cpp --- a/hotspot/src/share/vm/code/debugInfo.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/debugInfo.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,8 +29,6 @@ #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Constructors DebugInfoWriteStream::DebugInfoWriteStream(DebugInformationRecorder* recorder, int initial_size) @@ -59,7 +57,7 @@ #ifdef ASSERT assert(_obj_pool != NULL, "object pool does not exist"); for (int i = _obj_pool->length() - 1; i >= 0; i--) { - assert(((ObjectValue*) _obj_pool->at(i))->id() != id, "should not be read twice"); + assert(_obj_pool->at(i)->as_ObjectValue()->id() != id, "should not be read twice"); } #endif ObjectValue* result = new ObjectValue(id); @@ -73,7 +71,7 @@ int id = read_int(); assert(_obj_pool != NULL, "object pool does not exist"); for (int i = _obj_pool->length() - 1; i >= 0; i--) { - ObjectValue* ov = (ObjectValue*) _obj_pool->at(i); + ObjectValue* ov = _obj_pool->at(i)->as_ObjectValue(); if (ov->id() == id) { return ov; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/debugInfo.hpp --- a/hotspot/src/share/vm/code/debugInfo.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/debugInfo.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,6 +41,7 @@ // - ConstantValue describes a constant class ConstantOopReadValue; +class ObjectValue; class ScopeValue: public ResourceObj { public: @@ -58,6 +59,11 @@ return (ConstantOopReadValue*) this; } + ObjectValue* as_ObjectValue() { + assert(is_object(), "must be"); + return (ObjectValue*)this; + } + // Serialization of debugging information virtual void write_on(DebugInfoWriteStream* stream) = 0; static ScopeValue* read_from(DebugInfoReadStream* stream); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/debugInfoRec.cpp --- a/hotspot/src/share/vm/code/debugInfoRec.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/debugInfoRec.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -37,6 +37,9 @@ int _offset; // location in the stream of this scope int _length; // number of bytes in the stream int _hash; // hash of stream bytes (for quicker reuse) +#if INCLUDE_JVMCI + DebugInformationRecorder* _DIR; +#endif void* operator new(size_t ignore, DebugInformationRecorder* dir) throw() { assert(ignore == sizeof(DIR_Chunk), ""); @@ -51,6 +54,9 @@ DIR_Chunk(int offset, int length, DebugInformationRecorder* dir) { _offset = offset; _length = length; +#if INCLUDE_JVMCI + _DIR = dir; +#endif unsigned int hash = 0; address p = dir->stream()->buffer() + _offset; for (int i = 0; i < length; i++) { @@ -77,6 +83,25 @@ } return NULL; } + +#if INCLUDE_JVMCI + static int compare(DIR_Chunk* const & a, DIR_Chunk* const & b) { + if (b->_hash > a->_hash) { + return 1; + } + if (b->_hash < a->_hash) { + return -1; + } + if (b->_length > a->_length) { + return 1; + } + if (b->_length < a->_length) { + return -1; + } + address buf = a->_DIR->stream()->buffer(); + return memcmp(buf + b->_offset, buf + a->_offset, a->_length); + } +#endif }; static inline bool compute_recording_non_safepoints() { @@ -113,7 +138,9 @@ _oop_recorder = oop_recorder; _all_chunks = new GrowableArray(300); +#if !INCLUDE_JVMCI _shared_chunks = new GrowableArray(30); +#endif _next_chunk = _next_chunk_limit = NULL; add_new_pc_offset(PcDesc::lower_offset_limit); // sentinel record @@ -235,10 +262,13 @@ int DebugInformationRecorder::find_sharable_decode_offset(int stream_offset) { +#if !INCLUDE_JVMCI // Only pull this trick if non-safepoint recording // is enabled, for now. - if (!recording_non_safepoints()) + if (!recording_non_safepoints()) { return serialized_null; + } +#endif // INCLUDE_JVMCI NOT_PRODUCT(++dir_stats.chunks_queried); int stream_length = stream()->position() - stream_offset; @@ -247,6 +277,19 @@ DIR_Chunk* ns = new(this) DIR_Chunk(stream_offset, stream_length, this); +#if INCLUDE_JVMCI + DIR_Chunk* match = _all_chunks->insert_sorted(ns); + if (match != ns) { + // Found an existing chunk + NOT_PRODUCT(++dir_stats.chunks_shared); + assert(ns+1 == _next_chunk, ""); + _next_chunk = ns; + return match->_offset; + } else { + // Inserted this chunk, so nothing to do + return serialized_null; + } +#else // INCLUDE_JVMCI // Look in previously shared scopes first: DIR_Chunk* ms = ns->find_match(_shared_chunks, 0, this); if (ms != NULL) { @@ -274,15 +317,18 @@ // No match. Add this guy to the list, in hopes of future shares. _all_chunks->append(ns); return serialized_null; +#endif // INCLUDE_JVMCI } // must call add_safepoint before: it sets PcDesc and this routine uses // the last PcDesc set void DebugInformationRecorder::describe_scope(int pc_offset, + methodHandle methodH, ciMethod* method, int bci, bool reexecute, + bool rethrow_exception, bool is_method_handle_invoke, bool return_oop, DebugToken* locals, @@ -298,6 +344,7 @@ // Record flags into pcDesc. last_pd->set_should_reexecute(reexecute); + last_pd->set_rethrow_exception(rethrow_exception); last_pd->set_is_method_handle_invoke(is_method_handle_invoke); last_pd->set_return_oop(return_oop); @@ -305,8 +352,16 @@ stream()->write_int(sender_stream_offset); // serialize scope - Metadata* method_enc = (method == NULL)? NULL: method->constant_encoding(); - stream()->write_int(oop_recorder()->find_index(method_enc)); + Metadata* method_enc; + if (method != NULL) { + method_enc = method->constant_encoding(); + } else if (methodH.not_null()) { + method_enc = methodH(); + } else { + method_enc = NULL; + } + int method_enc_index = oop_recorder()->find_index(method_enc); + stream()->write_int(method_enc_index); stream()->write_bci(bci); assert(method == NULL || (method->is_native() && bci == 0) || @@ -338,7 +393,7 @@ PcDesc* last_pd = &_pcs[_pcs_length-1]; if (objects != NULL) { for (int i = objects->length() - 1; i >= 0; i--) { - ((ObjectValue*) objects->at(i))->set_visited(false); + objects->at(i)->as_ObjectValue()->set_visited(false); } } int offset = serialize_scope_values(objects); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/debugInfoRec.hpp --- a/hotspot/src/share/vm/code/debugInfoRec.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/debugInfoRec.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -98,9 +98,11 @@ // by add_non_safepoint, and the locals, expressions, and monitors // must all be null. void describe_scope(int pc_offset, + methodHandle methodH, ciMethod* method, int bci, bool reexecute, + bool rethrow_exception = false, bool is_method_handle_invoke = false, bool return_oop = false, DebugToken* locals = NULL, @@ -143,6 +145,12 @@ bool recording_non_safepoints() { return _recording_non_safepoints; } + PcDesc* pcs() const { return _pcs; } + int pcs_length() const { return _pcs_length; } + + DebugInfoWriteStream* stream() const { return _stream; } + + private: friend class ScopeDesc; friend class vframeStreamCommon; @@ -155,13 +163,13 @@ DebugInfoWriteStream* _stream; - DebugInfoWriteStream* stream() const { return _stream; } - OopRecorder* _oop_recorder; // Scopes that have been described so far. GrowableArray* _all_chunks; +#if !INCLUDE_JVMCI GrowableArray* _shared_chunks; +#endif DIR_Chunk* _next_chunk; DIR_Chunk* _next_chunk_limit; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/dependencies.cpp --- a/hotspot/src/share/vm/code/dependencies.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/dependencies.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,6 +31,7 @@ #include "code/dependencies.hpp" #include "compiler/compileLog.hpp" #include "oops/oop.inline.hpp" +#include "oops/objArrayKlass.hpp" #include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/thread.inline.hpp" @@ -52,6 +53,9 @@ _oop_recorder = env->oop_recorder(); _log = env->log(); _dep_seen = new(arena) GrowableArray(arena, 500, 0, 0); +#if INCLUDE_JVMCI + _using_dep_values = false; +#endif DEBUG_ONLY(_deps[end_marker] = NULL); for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) { _deps[i] = new(arena) GrowableArray(arena, 10, 0, 0); @@ -120,6 +124,66 @@ assert_common_2(call_site_target_value, call_site, method_handle); } +#if INCLUDE_JVMCI + +Dependencies::Dependencies(Arena* arena, OopRecorder* oop_recorder, CompileLog* log) { + _oop_recorder = oop_recorder; + _log = log; + _dep_seen = new(arena) GrowableArray(arena, 500, 0, 0); + _using_dep_values = true; + DEBUG_ONLY(_dep_values[end_marker] = NULL); + for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) { + _dep_values[i] = new(arena) GrowableArray(arena, 10, 0, DepValue()); + } + _content_bytes = NULL; + _size_in_bytes = (size_t)-1; + + assert(TYPE_LIMIT <= (1<oop_is_array()) { + // As a special case, support this assertion on an array type, + // which reduces to an assertion on its element type. + // Note that this cannot be done with assertions that + // relate to concreteness or abstractness. + BasicType elemt = ArrayKlass::cast(ctxk)->element_type(); + if (is_java_primitive(elemt)) return; // Ex: int[][] + ctxk = ObjArrayKlass::cast(ctxk)->bottom_klass(); + //if (ctxk->is_final()) return; // Ex: String[][] + } + check_ctxk(ctxk); + assert_common_1(leaf_type, DepValue(_oop_recorder, ctxk)); +} + +void Dependencies::assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck) { + check_ctxk_abstract(ctxk); + DepValue ctxk_dv(_oop_recorder, ctxk); + DepValue conck_dv(_oop_recorder, conck, &ctxk_dv); + assert_common_2(abstract_with_unique_concrete_subtype, ctxk_dv, conck_dv); +} + +void Dependencies::assert_unique_concrete_method(Klass* ctxk, Method* uniqm) { + check_ctxk(ctxk); + assert_common_2(unique_concrete_method, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqm)); +} + +void Dependencies::assert_call_site_target_value(oop call_site, oop method_handle) { + assert_common_2(call_site_target_value, DepValue(_oop_recorder, JNIHandles::make_local(call_site)), DepValue(_oop_recorder, JNIHandles::make_local(method_handle))); +} + +#endif // INCLUDE_JVMCI + + // Helper function. If we are adding a new dep. under ctxk2, // try to find an old dep. under a broader* ctxk1. If there is // @@ -230,6 +294,78 @@ deps->append(x2); } +#if INCLUDE_JVMCI +bool Dependencies::maybe_merge_ctxk(GrowableArray* deps, + int ctxk_i, DepValue ctxk2_dv) { + Klass* ctxk1 = deps->at(ctxk_i).as_klass(_oop_recorder); + Klass* ctxk2 = ctxk2_dv.as_klass(_oop_recorder); + if (ctxk2->is_subtype_of(ctxk1)) { + return true; // success, and no need to change + } else if (ctxk1->is_subtype_of(ctxk2)) { + // new context class fully subsumes previous one + deps->at_put(ctxk_i, ctxk2_dv); + return true; + } else { + return false; + } +} + +void Dependencies::assert_common_1(DepType dept, DepValue x) { + assert(dep_args(dept) == 1, "sanity"); + //log_dependency(dept, x); + GrowableArray* deps = _dep_values[dept]; + + // see if the same (or a similar) dep is already recorded + if (note_dep_seen(dept, x)) { + assert(deps->find(x) >= 0, "sanity"); + } else { + deps->append(x); + } +} + +void Dependencies::assert_common_2(DepType dept, + DepValue x0, DepValue x1) { + assert(dep_args(dept) == 2, "sanity"); + //log_dependency(dept, x0, x1); + GrowableArray* deps = _dep_values[dept]; + + // see if the same (or a similar) dep is already recorded + bool has_ctxk = has_explicit_context_arg(dept); + if (has_ctxk) { + assert(dep_context_arg(dept) == 0, "sanity"); + if (note_dep_seen(dept, x1)) { + // look in this bucket for redundant assertions + const int stride = 2; + for (int i = deps->length(); (i -= stride) >= 0; ) { + DepValue y1 = deps->at(i+1); + if (x1 == y1) { // same subject; check the context + if (maybe_merge_ctxk(deps, i+0, x0)) { + return; + } + } + } + } + } else { + assert(dep_implicit_context_arg(dept) == 0, "sanity"); + if (note_dep_seen(dept, x0) && note_dep_seen(dept, x1)) { + // look in this bucket for redundant assertions + const int stride = 2; + for (int i = deps->length(); (i -= stride) >= 0; ) { + DepValue y0 = deps->at(i+0); + DepValue y1 = deps->at(i+1); + if (x0 == y0 && x1 == y1) { + return; + } + } + } + } + + // append the assertion in the correct bucket: + deps->append(x0); + deps->append(x1); +} +#endif // INCLUDE_JVMCI + /// Support for encoding dependencies into an nmethod: void Dependencies::copy_to(nmethod* nm) { @@ -256,7 +392,40 @@ static int sort_dep_arg_3(ciBaseObject** p1, ciBaseObject** p2) { return sort_dep(p1, p2, 3); } +#if INCLUDE_JVMCI +// metadata deps are sorted before object deps +static int sort_dep_value(Dependencies::DepValue* p1, Dependencies::DepValue* p2, int narg) { + for (int i = 0; i < narg; i++) { + int diff = p1[i].sort_key() - p2[i].sort_key(); + if (diff != 0) return diff; + } + return 0; +} +static int sort_dep_value_arg_1(Dependencies::DepValue* p1, Dependencies::DepValue* p2) +{ return sort_dep_value(p1, p2, 1); } +static int sort_dep_value_arg_2(Dependencies::DepValue* p1, Dependencies::DepValue* p2) +{ return sort_dep_value(p1, p2, 2); } +static int sort_dep_value_arg_3(Dependencies::DepValue* p1, Dependencies::DepValue* p2) +{ return sort_dep_value(p1, p2, 3); } +#endif // INCLUDE_JVMCI + void Dependencies::sort_all_deps() { +#if INCLUDE_JVMCI + if (_using_dep_values) { + for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { + DepType dept = (DepType)deptv; + GrowableArray* deps = _dep_values[dept]; + if (deps->length() <= 1) continue; + switch (dep_args(dept)) { + case 1: deps->sort(sort_dep_value_arg_1, 1); break; + case 2: deps->sort(sort_dep_value_arg_2, 2); break; + case 3: deps->sort(sort_dep_value_arg_3, 3); break; + default: ShouldNotReachHere(); + } + } + return; + } +#endif // INCLUDE_JVMCI for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; @@ -272,6 +441,16 @@ size_t Dependencies::estimate_size_in_bytes() { size_t est_size = 100; +#if INCLUDE_JVMCI + if (_using_dep_values) { + for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { + DepType dept = (DepType)deptv; + GrowableArray* deps = _dep_values[dept]; + est_size += deps->length() * 2; // tags and argument(s) + } + return est_size; + } +#endif // INCLUDE_JVMCI for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; @@ -311,6 +490,37 @@ // cast is safe, no deps can overflow INT_MAX CompressedWriteStream bytes((int)estimate_size_in_bytes()); +#if INCLUDE_JVMCI + if (_using_dep_values) { + for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { + DepType dept = (DepType)deptv; + GrowableArray* deps = _dep_values[dept]; + if (deps->length() == 0) continue; + int stride = dep_args(dept); + int ctxkj = dep_context_arg(dept); // -1 if no context arg + assert(stride > 0, "sanity"); + for (int i = 0; i < deps->length(); i += stride) { + jbyte code_byte = (jbyte)dept; + int skipj = -1; + if (ctxkj >= 0 && ctxkj+1 < stride) { + Klass* ctxk = deps->at(i+ctxkj+0).as_klass(_oop_recorder); + DepValue x = deps->at(i+ctxkj+1); // following argument + if (ctxk == ctxk_encoded_as_null(dept, x.as_metadata(_oop_recorder))) { + skipj = ctxkj; // we win: maybe one less oop to keep track of + code_byte |= default_context_type_bit; + } + } + bytes.write_byte(code_byte); + for (int j = 0; j < stride; j++) { + if (j == skipj) continue; + DepValue v = deps->at(i+j); + int idx = v.index(); + bytes.write_int(idx); + } + } + } + } else { +#endif // INCLUDE_JVMCI for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) { DepType dept = (DepType)deptv; GrowableArray* deps = _deps[dept]; @@ -344,6 +554,9 @@ } } } +#if INCLUDE_JVMCI + } +#endif // write a sentinel byte to mark the end bytes.write_byte(end_marker); @@ -400,7 +613,7 @@ } void Dependencies::check_valid_dependency_type(DepType dept) { - guarantee(FIRST_TYPE <= dept && dept < TYPE_LIMIT, err_msg("invalid dependency type: %d", (int) dept)); + guarantee(FIRST_TYPE <= dept && dept < TYPE_LIMIT, "invalid dependency type: %d", (int) dept); } // for the sake of the compiler log, print out current dependencies: @@ -540,10 +753,10 @@ } void Dependencies::print_dependency(DepType dept, GrowableArray* args, - Klass* witness) { + Klass* witness, outputStream* st) { ResourceMark rm; ttyLocker ttyl; // keep the following output all in one block - tty->print_cr("%s of type %s", + st->print_cr("%s of type %s", (witness == NULL)? "Dependency": "Failed dependency", dep_name(dept)); // print arguments @@ -565,22 +778,22 @@ } else { what = "object "; } - tty->print(" %s = %s", what, (put_star? "*": "")); + st->print(" %s = %s", what, (put_star? "*": "")); if (arg.is_klass()) { - tty->print("%s", ((Klass*)arg.metadata_value())->external_name()); + st->print("%s", ((Klass*)arg.metadata_value())->external_name()); } else if (arg.is_method()) { - ((Method*)arg.metadata_value())->print_value(); + ((Method*)arg.metadata_value())->print_value_on(st); } else if (arg.is_oop()) { - arg.oop_value()->print_value_on(tty); + arg.oop_value()->print_value_on(st); } else { ShouldNotReachHere(); // Provide impl for this type. } - tty->cr(); + st->cr(); } if (witness != NULL) { bool put_star = !Dependencies::is_concrete_klass(witness); - tty->print_cr(" witness = %s%s", + st->print_cr(" witness = %s%s", (put_star? "*": ""), witness->external_name()); } @@ -600,14 +813,19 @@ } int argslen = args->length(); if (_deps != NULL && _deps->log() != NULL) { - Dependencies::write_dependency_to(_deps->log(), type(), args, witness); + if (ciEnv::current() != NULL) { + Dependencies::write_dependency_to(_deps->log(), type(), args, witness); + } else { + // Treat the CompileLog as an xmlstream instead + Dependencies::write_dependency_to((xmlStream*)_deps->log(), type(), args, witness); + } } else { Dependencies::write_dependency_to(xtty, type(), args, witness); } guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope"); } -void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose) { +void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose, outputStream* st) { ResourceMark rm; int nargs = argument_count(); GrowableArray* args = new GrowableArray(nargs); @@ -619,12 +837,12 @@ } } int argslen = args->length(); - Dependencies::print_dependency(type(), args, witness); + Dependencies::print_dependency(type(), args, witness, st); if (verbose) { if (_code != NULL) { - tty->print(" code: "); - _code->print_value_on(tty); - tty->cr(); + st->print(" code: "); + _code->print_value_on(st); + st->cr(); } } guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/dependencies.hpp --- a/hotspot/src/share/vm/code/dependencies.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/dependencies.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -202,10 +202,59 @@ static void check_valid_dependency_type(DepType dept); +#if INCLUDE_JVMCI + // A Metadata* or object value recorded in an OopRecorder + class DepValue VALUE_OBJ_CLASS_SPEC { + private: + // Unique identifier of the value within the associated OopRecorder that + // encodes both the category of the value (0: invalid, positive: metadata, negative: object) + // and the index within a category specific array (metadata: index + 1, object: -(index + 1)) + int _id; + + public: + DepValue() : _id(0) {} + DepValue(OopRecorder* rec, Metadata* metadata, DepValue* candidate = NULL) { + assert(candidate == NULL || candidate->is_metadata(), "oops"); + if (candidate != NULL && candidate->as_metadata(rec) == metadata) { + _id = candidate->_id; + } else { + _id = rec->find_index(metadata) + 1; + } + } + DepValue(OopRecorder* rec, jobject obj, DepValue* candidate = NULL) { + assert(candidate == NULL || candidate->is_object(), "oops"); + if (candidate != NULL && candidate->as_object(rec) == obj) { + _id = candidate->_id; + } else { + _id = -(rec->find_index(obj) + 1); + } + } + + // Used to sort values in ascending order of index() with metadata values preceding object values + int sort_key() const { return -_id; } + + bool operator == (const DepValue& other) const { return other._id == _id; } + + bool is_valid() const { return _id != 0; } + int index() const { assert(is_valid(), "oops"); return _id < 0 ? -(_id + 1) : _id - 1; } + bool is_metadata() const { assert(is_valid(), "oops"); return _id > 0; } + bool is_object() const { assert(is_valid(), "oops"); return _id < 0; } + + Metadata* as_metadata(OopRecorder* rec) const { assert(is_metadata(), "oops"); return rec->metadata_at(index()); } + Klass* as_klass(OopRecorder* rec) const { assert(as_metadata(rec)->is_klass(), "oops"); return (Klass*) as_metadata(rec); } + Method* as_method(OopRecorder* rec) const { assert(as_metadata(rec)->is_method(), "oops"); return (Method*) as_metadata(rec); } + jobject as_object(OopRecorder* rec) const { assert(is_object(), "oops"); return rec->oop_at(index()); } + }; +#endif // INCLUDE_JVMCI + private: // State for writing a new set of dependencies: GrowableArray* _dep_seen; // (seen[h->ident] & (1<* _deps[TYPE_LIMIT]; +#if INCLUDE_JVMCI + bool _using_dep_values; + GrowableArray* _dep_values[TYPE_LIMIT]; +#endif static const char* _dep_name[TYPE_LIMIT]; static int _dep_args[TYPE_LIMIT]; @@ -224,8 +273,25 @@ return (seen & (1<at_grow(x_id, 0); + _dep_seen->at_put(x_id, seen | (1<* deps, int ctxk_i, ciKlass* ctxk); +#if INCLUDE_JVMCI + bool maybe_merge_ctxk(GrowableArray* deps, + int ctxk_i, DepValue ctxk); +#endif void sort_all_deps(); size_t estimate_size_in_bytes(); @@ -247,6 +313,9 @@ Dependencies(ciEnv* env) { initialize(env); } +#if INCLUDE_JVMCI + Dependencies(Arena* arena, OopRecorder* oop_recorder, CompileLog* log); +#endif private: // Check for a valid context type. @@ -279,6 +348,27 @@ void assert_has_no_finalizable_subclasses(ciKlass* ctxk); void assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle); +#if INCLUDE_JVMCI + private: + static void check_ctxk(Klass* ctxk) { + assert(ctxk->oop_is_instance(), "java types only"); + } + static void check_ctxk_abstract(Klass* ctxk) { + check_ctxk(ctxk); + assert(ctxk->is_abstract(), "must be abstract"); + } + void assert_common_1(DepType dept, DepValue x); + void assert_common_2(DepType dept, DepValue x0, DepValue x1); + + public: + void assert_evol_method(Method* m); + void assert_has_no_finalizable_subclasses(Klass* ctxk); + void assert_leaf_type(Klass* ctxk); + void assert_unique_concrete_method(Klass* ctxk, Method* uniqm); + void assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck); + void assert_call_site_target_value(oop callSite, oop methodHandle); +#endif // INCLUDE_JVMCI + // Define whether a given method or type is concrete. // These methods define the term "concrete" as used in this module. // For this module, an "abstract" class is one which is non-concrete. @@ -422,7 +512,7 @@ static void print_dependency(DepType dept, GrowableArray* args, - Klass* witness = NULL); + Klass* witness = NULL, outputStream* st = tty); private: // helper for encoding common context types as zero: @@ -534,7 +624,7 @@ void log_dependency(Klass* witness = NULL); // Print the current dependency to tty. - void print_dependency(Klass* witness = NULL, bool verbose = false); + void print_dependency(Klass* witness = NULL, bool verbose = false, outputStream* st = tty); }; friend class Dependencies::DepStream; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/exceptionHandlerTable.cpp --- a/hotspot/src/share/vm/code/exceptionHandlerTable.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/exceptionHandlerTable.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -27,8 +27,6 @@ #include "code/nmethod.hpp" #include "memory/allocation.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void ExceptionHandlerTable::add_entry(HandlerTableEntry entry) { _nesting.check(); if (_length >= _size) { @@ -102,9 +100,12 @@ void ExceptionHandlerTable::copy_to(nmethod* nm) { assert(size_in_bytes() == nm->handler_table_size(), "size of space allocated in nmethod incorrect"); - memmove(nm->handler_table_begin(), _table, size_in_bytes()); + copy_bytes_to(nm->handler_table_begin()); } +void ExceptionHandlerTable::copy_bytes_to(address addr) { + memmove(addr, _table, size_in_bytes()); +} HandlerTableEntry* ExceptionHandlerTable::entry_for(int catch_pco, int handler_bci, int scope_depth) const { HandlerTableEntry* t = subtable_for(catch_pco); @@ -186,7 +187,7 @@ void ImplicitExceptionTable::print(address base) const { tty->print("{"); for( uint i=0; iprint("< " INTPTR_FORMAT ", " INTPTR_FORMAT " > ",base + *adr(i), base + *(adr(i)+1)); + tty->print("< " INTPTR_FORMAT ", " INTPTR_FORMAT " > ", p2i(base + *adr(i)), p2i(base + *(adr(i)+1))); tty->print_cr("}"); } @@ -225,6 +226,6 @@ for (uint i = 0; i < len(); i++) { 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)); + fatal("Invalid offset in ImplicitExceptionTable at " PTR_FORMAT, p2i(_data)); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/exceptionHandlerTable.hpp --- a/hotspot/src/share/vm/code/exceptionHandlerTable.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/exceptionHandlerTable.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -89,11 +89,11 @@ int _size; // the number of allocated entries ReallocMark _nesting; // assertion check for reallocations + public: // add the entry & grow the table if needed void add_entry(HandlerTableEntry entry); HandlerTableEntry* subtable_for(int catch_pco) const; - public: // (compile-time) construction within compiler ExceptionHandlerTable(int initial_size = 8); @@ -116,6 +116,7 @@ // nmethod support int size_in_bytes() const { return round_to(_length * sizeof(HandlerTableEntry), oopSize); } void copy_to(nmethod* nm); + void copy_bytes_to(address addr); // lookup HandlerTableEntry* entry_for(int catch_pco, int handler_bci, int scope_depth) const; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/icBuffer.cpp --- a/hotspot/src/share/vm/code/icBuffer.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/icBuffer.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -38,8 +38,6 @@ #include "runtime/mutexLocker.hpp" #include "runtime/stubRoutines.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - DEF_STUB_INTERFACE(ICStub); StubQueue* InlineCacheBuffer::_buffer = NULL; @@ -97,7 +95,7 @@ } void ICStub::print() { - tty->print_cr("ICStub: site: " INTPTR_FORMAT, _ic_site); + tty->print_cr("ICStub: site: " INTPTR_FORMAT, p2i(_ic_site)); } #endif @@ -175,7 +173,7 @@ assert (CompiledIC_lock->is_locked(), ""); if (TraceICBuffer) { tty->print_cr(" create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT, - ic->instruction_address(), entry, cached_value); + p2i(ic->instruction_address()), p2i(entry), p2i(cached_value)); } // If an transition stub is already associate with the inline cache, then we remove the association. @@ -230,6 +228,6 @@ _pending_released = icholder; _pending_count++; if (TraceICBuffer) { - tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", icholder); + tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", p2i(icholder)); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/nmethod.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,6 +26,7 @@ #include "code/codeCache.hpp" #include "code/compiledIC.hpp" #include "code/dependencies.hpp" +#include "code/nativeInst.hpp" #include "code/nmethod.hpp" #include "code/scopeDesc.hpp" #include "compiler/abstractCompiler.hpp" @@ -46,11 +47,27 @@ #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" +#ifdef TARGET_ARCH_x86 +# include "nativeInst_x86.hpp" +#endif +#ifdef TARGET_ARCH_sparc +# include "nativeInst_sparc.hpp" +#endif +#ifdef TARGET_ARCH_zero +# include "nativeInst_zero.hpp" +#endif +#ifdef TARGET_ARCH_arm +# include "nativeInst_arm.hpp" +#endif +#ifdef TARGET_ARCH_ppc +# include "nativeInst_ppc.hpp" +#endif #ifdef SHARK #include "shark/sharkCompiler.hpp" #endif - -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#endif unsigned char nmethod::_global_unloading_clock = 0; @@ -84,6 +101,11 @@ } return compiler()->is_c1(); } +bool nmethod::is_compiled_by_jvmci() const { + if (compiler() == NULL || method() == NULL) return false; // can happen during debug printing + if (is_native_method()) return false; + return compiler()->is_jvmci(); +} bool nmethod::is_compiled_by_c2() const { if (compiler() == NULL) { return false; @@ -108,8 +130,7 @@ #ifndef PRODUCT // These variables are put into one block to reduce relocations // and make it simpler to print from the debugger. -static -struct nmethod_stats_struct { +struct java_nmethod_stats_struct { int nmethod_count; int total_size; int relocation_size; @@ -122,6 +143,7 @@ int handler_table_size; int nul_chk_table_size; int oops_size; + int metadata_size; void note_nmethod(nmethod* nm) { nmethod_count += 1; @@ -131,39 +153,46 @@ insts_size += nm->insts_size(); stub_size += nm->stub_size(); oops_size += nm->oops_size(); + metadata_size += nm->metadata_size(); scopes_data_size += nm->scopes_data_size(); scopes_pcs_size += nm->scopes_pcs_size(); dependencies_size += nm->dependencies_size(); handler_table_size += nm->handler_table_size(); nul_chk_table_size += nm->nul_chk_table_size(); } - void print_nmethod_stats() { + void print_nmethod_stats(const char* name) { if (nmethod_count == 0) return; - tty->print_cr("Statistics for %d bytecoded nmethods:", nmethod_count); + tty->print_cr("Statistics for %d bytecoded nmethods for %s:", nmethod_count, name); if (total_size != 0) tty->print_cr(" total in heap = %d", total_size); + if (nmethod_count != 0) tty->print_cr(" header = " SIZE_FORMAT, nmethod_count * sizeof(nmethod)); if (relocation_size != 0) tty->print_cr(" relocation = %d", relocation_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 (metadata_size != 0) tty->print_cr(" metadata = %d", metadata_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); if (dependencies_size != 0) tty->print_cr(" dependencies = %d", dependencies_size); if (handler_table_size != 0) tty->print_cr(" handler table = %d", handler_table_size); if (nul_chk_table_size != 0) tty->print_cr(" nul chk table = %d", nul_chk_table_size); } - +}; + +struct native_nmethod_stats_struct { int native_nmethod_count; int native_total_size; int native_relocation_size; int native_insts_size; int native_oops_size; + int native_metadata_size; void note_native_nmethod(nmethod* nm) { native_nmethod_count += 1; native_total_size += nm->size(); native_relocation_size += nm->relocation_size(); native_insts_size += nm->insts_size(); native_oops_size += nm->oops_size(); + native_metadata_size += nm->metadata_size(); } void print_native_nmethod_stats() { if (native_nmethod_count == 0) return; @@ -172,8 +201,11 @@ if (native_relocation_size != 0) tty->print_cr(" N. relocation = %d", native_relocation_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); + if (native_metadata_size != 0) tty->print_cr(" N. metadata = %d", native_metadata_size); } - +}; + +struct pc_nmethod_stats_struct { int pc_desc_resets; // number of resets (= number of caches) int pc_desc_queries; // queries to nmethod::find_pc_desc int pc_desc_approx; // number of those which have approximate true @@ -194,9 +226,51 @@ pc_desc_repeats, pc_desc_hits, pc_desc_tests, pc_desc_searches, pc_desc_adds); } -} nmethod_stats; -#endif //PRODUCT - +}; + +#ifdef COMPILER1 +static java_nmethod_stats_struct c1_java_nmethod_stats; +#endif +#ifdef COMPILER2 +static java_nmethod_stats_struct c2_java_nmethod_stats; +#endif +#if INCLUDE_JVMCI +static java_nmethod_stats_struct jvmci_java_nmethod_stats; +#endif +#ifdef SHARK +static java_nmethod_stats_struct shark_java_nmethod_stats; +#endif +static java_nmethod_stats_struct unknown_java_nmethod_stats; + +static native_nmethod_stats_struct native_nmethod_stats; +static pc_nmethod_stats_struct pc_nmethod_stats; + +static void note_java_nmethod(nmethod* nm) { +#ifdef COMPILER1 + if (nm->is_compiled_by_c1()) { + c1_java_nmethod_stats.note_nmethod(nm); + } else +#endif +#ifdef COMPILER2 + if (nm->is_compiled_by_c2()) { + c2_java_nmethod_stats.note_nmethod(nm); + } else +#endif +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci()) { + jvmci_java_nmethod_stats.note_nmethod(nm); + } else +#endif +#ifdef SHARK + if (nm->is_compiled_by_shark()) { + shark_java_nmethod_stats.note_nmethod(nm); + } else +#endif + { + unknown_java_nmethod_stats.note_nmethod(nm); + } +} +#endif // !PRODUCT //--------------------------------------------------------------------------------- @@ -276,7 +350,7 @@ // Helper used by both find_pc_desc methods. static inline bool match_desc(PcDesc* pc, int pc_offset, bool approximate) { - NOT_PRODUCT(++nmethod_stats.pc_desc_tests); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_tests); if (!approximate) return pc->pc_offset() == pc_offset; else @@ -288,7 +362,7 @@ _pc_descs[0] = NULL; // native method; no PcDescs at all return; } - NOT_PRODUCT(++nmethod_stats.pc_desc_resets); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_resets); // reset the cache by filling it with benign (non-null) values assert(initial_pc_desc->pc_offset() < 0, "must be sentinel"); for (int i = 0; i < cache_size; i++) @@ -296,8 +370,8 @@ } PcDesc* PcDescCache::find_pc_desc(int pc_offset, bool approximate) { - NOT_PRODUCT(++nmethod_stats.pc_desc_queries); - NOT_PRODUCT(if (approximate) ++nmethod_stats.pc_desc_approx); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_queries); + NOT_PRODUCT(if (approximate) ++pc_nmethod_stats.pc_desc_approx); // Note: one might think that caching the most recently // read value separately would be a win, but one would be @@ -313,7 +387,7 @@ res = _pc_descs[0]; if (res == NULL) return NULL; // native method; no PcDescs at all if (match_desc(res, pc_offset, approximate)) { - NOT_PRODUCT(++nmethod_stats.pc_desc_repeats); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_repeats); return res; } @@ -322,7 +396,7 @@ res = _pc_descs[i]; if (res->pc_offset() < 0) break; // optimization: skip empty cache if (match_desc(res, pc_offset, approximate)) { - NOT_PRODUCT(++nmethod_stats.pc_desc_hits); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_hits); return res; } } @@ -332,7 +406,7 @@ } void PcDescCache::add_pc_desc(PcDesc* pc_desc) { - NOT_PRODUCT(++nmethod_stats.pc_desc_adds); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_adds); // Update the LRU cache by shifting pc_desc forward. for (int i = 0; i < cache_size; i++) { PcDesc* next = _pc_descs[i]; @@ -459,7 +533,7 @@ _marked_for_deoptimization = 0; _lock_count = 0; _stack_traversal_mark = 0; - _unload_reported = false; // jvmti state + _unload_reported = false; // jvmti state #ifdef ASSERT _oops_are_stale = false; @@ -478,6 +552,10 @@ #if INCLUDE_RTM_OPT _rtm_state = NoRTM; #endif +#if INCLUDE_JVMCI + _jvmci_installed_code = NULL; + _speculation_log = NULL; +#endif } nmethod* nmethod::new_native_nmethod(methodHandle method, @@ -503,7 +581,7 @@ code_buffer, frame_size, basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); - NOT_PRODUCT(if (nm != NULL) nmethod_stats.note_native_nmethod(nm)); + NOT_PRODUCT(if (nm != NULL) native_nmethod_stats.note_native_nmethod(nm)); if ((PrintAssembly || CompilerOracle::should_print(method)) && nm != NULL) { Disassembler::decode(nm); } @@ -531,6 +609,10 @@ ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, int comp_level +#if INCLUDE_JVMCI + , Handle installed_code, + Handle speculationLog +#endif ) { assert(debug_info->oop_recorder() == code_buffer->oop_recorder(), "shared OR"); @@ -553,7 +635,12 @@ handler_table, nul_chk_table, compiler, - comp_level); + comp_level +#if INCLUDE_JVMCI + , installed_code, + speculationLog +#endif + ); if (nm != NULL) { // To make dependency checking during class loading fast, record @@ -578,7 +665,7 @@ InstanceKlass::cast(klass)->add_dependent_nmethod(nm); } } - NOT_PRODUCT(nmethod_stats.note_nmethod(nm)); + NOT_PRODUCT(if (nm != NULL) note_java_nmethod(nm)); if (PrintAssembly || CompilerOracle::has_option_string(method, "PrintAssembly")) { Disassembler::decode(nm); } @@ -593,7 +680,10 @@ return nm; } - +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4355) // warning C4355: 'this' : used in base member initializer list +#endif // For native wrappers nmethod::nmethod( Method* method, @@ -683,6 +773,10 @@ } } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + void* nmethod::operator new(size_t size, int nmethod_size, int comp_level) throw () { return CodeCache::allocate(nmethod_size, CodeCache::get_code_blob_type(comp_level)); } @@ -703,6 +797,10 @@ ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, int comp_level +#if INCLUDE_JVMCI + , Handle installed_code, + Handle speculation_log +#endif ) : CodeBlob("nmethod", code_buffer, sizeof(nmethod), nmethod_size, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps), @@ -727,15 +825,42 @@ _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); _stub_offset = content_offset() + code_buffer->total_offset_of(code_buffer->stubs()); +#if INCLUDE_JVMCI + _jvmci_installed_code = installed_code(); + _speculation_log = (instanceOop)speculation_log(); + + if (compiler->is_jvmci()) { + // JVMCI might not produce any stub sections + if (offsets->value(CodeOffsets::Exceptions) != -1) { + _exception_offset = code_offset() + offsets->value(CodeOffsets::Exceptions); + } else { + _exception_offset = -1; + } + if (offsets->value(CodeOffsets::Deopt) != -1) { + _deoptimize_offset = code_offset() + offsets->value(CodeOffsets::Deopt); + } else { + _deoptimize_offset = -1; + } + if (offsets->value(CodeOffsets::DeoptMH) != -1) { + _deoptimize_mh_offset = code_offset() + offsets->value(CodeOffsets::DeoptMH); + } else { + _deoptimize_mh_offset = -1; + } + } else { +#endif // Exception handler and deopt handler are in the stub section assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set"); assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set"); + _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); _deoptimize_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); if (offsets->value(CodeOffsets::DeoptMH) != -1) { _deoptimize_mh_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH); } else { _deoptimize_mh_offset = -1; +#if INCLUDE_JVMCI + } +#endif } if (offsets->value(CodeOffsets::UnwindHandler) != -1) { _unwind_handler_offset = code_offset() + offsets->value(CodeOffsets::UnwindHandler); @@ -779,12 +904,12 @@ // we use the information of entry points to find out if a method is // static or non static - assert(compiler->is_c2() || + assert(compiler->is_c2() || compiler->is_jvmci() || _method->is_static() == (entry_point() == _verified_entry_point), " entry points must be same for static methods and vice versa"); } - bool printnmethods = PrintNMethods + bool printnmethods = PrintNMethods || PrintNMethodsAtLevel == _comp_level || CompilerOracle::should_print(_method) || CompilerOracle::has_option_string(_method, "PrintNMethods"); if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { @@ -792,7 +917,6 @@ } } - // Print a short set of xml attributes to identify this nmethod. The // output should be embedded in some other element. void nmethod::log_identity(xmlStream* log) const { @@ -809,9 +933,9 @@ #define LOG_OFFSET(log, name) \ - if ((intptr_t)name##_end() - (intptr_t)name##_begin()) \ - log->print(" " XSTR(name) "_offset='%d'" , \ - (intptr_t)name##_begin() - (intptr_t)this) + if (p2i(name##_end()) - p2i(name##_begin())) \ + log->print(" " XSTR(name) "_offset='" INTX_FORMAT "'" , \ + p2i(name##_begin()) - p2i(this)) void nmethod::log_new_nmethod() const { @@ -820,8 +944,8 @@ HandleMark hm; xtty->begin_elem("nmethod"); log_identity(xtty); - xtty->print(" entry='" INTPTR_FORMAT "' size='%d'", code_begin(), size()); - xtty->print(" address='" INTPTR_FORMAT "'", (intptr_t) this); + xtty->print(" entry='" INTPTR_FORMAT "' size='%d'", p2i(code_begin()), size()); + xtty->print(" address='" INTPTR_FORMAT "'", p2i(this)); LOG_OFFSET(xtty, relocation); LOG_OFFSET(xtty, consts); @@ -833,6 +957,7 @@ LOG_OFFSET(xtty, handler_table); LOG_OFFSET(xtty, nul_chk_table); LOG_OFFSET(xtty, oops); + LOG_OFFSET(xtty, metadata); xtty->method(method()); xtty->stamp(); @@ -849,7 +974,7 @@ ttyLocker ttyl; if (WizardMode) { CompileTask::print(st, this, msg, /*short_form:*/ true); - st->print_cr(" (" INTPTR_FORMAT ")", this); + st->print_cr(" (" INTPTR_FORMAT ")", p2i(this)); } else { CompileTask::print(st, this, msg, /*short_form:*/ false); } @@ -874,13 +999,13 @@ oop_maps()->print(); } } - if (PrintDebugInfo) { + if (PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) { print_scopes(); } - if (PrintRelocations) { + if (PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) { print_relocations(); } - if (PrintDependencies) { + if (PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) { print_dependencies(); } if (PrintExceptionHandlers) { @@ -990,7 +1115,7 @@ PcDesc* pd = pc_desc_at(pc); guarantee(pd != NULL, "scope must be present"); return new ScopeDesc(this, pd->scope_decode_offset(), - pd->obj_decode_offset(), pd->should_reexecute(), + pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(), pd->return_oop()); } @@ -1161,7 +1286,7 @@ } void nmethod::inc_decompile_count() { - if (!is_compiled_by_c2()) return; + if (!is_compiled_by_c2() && !is_compiled_by_jvmci()) return; // Could be gated by ProfileTraps, but do not bother... Method* m = method(); if (m == NULL) return; @@ -1205,7 +1330,7 @@ tty->print_cr("[Class unloading: Making nmethod " INTPTR_FORMAT " unloadable], Method*(" INTPTR_FORMAT "), cause(" INTPTR_FORMAT ")", - this, (address)_method, (address)cause); + p2i(this), p2i(_method), p2i(cause)); if (!Universe::heap()->is_gc_active()) cause->klass()->print(); } @@ -1225,6 +1350,7 @@ } _method = NULL; // Clear the method of this dead nmethod } + // Make the class unloaded - i.e., change state and notify sweeper assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); if (is_in_use()) { @@ -1237,6 +1363,18 @@ // Unregister must be done before the state change Universe::heap()->unregister_nmethod(this); +#if INCLUDE_JVMCI + // The method can only be unloaded after the pointer to the installed code + // Java wrapper is no longer alive. Here we need to clear out this weak + // reference to the dead object. Nulling out the reference has to happen + // after the method is unregistered since the original value may be still + // tracked by the rset. + if (_jvmci_installed_code != NULL) { + InstalledCode::set_address(_jvmci_installed_code, 0); + _jvmci_installed_code = NULL; + } +#endif + _state = unloaded; // Log the unloading. @@ -1400,9 +1538,16 @@ } else { assert(state == not_entrant, "other cases may need to be handled differently"); } +#if INCLUDE_JVMCI + if (_jvmci_installed_code != NULL) { + // Break the link between nmethod and InstalledCode such that the nmethod can subsequently be flushed safely. + InstalledCode::set_address(_jvmci_installed_code, 0); + } +#endif if (TraceCreateZombies) { - tty->print_cr("nmethod <" INTPTR_FORMAT "> code made %s", this, (state == not_entrant) ? "not entrant" : "zombie"); + ResourceMark m; + tty->print_cr("nmethod <" INTPTR_FORMAT "> %s code made %s", p2i(this), this->method() ? this->method()->name_and_sig_as_C_string() : "null", (state == not_entrant) ? "not entrant" : "zombie"); } NMethodSweeper::report_state_change(this); @@ -1418,10 +1563,12 @@ assert_locked_or_safepoint(CodeCache_lock); // completely deallocate this method - Events::log(JavaThread::current(), "flushing nmethod " INTPTR_FORMAT, this); + Events::log(JavaThread::current(), "flushing nmethod " INTPTR_FORMAT, p2i(this)); if (PrintMethodFlushing) { - tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT "/Free CodeCache:" SIZE_FORMAT "Kb", - _compile_id, this, CodeCache::nof_blobs(), CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(this))/1024); + tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT + "/Free CodeCache:" SIZE_FORMAT "Kb", + _compile_id, p2i(this), CodeCache::nof_blobs(), + CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(this))/1024); } // We need to deallocate any ExceptionCache data. @@ -1690,6 +1837,33 @@ } } +#if INCLUDE_JVMCI + // Follow JVMCI method + BarrierSet* bs = Universe::heap()->barrier_set(); + if (_jvmci_installed_code != NULL) { + if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { + if (!is_alive->do_object_b(_jvmci_installed_code)) { + bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); + _jvmci_installed_code = NULL; + bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + } + } else { + if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { + return; + } + } + } + + if (_speculation_log != NULL) { + if (!is_alive->do_object_b(_speculation_log)) { + bs->write_ref_nmethod_pre(&_speculation_log, this); + _speculation_log = NULL; + bs->write_ref_nmethod_post(&_speculation_log, this); + } + } +#endif + + // Ensure that all metadata is still alive verify_metadata_loaders(low_boundary, is_alive); } @@ -1709,7 +1883,7 @@ // Clean inline caches pointing to both zombie and not_entrant methods if (!nm->is_in_use() || (nm->method()->code() != nm)) { ic->set_to_clean(); - assert(ic->is_clean(), err_msg("nmethod " PTR_FORMAT "not clean %s", from, from->method()->name_and_sig_as_C_string())); + assert(ic->is_clean(), "nmethod " PTR_FORMAT "not clean %s", p2i(from), from->method()->name_and_sig_as_C_string()); } } @@ -1772,6 +1946,27 @@ unloading_occurred = true; } +#if INCLUDE_JVMCI + // Follow JVMCI method + if (_jvmci_installed_code != NULL) { + if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { + if (!is_alive->do_object_b(_jvmci_installed_code)) { + _jvmci_installed_code = NULL; + } + } else { + if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { + return false; + } + } + } + + if (_speculation_log != NULL) { + if (!is_alive->do_object_b(_speculation_log)) { + _speculation_log = NULL; + } + } +#endif + // Exception cache clean_exception_cache(is_alive); @@ -1829,6 +2024,32 @@ return postponed; } +#if INCLUDE_JVMCI + // Follow JVMCI method + BarrierSet* bs = Universe::heap()->barrier_set(); + if (_jvmci_installed_code != NULL) { + if (_jvmci_installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(_jvmci_installed_code)) { + if (!is_alive->do_object_b(_jvmci_installed_code)) { + bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); + _jvmci_installed_code = NULL; + bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + } + } else { + if (can_unload(is_alive, (oop*)&_jvmci_installed_code, unloading_occurred)) { + is_unloaded = true; + } + } + } + + if (_speculation_log != NULL) { + if (!is_alive->do_object_b(_speculation_log)) { + bs->write_ref_nmethod_pre(&_speculation_log, this); + _speculation_log = NULL; + bs->write_ref_nmethod_post(&_speculation_log, this); + } + } +#endif + // Ensure that all metadata is still alive verify_metadata_loaders(low_boundary, is_alive); @@ -2013,6 +2234,15 @@ // (See comment above.) } +#if INCLUDE_JVMCI + if (_jvmci_installed_code != NULL) { + f->do_oop((oop*) &_jvmci_installed_code); + } + if (_speculation_log != NULL) { + f->do_oop((oop*) &_speculation_log); + } +#endif + RelocIterator iter(this, low_boundary); while (iter.next()) { @@ -2119,8 +2349,8 @@ if (_print_nm == NULL) return; if (!_detected_scavenge_root) _print_nm->print_on(tty, "new scavenge root"); tty->print_cr("" PTR_FORMAT "[offset=%d] detected scavengable oop " PTR_FORMAT " (found at " PTR_FORMAT ")", - _print_nm, (int)((intptr_t)p - (intptr_t)_print_nm), - (void *)(*p), (intptr_t)p); + p2i(_print_nm), (int)((intptr_t)p - (intptr_t)_print_nm), + p2i(*p), p2i(p)); (*p)->print(); } #endif //PRODUCT @@ -2137,7 +2367,7 @@ // called with a frame corresponding to a Java invoke void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { #ifndef SHARK - if (!method()->is_native()) { + if (method() != NULL && !method()->is_native()) { SimpleScopeDesc ssd(this, fr.pc()); Bytecode_invoke call(ssd.method(), ssd.bci()); bool has_receiver = call.has_receiver(); @@ -2203,6 +2433,14 @@ memcpy(scopes_data_begin(), buffer, size); } +// When using JVMCI the address might be off by the size of a call instruction. +bool nmethod::is_deopt_entry(address pc) { + return pc == deopt_handler_begin() +#if INCLUDE_JVMCI + || pc == (deopt_handler_begin() + NativeCall::instruction_size) +#endif + ; +} #ifdef ASSERT static PcDesc* linear_search(nmethod* nm, int pc_offset, bool approximate) { @@ -2211,7 +2449,7 @@ lower += 1; // exclude initial sentinel PcDesc* res = NULL; for (PcDesc* p = lower; p < upper; p++) { - NOT_PRODUCT(--nmethod_stats.pc_desc_tests); // don't count this call to match_desc + NOT_PRODUCT(--pc_nmethod_stats.pc_desc_tests); // don't count this call to match_desc if (match_desc(p, pc_offset, approximate)) { if (res == NULL) res = p; @@ -2258,7 +2496,7 @@ // Use the last successful return as a split point. PcDesc* mid = _pc_desc_cache.last_pc_desc(); - NOT_PRODUCT(++nmethod_stats.pc_desc_searches); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_searches); if (mid->pc_offset() < pc_offset) { lower = mid; } else { @@ -2271,7 +2509,7 @@ for (int step = (1 << (LOG2_RADIX*3)); step > 1; step >>= LOG2_RADIX) { while ((mid = lower + step) < upper) { assert_LU_OK; - NOT_PRODUCT(++nmethod_stats.pc_desc_searches); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_searches); if (mid->pc_offset() < pc_offset) { lower = mid; } else { @@ -2286,7 +2524,7 @@ while (true) { assert_LU_OK; mid = lower + 1; - NOT_PRODUCT(++nmethod_stats.pc_desc_searches); + NOT_PRODUCT(++pc_nmethod_stats.pc_desc_searches); if (mid->pc_offset() < pc_offset) { lower = mid; } else { @@ -2426,7 +2664,7 @@ ResourceMark rm(thread); CodeBlob* cb = CodeCache::find_blob(pc); assert(cb != NULL && cb == this, ""); - tty->print_cr("implicit exception happened at " INTPTR_FORMAT, pc); + tty->print_cr("implicit exception happened at " INTPTR_FORMAT, p2i(pc)); print(); method()->print_codes(); print_code(); @@ -2473,7 +2711,6 @@ assert(nm->_lock_count >= 0, "unmatched nmethod lock/unlock"); } - // ----------------------------------------------------------------------------- // nmethod::get_deopt_original_pc // @@ -2519,7 +2756,7 @@ _ok = false; } tty->print_cr("*** non-oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)", - (void *)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); + p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm)); } virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } }; @@ -2540,7 +2777,7 @@ ResourceMark rm; if (!CodeCache::contains(this)) { - fatal(err_msg("nmethod at " INTPTR_FORMAT " not in zone", this)); + fatal("nmethod at " INTPTR_FORMAT " not in zone", p2i(this)); } if(is_native_method() ) @@ -2548,13 +2785,12 @@ nmethod* nm = CodeCache::find_nmethod(verified_entry_point()); if (nm != this) { - fatal(err_msg("findNMethod did not find this nmethod (" INTPTR_FORMAT ")", - this)); + fatal("findNMethod did not find this nmethod (" INTPTR_FORMAT ")", p2i(this)); } for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) { if (! p->verify(this)) { - tty->print_cr("\t\tin nmethod at " INTPTR_FORMAT " (pcs)", this); + tty->print_cr("\t\tin nmethod at " INTPTR_FORMAT " (pcs)", p2i(this)); } } @@ -2587,7 +2823,7 @@ PcDesc* pd = pc_desc_at(nativeCall_at(call_site)->return_address()); assert(pd != NULL, "PcDesc must exist"); for (ScopeDesc* sd = new ScopeDesc(this, pd->scope_decode_offset(), - pd->obj_decode_offset(), pd->should_reexecute(), + pd->obj_decode_offset(), pd->should_reexecute(), pd->rethrow_exception(), pd->return_oop()); !sd->is_top(); sd = sd->sender()) { sd->verify(); @@ -2643,7 +2879,7 @@ _ok = false; } tty->print_cr("*** scavengable oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)", - (void *)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); + p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm)); (*p)->print(); } virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } @@ -2680,6 +2916,8 @@ tty->print("(c2) "); } else if (is_compiled_by_shark()) { tty->print("(shark) "); + } else if (is_compiled_by_jvmci()) { + tty->print("(JVMCI) "); } else { tty->print("(nm) "); } @@ -2687,8 +2925,8 @@ print_on(tty, NULL); if (WizardMode) { - tty->print("((nmethod*) " INTPTR_FORMAT ") ", this); - tty->print(" for method " INTPTR_FORMAT , (address)method()); + tty->print("((nmethod*) " INTPTR_FORMAT ") ", p2i(this)); + tty->print(" for method " INTPTR_FORMAT , p2i(method())); tty->print(" { "); if (is_in_use()) tty->print("in_use "); if (is_not_entrant()) tty->print("not_entrant "); @@ -2698,52 +2936,52 @@ tty->print_cr("}:"); } if (size () > 0) tty->print_cr(" total in heap [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - (address)this, - (address)this + size(), + p2i(this), + p2i(this) + size(), size()); if (relocation_size () > 0) tty->print_cr(" relocation [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - relocation_begin(), - relocation_end(), + p2i(relocation_begin()), + p2i(relocation_end()), relocation_size()); if (consts_size () > 0) tty->print_cr(" constants [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - consts_begin(), - consts_end(), + p2i(consts_begin()), + p2i(consts_end()), consts_size()); if (insts_size () > 0) tty->print_cr(" main code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - insts_begin(), - insts_end(), + p2i(insts_begin()), + p2i(insts_end()), insts_size()); if (stub_size () > 0) tty->print_cr(" stub code [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - stub_begin(), - stub_end(), + p2i(stub_begin()), + p2i(stub_end()), stub_size()); if (oops_size () > 0) tty->print_cr(" oops [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - oops_begin(), - oops_end(), + p2i(oops_begin()), + p2i(oops_end()), oops_size()); if (metadata_size () > 0) tty->print_cr(" metadata [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - metadata_begin(), - metadata_end(), + p2i(metadata_begin()), + p2i(metadata_end()), metadata_size()); if (scopes_data_size () > 0) tty->print_cr(" scopes data [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - scopes_data_begin(), - scopes_data_end(), + p2i(scopes_data_begin()), + p2i(scopes_data_end()), scopes_data_size()); if (scopes_pcs_size () > 0) tty->print_cr(" scopes pcs [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - scopes_pcs_begin(), - scopes_pcs_end(), + p2i(scopes_pcs_begin()), + p2i(scopes_pcs_end()), scopes_pcs_size()); if (dependencies_size () > 0) tty->print_cr(" dependencies [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - dependencies_begin(), - dependencies_end(), + p2i(dependencies_begin()), + p2i(dependencies_end()), dependencies_size()); if (handler_table_size() > 0) tty->print_cr(" handler table [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - handler_table_begin(), - handler_table_end(), + p2i(handler_table_begin()), + p2i(handler_table_end()), handler_table_size()); if (nul_chk_table_size() > 0) tty->print_cr(" nul chk table [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", - nul_chk_table_begin(), - nul_chk_table_end(), + p2i(nul_chk_table_begin()), + p2i(nul_chk_table_end()), nul_chk_table_size()); } @@ -2764,7 +3002,10 @@ continue; ScopeDesc* sd = scope_desc_at(p->real_pc(this)); - sd->print_on(tty, p); + while (sd != NULL) { + sd->print_on(tty, p); + sd = sd->sender(); + } } } @@ -2794,20 +3035,20 @@ jint* index_end = (jint*)relocation_end() - 1; jint index_size = *index_end; jint* index_start = (jint*)( (address)index_end - index_size ); - tty->print_cr(" index @" INTPTR_FORMAT ": index_size=%d", index_start, index_size); + tty->print_cr(" index @" INTPTR_FORMAT ": index_size=%d", p2i(index_start), index_size); if (index_size > 0) { jint* ip; for (ip = index_start; ip+2 <= index_end; ip += 2) tty->print_cr(" (%d %d) addr=" INTPTR_FORMAT " @" INTPTR_FORMAT, ip[0], ip[1], - header_end()+ip[0], - relocation_begin()-1+ip[1]); + p2i(header_end()+ip[0]), + p2i(relocation_begin()-1+ip[1])); for (; ip < index_end; ip++) tty->print_cr(" (%d ?)", ip[0]); - tty->print_cr(" @" INTPTR_FORMAT ": index_size=%d", ip, *ip); + tty->print_cr(" @" INTPTR_FORMAT ": index_size=%d", p2i(ip), *ip); ip++; - tty->print_cr("reloc_end @" INTPTR_FORMAT ":", ip); + tty->print_cr("reloc_end @" INTPTR_FORMAT ":", p2i(ip)); } } } @@ -2881,7 +3122,7 @@ PcDesc* p = pc_desc_near(begin+1); if (p != NULL && p->real_pc(this) <= end) { return new ScopeDesc(this, p->scope_decode_offset(), - p->obj_decode_offset(), p->should_reexecute(), + p->obj_decode_offset(), p->should_reexecute(), p->rethrow_exception(), p->return_oop()); } return NULL; @@ -2890,9 +3131,9 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) const { if (block_begin == entry_point()) stream->print_cr("[Entry Point]"); if (block_begin == verified_entry_point()) stream->print_cr("[Verified Entry Point]"); - if (block_begin == exception_begin()) stream->print_cr("[Exception Handler]"); + if (JVMCI_ONLY(_exception_offset >= 0 &&) block_begin == exception_begin()) stream->print_cr("[Exception Handler]"); if (block_begin == stub_begin()) stream->print_cr("[Stub Code]"); - if (block_begin == deopt_handler_begin()) stream->print_cr("[Deopt Handler Code]"); + if (JVMCI_ONLY(_deoptimize_offset >= 0 &&) block_begin == deopt_handler_begin()) stream->print_cr("[Deopt Handler Code]"); if (has_method_handle_invokes()) if (block_begin == deopt_mh_handler_begin()) stream->print_cr("[Deopt MH Handler Code]"); @@ -3058,6 +3299,7 @@ } } } + st->print(" {reexecute=%d rethrow=%d return_oop=%d}", sd->should_reexecute(), sd->rethrow_exception(), sd->return_oop()); } // Print all scopes @@ -3089,7 +3331,7 @@ 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, code_begin() + cont_offset); + st->print("; implicit exception: dispatches to " INTPTR_FORMAT, p2i(code_begin() + cont_offset)); } } @@ -3112,7 +3354,7 @@ break; } case relocInfo::static_call_type: - st->print_cr("Static call at " INTPTR_FORMAT, iter.reloc()->addr()); + st->print_cr("Static call at " INTPTR_FORMAT, p2i(iter.reloc()->addr())); compiledStaticCall_at(iter.reloc())->print(); break; } @@ -3130,12 +3372,49 @@ void nmethod::print_statistics() { ttyLocker ttyl; if (xtty != NULL) xtty->head("statistics type='nmethod'"); - nmethod_stats.print_native_nmethod_stats(); - nmethod_stats.print_nmethod_stats(); + native_nmethod_stats.print_native_nmethod_stats(); +#ifdef COMPILER1 + c1_java_nmethod_stats.print_nmethod_stats("C1"); +#endif +#ifdef COMPILER2 + c2_java_nmethod_stats.print_nmethod_stats("C2"); +#endif +#if INCLUDE_JVMCI + jvmci_java_nmethod_stats.print_nmethod_stats("JVMCI"); +#endif +#ifdef SHARK + shark_java_nmethod_stats.print_nmethod_stats("Shark"); +#endif + unknown_java_nmethod_stats.print_nmethod_stats("Unknown"); DebugInformationRecorder::print_statistics(); - nmethod_stats.print_pc_stats(); +#ifndef PRODUCT + pc_nmethod_stats.print_pc_stats(); +#endif Dependencies::print_statistics(); if (xtty != NULL) xtty->tail("statistics"); } -#endif // PRODUCT +#endif // !PRODUCT + +#if INCLUDE_JVMCI +char* nmethod::jvmci_installed_code_name(char* buf, size_t buflen) { + if (!this->is_compiled_by_jvmci()) { + return NULL; + } + oop installedCode = this->jvmci_installed_code(); + if (installedCode != NULL) { + oop installedCodeName = NULL; + if (installedCode->is_a(InstalledCode::klass())) { + installedCodeName = InstalledCode::name(installedCode); + } + if (installedCodeName != NULL) { + return java_lang_String::as_utf8_string(installedCodeName, buf, (int)buflen); + } else { + jio_snprintf(buf, buflen, "null"); + return buf; + } + } + jio_snprintf(buf, buflen, "noInstalledCode"); + return buf; +} +#endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/nmethod.hpp --- a/hotspot/src/share/vm/code/nmethod.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/nmethod.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -126,6 +126,12 @@ int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method jmethodID _jmethod_id; // Cache of method()->jmethod_id() +#if INCLUDE_JVMCI + // Needed to keep nmethods alive that are not the default nmethod for the associated Method. + oop _jvmci_installed_code; + oop _speculation_log; +#endif + // To support simple linked-list chaining of nmethods: nmethod* _osr_link; // from InstanceKlass::osr_nmethods_head @@ -273,7 +279,12 @@ ExceptionHandlerTable* handler_table, ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, - int comp_level); + int comp_level +#if INCLUDE_JVMCI + , Handle installed_code, + Handle speculation_log +#endif + ); // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); @@ -309,7 +320,12 @@ ExceptionHandlerTable* handler_table, ImplicitExceptionTable* nul_chk_table, AbstractCompiler* compiler, - int comp_level); + int comp_level +#if INCLUDE_JVMCI + , Handle installed_code = Handle(), + Handle speculation_log = Handle() +#endif + ); static nmethod* new_native_nmethod(methodHandle method, int compile_id, @@ -332,6 +348,7 @@ bool is_osr_method() const { return _entry_bci != InvocationEntryBci; } bool is_compiled_by_c1() const; + bool is_compiled_by_jvmci() const; bool is_compiled_by_c2() const; bool is_compiled_by_shark() const; @@ -582,6 +599,14 @@ // Evolution support. We make old (discarded) compiled methods point to new Method*s. void set_method(Method* method) { _method = method; } +#if INCLUDE_JVMCI + oop jvmci_installed_code() { return _jvmci_installed_code ; } + char* jvmci_installed_code_name(char* buf, size_t buflen); + void set_jvmci_installed_code(oop installed_code) { _jvmci_installed_code = installed_code; } + oop speculation_log() { return _speculation_log ; } + void set_speculation_log(oop speculation_log) { _speculation_log = speculation_log; } +#endif + // GC support void do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred); // The parallel versions are used by G1. @@ -639,7 +664,7 @@ // Deopt // Return true is the PC is one would expect if the frame is being deopted. bool is_deopt_pc (address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } - bool is_deopt_entry (address pc) { return pc == deopt_handler_begin(); } + bool is_deopt_entry (address pc); bool is_deopt_mh_entry(address pc) { return pc == deopt_mh_handler_begin(); } // Accessor/mutator for the original pc of a frame before a frame was deopted. address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); } @@ -690,7 +715,7 @@ // Prints a comment for one native instruction (reloc info, pc desc) void print_code_comment_on(outputStream* st, int column, address begin, address end); - static void print_statistics() PRODUCT_RETURN; + static void print_statistics() PRODUCT_RETURN; // Compiler task identification. Note that all OSR methods // are numbered in an independent sequence if CICountOSR is true, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/oopRecorder.cpp --- a/hotspot/src/share/vm/code/oopRecorder.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/oopRecorder.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -157,3 +157,48 @@ // Explicitly instantiate these types template class ValueRecorder; template class ValueRecorder; + +oop ObjectLookup::ObjectEntry::oop_value() const { return JNIHandles::resolve(_value); } + +ObjectLookup::ObjectLookup(): _gc_count(Universe::heap()->total_collections()), _values(4) {} + +void ObjectLookup::maybe_resort() { + // The values are kept sorted by address which may be invalidated + // after a GC, so resort if a GC has occurred since last time. + if (_gc_count != Universe::heap()->total_collections()) { + _gc_count = Universe::heap()->total_collections(); + _values.sort(sort_by_address); + } +} + +int ObjectLookup::sort_by_address(oop a, oop b) { + if (b > a) return 1; + if (a > b) return -1; + return 0; +} + +int ObjectLookup::sort_by_address(ObjectEntry* a, ObjectEntry* b) { + return sort_by_address(a->oop_value(), b->oop_value()); +} + +int ObjectLookup::sort_oop_by_address(oop const& a, ObjectEntry const& b) { + return sort_by_address(a, b.oop_value()); +} + +int ObjectLookup::find_index(jobject handle, OopRecorder* oop_recorder) { + if (handle == NULL) { + return 0; + } + oop object = JNIHandles::resolve(handle); + maybe_resort(); + bool found; + int location = _values.find_sorted(object, found); + if (!found) { + jobject handle = JNIHandles::make_local(object); + ObjectEntry r(handle, oop_recorder->allocate_oop_index(handle)); + _values.insert_before(location, r); + return r.index(); + } + return _values.at(location).index(); +} + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/oopRecorder.hpp --- a/hotspot/src/share/vm/code/oopRecorder.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/oopRecorder.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -146,18 +146,57 @@ #endif }; +class OopRecorder; + +class ObjectLookup : public ResourceObj { + private: + class ObjectEntry { + private: + jobject _value; + int _index; + + public: + ObjectEntry(jobject value, int index) : _value(value), _index(index) {} + ObjectEntry() : _value(NULL), _index(0) {} + oop oop_value() const; + int index() { return _index; } + }; + + GrowableArray _values; + unsigned int _gc_count; + + // Utility sort functions + static int sort_by_address(oop a, oop b); + static int sort_by_address(ObjectEntry* a, ObjectEntry* b); + static int sort_oop_by_address(oop const& a, ObjectEntry const& b); + + public: + ObjectLookup(); + + // Resort list if a GC has occurred since the last sort + void maybe_resort(); + int find_index(jobject object, OopRecorder* oop_recorder); +}; + class OopRecorder : public ResourceObj { private: ValueRecorder _oops; ValueRecorder _metadata; + ObjectLookup* _object_lookup; public: - OopRecorder(Arena* arena = NULL): _oops(arena), _metadata(arena) {} + OopRecorder(Arena* arena = NULL, bool deduplicate = false): _oops(arena), _metadata(arena) { + if (deduplicate) { + _object_lookup = new ObjectLookup(); + } else { + _object_lookup = NULL; + } + } int allocate_oop_index(jobject h) { return _oops.allocate_index(h); } - int find_index(jobject h) { - return _oops.find_index(h); + virtual int find_index(jobject h) { + return _object_lookup != NULL ? _object_lookup->find_index(h, this) : _oops.find_index(h); } jobject oop_at(int index) { return _oops.at(index); @@ -175,7 +214,7 @@ int allocate_metadata_index(Metadata* oop) { return _metadata.allocate_index(oop); } - int find_index(Metadata* h) { + virtual int find_index(Metadata* h) { return _metadata.find_index(h); } Metadata* metadata_at(int index) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/pcDesc.cpp --- a/hotspot/src/share/vm/code/pcDesc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/pcDesc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,8 +29,6 @@ #include "code/scopeDesc.hpp" #include "memory/resourceArea.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - PcDesc::PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset) { _pc_offset = pc_offset; _scope_decode_offset = scope_decode_offset; @@ -45,7 +43,7 @@ void PcDesc::print(nmethod* code) { #ifndef PRODUCT ResourceMark rm; - tty->print_cr("PcDesc(pc=0x%lx offset=%x bits=%x):", real_pc(code), pc_offset(), _flags); + tty->print_cr("PcDesc(pc=" PTR_FORMAT " offset=%x bits=%x):", p2i(real_pc(code)), pc_offset(), _flags); if (scope_decode_offset() == DebugInformationRecorder::serialized_null) { return; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/pcDesc.hpp --- a/hotspot/src/share/vm/code/pcDesc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/pcDesc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -42,7 +42,8 @@ enum { PCDESC_reexecute = 1 << 0, PCDESC_is_method_handle_invoke = 1 << 1, - PCDESC_return_oop = 1 << 2 + PCDESC_return_oop = 1 << 2, + PCDESC_rethrow_exception = 1 << 3 }; int _flags; @@ -71,6 +72,8 @@ }; // Flags + bool rethrow_exception() const { return (_flags & PCDESC_rethrow_exception) != 0; } + void set_rethrow_exception(bool z) { set_flag(PCDESC_rethrow_exception, z); } bool should_reexecute() const { return (_flags & PCDESC_reexecute) != 0; } void set_should_reexecute(bool z) { set_flag(PCDESC_reexecute, z); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/relocInfo.cpp --- a/hotspot/src/share/vm/code/relocInfo.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/relocInfo.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,8 +30,7 @@ #include "memory/resourceArea.hpp" #include "runtime/stubCodeGenerator.hpp" #include "utilities/copy.hpp" - -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#include "oops/oop.inline.hpp" const RelocationHolder RelocationHolder::none; // its type is relocInfo::none @@ -424,6 +423,30 @@ ShouldNotReachHere(); } +void Relocation::const_set_data_value(address x) { +#ifdef _LP64 + if (format() == relocInfo::narrow_oop_in_const) { + *(narrowOop*)addr() = oopDesc::encode_heap_oop((oop) x); + } else { +#endif + *(address*)addr() = x; +#ifdef _LP64 + } +#endif +} + +void Relocation::const_verify_data_value(address x) { +#ifdef _LP64 + if (format() == relocInfo::narrow_oop_in_const) { + assert(*(narrowOop*)addr() == oopDesc::encode_heap_oop((oop) x), "must agree"); + } else { +#endif + assert(*(address*)addr() == x, "must agree"); +#ifdef _LP64 + } +#endif +} + RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { if (rtype == relocInfo::none) return RelocationHolder::none; @@ -447,7 +470,7 @@ // Known "miscellaneous" non-stub pointers: // os::get_polling_page(), SafepointSynchronize::address_of_state() if (PrintRelocations) { - tty->print_cr("random unregistered address in relocInfo: " INTPTR_FORMAT, runtime_address); + tty->print_cr("random unregistered address in relocInfo: " INTPTR_FORMAT, p2i(runtime_address)); } #ifndef _LP64 return (int32_t) (intptr_t)runtime_address; @@ -580,7 +603,8 @@ void static_stub_Relocation::unpack_data() { address base = binding()->section_start(CodeBuffer::SECT_INSTS); - _static_call = address_from_scaled_offset(unpack_1_int(), base); + jint offset = unpack_1_int(); + _static_call = address_from_scaled_offset(offset, base); } void trampoline_stub_Relocation::pack_data_to(CodeSection* dest ) { @@ -794,7 +818,8 @@ RelocIterator iter(code()); while (iter.next()) { if (iter.type() == relocInfo::static_stub_type) { - if (iter.static_stub_reloc()->static_call() == static_call_addr) { + static_stub_Relocation* stub_reloc = iter.static_stub_reloc(); + if (stub_reloc->static_call() == static_call_addr) { return iter.addr(); } } @@ -816,7 +841,8 @@ RelocIterator iter(code()); while (iter.next()) { if (iter.type() == relocInfo::static_stub_type) { - if (iter.static_stub_reloc()->static_call() == static_call_addr) { + static_stub_Relocation* stub_reloc = iter.static_stub_reloc(); + if (stub_reloc->static_call() == static_call_addr) { return iter.addr(); } } @@ -925,7 +951,7 @@ return; } tty->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d", - _current, type(), reloc_type_string((relocInfo::relocType) type()), _addr, _current->addr_offset()); + p2i(_current), type(), reloc_type_string((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset()); if (current()->format() != 0) tty->print(" format=%d", current()->format()); if (datalen() == 1) { @@ -951,11 +977,11 @@ oop_value = r->oop_value(); } tty->print(" | [oop_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT " offset=%d]", - oop_addr, (address)raw_oop, r->offset()); + p2i(oop_addr), p2i(raw_oop), r->offset()); // Do not print the oop by default--we want this routine to // work even during GC or other inconvenient times. if (WizardMode && oop_value != NULL) { - tty->print("oop_value=" INTPTR_FORMAT ": ", (address)oop_value); + tty->print("oop_value=" INTPTR_FORMAT ": ", p2i(oop_value)); oop_value->print_value_on(tty); } break; @@ -972,9 +998,9 @@ metadata_value = r->metadata_value(); } tty->print(" | [metadata_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT " offset=%d]", - metadata_addr, (address)raw_metadata, r->offset()); + p2i(metadata_addr), p2i(raw_metadata), r->offset()); if (metadata_value != NULL) { - tty->print("metadata_value=" INTPTR_FORMAT ": ", (address)metadata_value); + tty->print("metadata_value=" INTPTR_FORMAT ": ", p2i(metadata_value)); metadata_value->print_value_on(tty); } break; @@ -984,33 +1010,33 @@ case relocInfo::section_word_type: { DataRelocation* r = (DataRelocation*) reloc(); - tty->print(" | [target=" INTPTR_FORMAT "]", r->value()); //value==target + tty->print(" | [target=" INTPTR_FORMAT "]", p2i(r->value())); //value==target break; } case relocInfo::static_call_type: case relocInfo::runtime_call_type: { CallRelocation* r = (CallRelocation*) reloc(); - tty->print(" | [destination=" INTPTR_FORMAT "]", r->destination()); + tty->print(" | [destination=" INTPTR_FORMAT "]", p2i(r->destination())); break; } case relocInfo::virtual_call_type: { virtual_call_Relocation* r = (virtual_call_Relocation*) reloc(); tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT "]", - r->destination(), r->cached_value()); + p2i(r->destination()), p2i(r->cached_value())); break; } case relocInfo::static_stub_type: { static_stub_Relocation* r = (static_stub_Relocation*) reloc(); - tty->print(" | [static_call=" INTPTR_FORMAT "]", r->static_call()); + tty->print(" | [static_call=" INTPTR_FORMAT "]", p2i(r->static_call())); break; } case relocInfo::trampoline_stub_type: { trampoline_stub_Relocation* r = (trampoline_stub_Relocation*) reloc(); - tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", r->owner()); + tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", p2i(r->owner())); break; } } @@ -1029,7 +1055,7 @@ got_next = (skip_next || next()); skip_next = false; - tty->print(" @" INTPTR_FORMAT ": ", scan); + tty->print(" @" INTPTR_FORMAT ": ", p2i(scan)); relocInfo* newscan = _current+1; if (!has_current()) newscan -= 1; // nothing to scan here! while (scan < newscan) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/relocInfo.hpp --- a/hotspot/src/share/vm/code/relocInfo.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/relocInfo.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -210,6 +210,11 @@ // See [About Offsets] below. // //%note reloc_2 // +// relocInfo::poll_[return_]type -- a safepoint poll +// Value: none +// Instruction types: memory load or test +// Data: none +// // For example: // // INSTRUCTIONS RELOC: TYPE PREFIX DATA @@ -443,6 +448,11 @@ }; public: enum { +#ifdef _LP64 + // for use in format + // format_width must be at least 1 on _LP64 + narrow_oop_in_const = 1, +#endif // Conservatively large estimate of maximum length (in shorts) // of any relocation record. // Extended format is length prefix, data words, and tag/offset suffix. @@ -525,19 +535,19 @@ typedef relocInfo::relocType relocType; private: - address _limit; // stop producing relocations after this _addr - relocInfo* _current; // the current relocation information - relocInfo* _end; // end marker; we're done iterating when _current == _end - nmethod* _code; // compiled method containing _addr - address _addr; // instruction to which the relocation applies - short _databuf; // spare buffer for compressed data - short* _data; // pointer to the relocation's data - short _datalen; // number of halfwords in _data - char _format; // position within the instruction + address _limit; // stop producing relocations after this _addr + relocInfo* _current; // the current relocation information + relocInfo* _end; // end marker; we're done iterating when _current == _end + nmethod* _code; // compiled method containing _addr + address _addr; // instruction to which the relocation applies + short _databuf; // spare buffer for compressed data + short* _data; // pointer to the relocation's data + short _datalen; // number of halfwords in _data + char _format; // position within the instruction // Base addresses needed to compute targets of section_word_type relocs. - address _section_start[SECT_LIMIT]; - address _section_end [SECT_LIMIT]; + address _section_start[SECT_LIMIT]; + address _section_end [SECT_LIMIT]; void set_has_current(bool b) { _datalen = !b ? -1 : 0; @@ -565,7 +575,7 @@ public: // constructor - RelocIterator(nmethod* nm, address begin = NULL, address limit = NULL); + RelocIterator(nmethod* nm, address begin = NULL, address limit = NULL); RelocIterator(CodeSection* cb, address begin = NULL, address limit = NULL); // get next reloc info, return !eos @@ -762,6 +772,9 @@ } protected: + // platform-independent utility for patching constant section + void const_set_data_value (address x); + void const_verify_data_value (address x); // platform-dependent utilities for decoding and patching instructions void pd_set_data_value (address x, intptr_t off, bool verify_only = false); // a set or mem-ref void pd_verify_data_value (address x, intptr_t off) { pd_set_data_value(x, off, true); } @@ -872,13 +885,13 @@ void set_value(address x) { set_value(x, offset()); } void set_value(address x, intptr_t o) { if (addr_in_const()) - *(address*)addr() = x; + const_set_data_value(x); else pd_set_data_value(x, o); } void verify_value(address x) { if (addr_in_const()) - assert(*(address*)addr() == x, "must agree"); + const_verify_data_value(x); else pd_verify_data_value(x, offset()); } @@ -1117,7 +1130,7 @@ } private: - address _static_call; // location of corresponding static_call + address _static_call; // location of corresponding static_call static_stub_Relocation(address static_call) { _static_call = static_call; @@ -1318,10 +1331,8 @@ void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); }; -class poll_return_Relocation : public Relocation { - bool is_data() { return true; } +class poll_return_Relocation : public poll_Relocation { relocInfo::relocType type() { return relocInfo::poll_return_type; } - void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest); }; // We know all the xxx_Relocation classes, so now we can define these: diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/scopeDesc.cpp --- a/hotspot/src/share/vm/code/scopeDesc.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/scopeDesc.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,22 +30,22 @@ #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - -ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop) { +ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) { _code = code; _decode_offset = decode_offset; _objects = decode_object_values(obj_decode_offset); _reexecute = reexecute; + _rethrow_exception = rethrow_exception; _return_oop = return_oop; decode_body(); } -ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop) { +ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop) { _code = code; _decode_offset = decode_offset; _objects = decode_object_values(DebugInformationRecorder::serialized_null); _reexecute = reexecute; + _rethrow_exception = rethrow_exception; _return_oop = return_oop; decode_body(); } @@ -56,6 +56,7 @@ _decode_offset = parent->_sender_decode_offset; _objects = parent->_objects; _reexecute = false; //reexecute only applies to the first scope + _rethrow_exception = false; _return_oop = false; decode_body(); } @@ -178,13 +179,13 @@ void ScopeDesc::print_on(outputStream* st, PcDesc* pd) const { // header if (pd != NULL) { - st->print_cr("ScopeDesc(pc=" PTR_FORMAT " offset=%x):", pd->real_pc(_code), pd->pc_offset()); + st->print_cr("ScopeDesc(pc=" PTR_FORMAT " offset=%x):", p2i(pd->real_pc(_code)), pd->pc_offset()); } print_value_on(st); // decode offsets if (WizardMode) { - st->print("ScopeDesc[%d]@" PTR_FORMAT " ", _decode_offset, _code->content_begin()); + st->print("ScopeDesc[%d]@" PTR_FORMAT " ", _decode_offset, p2i(_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"); @@ -227,17 +228,18 @@ } } -#ifdef COMPILER2 - if (DoEscapeAnalysis && is_top() && _objects != NULL) { +#if defined(COMPILER2) || INCLUDE_JVMCI + if (NOT_JVMCI(DoEscapeAnalysis &&) is_top() && _objects != NULL) { st->print_cr(" Objects"); for (int i = 0; i < _objects->length(); i++) { ObjectValue* sv = (ObjectValue*) _objects->at(i); st->print(" - %d: ", sv->id()); + st->print("%s ", java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())->external_name()); sv->print_fields_on(st); st->cr(); } } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI } #endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/scopeDesc.hpp --- a/hotspot/src/share/vm/code/scopeDesc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/scopeDesc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,7 +41,7 @@ int _bci; public: - SimpleScopeDesc(nmethod* code,address pc) { + SimpleScopeDesc(nmethod* code, address pc) { PcDesc* pc_desc = code->pc_desc_at(pc); assert(pc_desc != NULL, "Must be able to find matching PcDesc"); DebugInfoReadStream buffer(code, pc_desc->scope_decode_offset()); @@ -60,17 +60,18 @@ class ScopeDesc : public ResourceObj { public: // Constructor - ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop); + ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool rethrow_exception, bool return_oop); // Calls above, giving default value of "serialized_null" to the // "obj_decode_offset" argument. (We don't use a default argument to // avoid a .hpp-.hpp dependency.) - ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop); + ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool rethrow_exception, bool return_oop); // JVM state Method* method() const { return _method; } int bci() const { return _bci; } bool should_reexecute() const { return _reexecute; } + bool rethrow_exception() const { return _rethrow_exception; } bool return_oop() const { return _return_oop; } GrowableArray* locals(); @@ -95,6 +96,7 @@ Method* _method; int _bci; bool _reexecute; + bool _rethrow_exception; bool _return_oop; // Decoding offsets diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/stubs.cpp --- a/hotspot/src/share/vm/code/stubs.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/stubs.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -67,7 +67,7 @@ intptr_t size = round_to(buffer_size, 2*BytesPerWord); BufferBlob* blob = BufferBlob::create(name, size); if( blob == NULL) { - vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, err_msg("CodeCache: no room for %s", name)); + vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CodeCache: no room for %s", name); } _stub_interface = stub_interface; _buffer_size = blob->content_size(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/code/vtableStubs.cpp --- a/hotspot/src/share/vm/code/vtableStubs.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/code/vtableStubs.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -40,8 +40,6 @@ #include "opto/matcher.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // ----------------------------------------------------------------------------------------- // Implementation of VtableStub @@ -79,8 +77,8 @@ void VtableStub::print_on(outputStream* st) const { - st->print("vtable stub (index = %d, receiver_location = %d, code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "[)", - index(), receiver_location(), code_begin(), code_end()); + st->print("vtable stub (index = %d, receiver_location = " INTX_FORMAT ", code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "[)", + index(), p2i(receiver_location()), p2i(code_begin()), p2i(code_end())); } @@ -126,8 +124,8 @@ enter(is_vtable_stub, vtable_index, s); if (PrintAdapterHandlers) { - tty->print_cr("Decoding VtableStub %s[%d]@%d", - is_vtable_stub? "vtbl": "itbl", vtable_index, VtableStub::receiver_location()); + tty->print_cr("Decoding VtableStub %s[%d]@" INTX_FORMAT, + is_vtable_stub? "vtbl": "itbl", vtable_index, p2i(VtableStub::receiver_location())); Disassembler::decode(s->code_begin(), s->code_end()); } // Notify JVMTI about this stub. The event will be recorded by the enclosing @@ -222,9 +220,9 @@ InstanceKlass* ik = InstanceKlass::cast(klass); klassVtable* vt = ik->vtable(); ik->print(); - fatal(err_msg("bad compiled vtable dispatch: receiver " INTPTR_FORMAT ", " - "index %d (vtable length %d)", - (address)receiver, index, vt->length())); + fatal("bad compiled vtable dispatch: receiver " INTPTR_FORMAT ", " + "index %d (vtable length %d)", + p2i(receiver), index, vt->length()); } -#endif // Product +#endif // PRODUCT diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/abstractCompiler.cpp --- a/hotspot/src/share/vm/compiler/abstractCompiler.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/abstractCompiler.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -58,7 +58,7 @@ } void AbstractCompiler::set_state(int state) { - // Ensure that ste is only set by one thread at a time + // Ensure that state is only set by one thread at a time MutexLocker only_one(CompileThread_lock); _compiler_state = state; CompileThread_lock->notify_all(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/abstractCompiler.hpp --- a/hotspot/src/share/vm/compiler/abstractCompiler.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/abstractCompiler.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * 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,47 @@ #include "ci/compilerInterface.hpp" +typedef void (*initializer)(void); + +#if INCLUDE_JVMCI +// Per-compiler statistics +class CompilerStatistics VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + + class Data VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; + public: + elapsedTimer _time; // time spent compiling + int _bytes; // number of bytecodes compiled, including inlined bytecodes + int _count; // number of compilations + Data() : _bytes(0), _count(0) {} + void update(elapsedTimer time, int bytes) { + _time.add(time); + _bytes += bytes; + _count++; + } + void reset() { + _time.reset(); + } + }; + + public: + Data _standard; // stats for non-OSR compilations + Data _osr; // stats for OSR compilations + int _nmethods_size; // + int _nmethods_code_size; + int bytes_per_second() { + int bytes = _standard._bytes + _osr._bytes; + if (bytes == 0) { + return 0; + } + double seconds = _standard._time.seconds() + _osr._time.seconds(); + return seconds == 0.0 ? 0 : (int) (bytes / seconds); + } + CompilerStatistics() : _nmethods_size(0), _nmethods_code_size(0) {} +}; +#endif // INCLUDE_JVMCI + class AbstractCompiler : public CHeapObj { private: volatile int _num_compiler_threads; @@ -45,12 +86,17 @@ none, c1, c2, + jvmci, shark }; private: Type _type; +#if INCLUDE_JVMCI + CompilerStatistics _stats; +#endif + public: AbstractCompiler(Type type) : _type(type), _compiler_state(uninitialized), _num_compiler_threads(0) {} @@ -115,6 +161,7 @@ // Compiler type queries. bool is_c1() { return _type == c1; } bool is_c2() { return _type == c2; } + bool is_jvmci() { return _type == jvmci; } bool is_shark() { return _type == shark; } // Customization @@ -138,6 +185,10 @@ virtual void print_timers() { ShouldNotReachHere(); } + +#if INCLUDE_JVMCI + CompilerStatistics* stats() { return &_stats; } +#endif }; #endif // SHARE_VM_COMPILER_ABSTRACTCOMPILER_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/compileBroker.cpp --- a/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -51,6 +51,11 @@ #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "runtime/vframe.hpp" +#endif #ifdef COMPILER2 #include "opto/c2compiler.hpp" #endif @@ -453,41 +458,9 @@ print(tty); } -CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) { - +CompilerCounters::CompilerCounters() { _current_method[0] = '\0'; _compile_type = CompileBroker::no_compile; - - if (UsePerfData) { - ResourceMark rm; - - // create the thread instance name space string - don't create an - // instance subspace if instance is -1 - keeps the adapterThread - // counters from having a ".0" namespace. - const char* thread_i = (instance == -1) ? thread_name : - PerfDataManager::name_space(thread_name, instance); - - - char* name = PerfDataManager::counter_name(thread_i, "method"); - _perf_current_method = - PerfDataManager::create_string_variable(SUN_CI, name, - cmname_buffer_length, - _current_method, CHECK); - - name = PerfDataManager::counter_name(thread_i, "type"); - _perf_compile_type = PerfDataManager::create_variable(SUN_CI, name, - PerfData::U_None, - (jlong)_compile_type, - CHECK); - - name = PerfDataManager::counter_name(thread_i, "time"); - _perf_time = PerfDataManager::create_counter(SUN_CI, name, - PerfData::U_Ticks, CHECK); - - name = PerfDataManager::counter_name(thread_i, "compiles"); - _perf_compiles = PerfDataManager::create_counter(SUN_CI, name, - PerfData::U_Events, CHECK); - } } // ------------------------------------------------------------------ @@ -505,6 +478,30 @@ // 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); + +#if INCLUDE_JVMCI + if (EnableJVMCI) { + // This is creating a JVMCICompiler singleton. + JVMCICompiler* jvmci = new JVMCICompiler(); + + if (UseJVMCICompiler) { + _compilers[1] = jvmci; + if (FLAG_IS_DEFAULT(JVMCIThreads)) { + if (BootstrapJVMCI) { + // JVMCI will bootstrap so give it more threads + c2_count = MIN2(32, os::active_processor_count()); + } + } else { + c2_count = JVMCIThreads; + } + if (FLAG_IS_DEFAULT(JVMCIHostThreads)) { + } else { + c1_count = JVMCIHostThreads; + } + } + } +#endif // INCLUDE_JVMCI + #ifdef COMPILER1 if (c1_count > 0) { _compilers[0] = new Compiler(); @@ -512,8 +509,10 @@ #endif // COMPILER1 #ifdef COMPILER2 - if (c2_count > 0) { - _compilers[1] = new C2Compiler(); + if (true JVMCI_ONLY( && !UseJVMCICompiler)) { + if (c2_count > 0) { + _compilers[1] = new C2Compiler(); + } } #endif // COMPILER2 @@ -733,8 +732,8 @@ const bool compiler_thread = true; for (int i = 0; i < c2_compiler_count; i++) { // Create a name for our thread. - sprintf(name_buffer, "C2 CompilerThread%d", i); - CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK); + sprintf(name_buffer, "%s CompilerThread%d", _compilers[1]->name(), i); + CompilerCounters* counters = new CompilerCounters(); // Shark and C2 make_thread(name_buffer, _c2_compile_queue, counters, _compilers[1], compiler_thread, CHECK); } @@ -742,7 +741,7 @@ 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); + CompilerCounters* counters = new CompilerCounters(); // C1 make_thread(name_buffer, _c1_compile_queue, counters, _compilers[0], compiler_thread, CHECK); } @@ -803,7 +802,7 @@ if (osr_bci != InvocationEntryBci) { tty->print(" osr_bci: %d", osr_bci); } - tty->print(" comment: %s count: %d", comment, hot_count); + tty->print(" level: %d comment: %s count: %d", comp_level, comment, hot_count); if (!hot_method.is_null()) { tty->print(" hot: "); if (hot_method() != method()) { @@ -895,6 +894,41 @@ // Should this thread wait for completion of the compile? blocking = is_compile_blocking(); +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + if (blocking) { + // Don't allow blocking compiles for requests triggered by JVMCI. + if (thread->is_Compiler_thread()) { + blocking = false; + } + + // Don't allow blocking compiles if inside a class initializer or while performing class loading + vframeStream vfst((JavaThread*) thread); + for (; !vfst.at_end(); vfst.next()) { + if (vfst.method()->is_static_initializer() || + (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && + vfst.method()->name() == vmSymbols::loadClass_name())) { + blocking = false; + break; + } + } + + // Don't allow blocking compilation requests to JVMCI + // if JVMCI itself is not yet initialized + if (!JVMCIRuntime::is_HotSpotJVMCIRuntime_initialized() && compiler(comp_level)->is_jvmci()) { + blocking = false; + } + + // Don't allow blocking compilation requests if we are in JVMCIRuntime::shutdown + // to avoid deadlock between compiler thread(s) and threads run at shutdown + // such as the DestroyJavaVM thread. + if (JVMCIRuntime::shutdown_called()) { + blocking = false; + } + } + } +#endif // INCLUDE_JVMCI + // We will enter the compilation in the queue. // 14012000: Note that this sets the queued_for_compile bits in // the target method. We can now reason that a method cannot be @@ -1076,7 +1110,10 @@ // return requested nmethod // We accept a higher level osr method - return osr_bci == InvocationEntryBci ? method->code() : method->lookup_osr_nmethod_for(osr_bci, comp_level, false); + if (osr_bci == InvocationEntryBci) { + return method->code(); + } + return method->lookup_osr_nmethod_for(osr_bci, comp_level, false); } @@ -1157,7 +1194,7 @@ method->print_short_name(tty); tty->cr(); } - method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompilerOracle"); + method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompileCommand"); } return false; @@ -1199,6 +1236,15 @@ #endif } +// ------------------------------------------------------------------ +// CompileBroker::assign_compile_id_unlocked +// +// Public wrapper for assign_compile_id that acquires the needed locks +uint CompileBroker::assign_compile_id_unlocked(Thread* thread, methodHandle method, int osr_bci) { + MutexLocker locker(MethodCompileQueue_lock, thread); + return assign_compile_id(method, osr_bci); +} + /** * Should the current thread block until this compilation request * has been fulfilled? @@ -1436,10 +1482,6 @@ os::hint_no_preempt(); } - // trace per thread time and compile statistics - CompilerCounters* counters = ((CompilerThread*)thread)->counters(); - PerfTraceTimedEvent(counters->time_counter(), counters->compile_counter()); - // Assign the task to the current thread. Mark this compilation // thread as active for the profiler. CompileTaskWrapper ctw(task); @@ -1558,6 +1600,35 @@ tty->print("%s", s.as_string()); } +void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) { + + if (success) { + task->mark_success(); + if (ci_env != NULL) { + task->set_num_inlined_bytecodes(ci_env->num_inlined_bytecodes()); + } + if (_compilation_log != NULL) { + nmethod* code = task->code(); + if (code != NULL) { + _compilation_log->log_nmethod(thread, code); + } + } + } + + // simulate crash during compilation + assert(task->compile_id() != CICrashAt, "just as planned"); + if (event.should_commit()) { + event.set_method(task->method()); + event.set_compileID(task->compile_id()); + event.set_compileLevel(task->comp_level()); + event.set_succeded(task->is_success()); + event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci); + event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size()); + event.set_inlinedBytes(task->num_inlined_bytecodes()); + event.commit(); + } +} + // ------------------------------------------------------------------ // CompileBroker::invoke_compiler_on_method // @@ -1606,12 +1677,27 @@ push_jni_handle_block(); Method* target_handle = task->method(); int compilable = ciEnv::MethodCompilable; + AbstractCompiler *comp = compiler(task_level); + + int system_dictionary_modification_counter; { - int system_dictionary_modification_counter; - { - MutexLocker locker(Compile_lock, thread); - system_dictionary_modification_counter = SystemDictionary::number_of_modifications(); - } + MutexLocker locker(Compile_lock, thread); + system_dictionary_modification_counter = SystemDictionary::number_of_modifications(); + } +#if INCLUDE_JVMCI + if (UseJVMCICompiler && comp != NULL && comp->is_jvmci()) { + JVMCICompiler* jvmci = (JVMCICompiler*) comp; + + TraceTime t1("compilation", &time); + EventCompilation event; + + JVMCIEnv env(task, system_dictionary_modification_counter); + jvmci->compile_method(target_handle, osr_bci, &env); + + post_compile(thread, task, event, task->code() != NULL, NULL); + } else +#endif // INCLUDE_JVMCI + { NoHandleMark nhm; ThreadToNativeFromVM ttn(thread); @@ -1637,7 +1723,6 @@ TraceTime t1("compilation", &time); EventCompilation event; - AbstractCompiler *comp = compiler(task_level); if (comp == NULL) { ci_env.record_method_not_compilable("no compiler", !TieredCompilation); } else { @@ -1669,32 +1754,13 @@ } if (PrintCompilation) { FormatBufferResource msg = retry_message != NULL ? - err_msg_res("COMPILE SKIPPED: %s (%s)", ci_env.failure_reason(), retry_message) : - err_msg_res("COMPILE SKIPPED: %s", ci_env.failure_reason()); + FormatBufferResource("COMPILE SKIPPED: %s (%s)", ci_env.failure_reason(), retry_message) : + FormatBufferResource("COMPILE SKIPPED: %s", ci_env.failure_reason()); task->print(tty, msg); } - } else { - task->mark_success(); - task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes()); - if (_compilation_log != NULL) { - nmethod* code = task->code(); - if (code != NULL) { - _compilation_log->log_nmethod(thread, code); - } - } } - // simulate crash during compilation - assert(task->compile_id() != CICrashAt, "just as planned"); - if (event.should_commit()) { - event.set_method(target->get_Method()); - event.set_compileID(compile_id); - event.set_compileLevel(task->comp_level()); - event.set_succeded(task->is_success()); - event.set_isOsr(is_osr); - event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size()); - event.set_inlinedBytes(task->num_inlined_bytecodes()); - event.commit(); - } + + post_compile(thread, task, event, !ci_env.failing(), &ci_env); } pop_jni_handle_block(); @@ -1945,13 +2011,19 @@ _peak_compilation_time = time.milliseconds() > _peak_compilation_time ? time.milliseconds() : _peak_compilation_time; if (CITime) { + int bytes_compiled = method->code_size() + task->num_inlined_bytecodes(); + JVMCI_ONLY(CompilerStatistics* stats = compiler(task->comp_level())->stats();) if (is_osr) { _t_osr_compilation.add(time); - _sum_osr_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); + _sum_osr_bytes_compiled += bytes_compiled; + JVMCI_ONLY(stats->_osr.update(time, bytes_compiled);) } else { _t_standard_compilation.add(time); _sum_standard_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); + JVMCI_ONLY(stats->_standard.update(time, bytes_compiled);) } + JVMCI_ONLY(stats->_nmethods_size += code->total_size();) + JVMCI_ONLY(stats->_nmethods_code_size += code->insts_size();) } if (UsePerfData) { @@ -2007,22 +2079,106 @@ } } -void CompileBroker::print_times() { +#if INCLUDE_JVMCI +void CompileBroker::print_times(AbstractCompiler* comp) { + CompilerStatistics* stats = comp->stats(); + tty->print_cr(" %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}", + comp->name(), stats->bytes_per_second(), + stats->_standard._time.seconds(), stats->_standard._bytes, stats->_standard._count, + stats->_osr._time.seconds(), stats->_osr._bytes, stats->_osr._count, + stats->_nmethods_size, stats->_nmethods_code_size); + comp->print_timers(); +} +#endif // INCLUDE_JVMCI + +void CompileBroker::print_times(bool per_compiler, bool aggregate) { +#if INCLUDE_JVMCI + elapsedTimer standard_compilation; + elapsedTimer total_compilation; + elapsedTimer osr_compilation; + + int standard_bytes_compiled = 0; + int osr_bytes_compiled = 0; + + int standard_compile_count = 0; + int osr_compile_count = 0; + int total_compile_count = 0; + + int nmethods_size = 0; + int nmethods_code_size = 0; + bool printedHeader = false; + + for (unsigned int i = 0; i < sizeof(_compilers) / sizeof(AbstractCompiler*); i++) { + AbstractCompiler* comp = _compilers[i]; + if (comp != NULL) { + if (per_compiler && aggregate && !printedHeader) { + printedHeader = true; + tty->cr(); + tty->print_cr("Individual compiler times (for compiled methods only)"); + tty->print_cr("------------------------------------------------"); + tty->cr(); + } + CompilerStatistics* stats = comp->stats(); + + standard_compilation.add(stats->_standard._time); + osr_compilation.add(stats->_osr._time); + + standard_bytes_compiled += stats->_standard._bytes; + osr_bytes_compiled += stats->_osr._bytes; + + standard_compile_count += stats->_standard._count; + osr_compile_count += stats->_osr._count; + + nmethods_size += stats->_nmethods_size; + nmethods_code_size += stats->_nmethods_code_size; + + if (per_compiler) { + print_times(comp); + } + } + } + total_compile_count = osr_compile_count + standard_compile_count; + total_compilation.add(osr_compilation); + total_compilation.add(standard_compilation); + + // In hosted mode, print the JVMCI compiler specific counters manually. + if (!UseJVMCICompiler) { + JVMCICompiler::print_compilation_timers(); + } +#else // INCLUDE_JVMCI + elapsedTimer standard_compilation = CompileBroker::_t_standard_compilation; + elapsedTimer osr_compilation = CompileBroker::_t_osr_compilation; + elapsedTimer total_compilation = CompileBroker::_t_total_compilation; + + int standard_bytes_compiled = CompileBroker::_sum_standard_bytes_compiled; + int osr_bytes_compiled = CompileBroker::_sum_osr_bytes_compiled; + + int standard_compile_count = CompileBroker::_total_standard_compile_count; + int osr_compile_count = CompileBroker::_total_osr_compile_count; + int total_compile_count = CompileBroker::_total_compile_count; + + int nmethods_size = CompileBroker::_sum_nmethod_code_size; + int nmethods_code_size = CompileBroker::_sum_nmethod_size; +#endif // INCLUDE_JVMCI + + if (!aggregate) { + return; + } tty->cr(); tty->print_cr("Accumulated compiler times"); tty->print_cr("----------------------------------------------------------"); //0000000000111111111122222222223333333333444444444455555555556666666666 //0123456789012345678901234567890123456789012345678901234567890123456789 - tty->print_cr(" Total compilation time : %7.3f s", CompileBroker::_t_total_compilation.seconds()); + tty->print_cr(" Total compilation time : %7.3f s", total_compilation.seconds()); tty->print_cr(" Standard compilation : %7.3f s, Average : %2.3f s", - CompileBroker::_t_standard_compilation.seconds(), - CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count); + standard_compilation.seconds(), + standard_compilation.seconds() / standard_compile_count); tty->print_cr(" Bailed out compilation : %7.3f s, Average : %2.3f s", CompileBroker::_t_bailedout_compilation.seconds(), CompileBroker::_t_bailedout_compilation.seconds() / CompileBroker::_total_bailout_count); tty->print_cr(" On stack replacement : %7.3f s, Average : %2.3f s", - CompileBroker::_t_osr_compilation.seconds(), - CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count); + osr_compilation.seconds(), + osr_compilation.seconds() / osr_compile_count); tty->print_cr(" Invalidated : %7.3f s, Average : %2.3f s", CompileBroker::_t_invalidated_compilation.seconds(), CompileBroker::_t_invalidated_compilation.seconds() / CompileBroker::_total_invalidated_count); @@ -2038,18 +2194,19 @@ comp->print_timers(); } tty->cr(); - tty->print_cr(" Total compiled methods : %8d methods", CompileBroker::_total_compile_count); - tty->print_cr(" Standard compilation : %8d methods", CompileBroker::_total_standard_compile_count); - tty->print_cr(" On stack replacement : %8d methods", CompileBroker::_total_osr_compile_count); - int tcb = CompileBroker::_sum_osr_bytes_compiled + CompileBroker::_sum_standard_bytes_compiled; + tty->print_cr(" Total compiled methods : %8d methods", total_compile_count); + tty->print_cr(" Standard compilation : %8d methods", standard_compile_count); + tty->print_cr(" On stack replacement : %8d methods", osr_compile_count); + int tcb = osr_bytes_compiled + standard_bytes_compiled; tty->print_cr(" Total compiled bytecodes : %8d bytes", tcb); - tty->print_cr(" Standard compilation : %8d bytes", CompileBroker::_sum_standard_bytes_compiled); - tty->print_cr(" On stack replacement : %8d bytes", CompileBroker::_sum_osr_bytes_compiled); - int bps = (int)(tcb / CompileBroker::_t_total_compilation.seconds()); + tty->print_cr(" Standard compilation : %8d bytes", standard_bytes_compiled); + tty->print_cr(" On stack replacement : %8d bytes", osr_bytes_compiled); + double tcs = total_compilation.seconds(); + int bps = tcs == 0.0 ? 0 : (int)(tcb / tcs); tty->print_cr(" Average compilation speed : %8d bytes/s", bps); tty->cr(); - tty->print_cr(" nmethod code size : %8d bytes", CompileBroker::_sum_nmethod_code_size); - tty->print_cr(" nmethod total size : %8d bytes", CompileBroker::_sum_nmethod_size); + tty->print_cr(" nmethod code size : %8d bytes", nmethods_code_size); + tty->print_cr(" nmethod total size : %8d bytes", nmethods_size); } // Debugging output for failure diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/compileBroker.hpp --- a/hotspot/src/share/vm/compiler/compileBroker.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,6 +29,7 @@ #include "compiler/abstractCompiler.hpp" #include "compiler/compileTask.hpp" #include "runtime/perfData.hpp" +#include "trace/tracing.hpp" class nmethod; class nmethodLocker; @@ -47,36 +48,26 @@ private: char _current_method[cmname_buffer_length]; - PerfStringVariable* _perf_current_method; - int _compile_type; - PerfVariable* _perf_compile_type; - - PerfCounter* _perf_time; - PerfCounter* _perf_compiles; public: - CompilerCounters(const char* name, int instance, TRAPS); + CompilerCounters(); // these methods should be called in a thread safe context void set_current_method(const char* method) { strncpy(_current_method, method, (size_t)cmname_buffer_length-1); _current_method[cmname_buffer_length-1] = '\0'; - if (UsePerfData) _perf_current_method->set_value(method); } char* current_method() { return _current_method; } void set_compile_type(int compile_type) { _compile_type = compile_type; - if (UsePerfData) _perf_compile_type->set_value((jlong)compile_type); } int compile_type() { return _compile_type; } - PerfCounter* time_counter() { return _perf_time; } - PerfCounter* compile_counter() { return _perf_compiles; } }; // CompileQueue @@ -243,6 +234,7 @@ static void wait_for_completion(CompileTask* task); static void invoke_compiler_on_method(CompileTask* task); + static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env); static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level); static void push_jni_handle_block(); static void pop_jni_handle_block(); @@ -288,6 +280,9 @@ int hot_count, const char* comment, Thread* thread); + // Acquire any needed locks and assign a compile id + static uint assign_compile_id_unlocked(Thread* thread, methodHandle method, int osr_bci); + static void compiler_thread_loop(); static uint get_compilation_id() { return _compilation_id; } @@ -336,8 +331,13 @@ // Redefine Classes support static void mark_on_stack(); +#if INCLUDE_JVMCI + // Print curent compilation time stats for a given compiler + static void print_times(AbstractCompiler* comp); +#endif + // Print a detailed accounting of compilation time - static void print_times(); + static void print_times(bool per_compiler = true, bool aggregate = true); // Debugging output for failure static void print_last_compile(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/compileTask.cpp --- a/hotspot/src/share/vm/compiler/compileTask.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/compileTask.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -183,6 +183,10 @@ if (!short_form) { st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp } + // print compiler name if requested + if (CIPrintCompilerName) { + st->print("%s:", CompileBroker::compiler_name(comp_level)); + } st->print("%4d ", compile_id); // print compilation number // For unloaded methods the transition to zombie occurs after the @@ -271,7 +275,8 @@ if (_osr_bci != CompileBroker::standard_entry_bci) { log->print(" osr_bci='%d'", _osr_bci); } - if (_comp_level != CompLevel_highest_tier) { + // Always print the level in tiered. + if (_comp_level != CompLevel_highest_tier || TieredCompilation) { log->print(" level='%d'", _comp_level); } if (_is_blocking) { @@ -307,6 +312,24 @@ // ------------------------------------------------------------------ +// CompileTask::log_task_dequeued +void CompileTask::log_task_dequeued(const char* comment) { + if (LogCompilation && xtty != NULL) { + Thread* thread = Thread::current(); + ttyLocker ttyl; + ResourceMark rm(thread); + + xtty->begin_elem("task_dequeued"); + log_task(xtty); + if (comment != NULL) { + xtty->print(" comment='%s'", comment); + } + xtty->end_elem(); + } +} + + +// ------------------------------------------------------------------ // CompileTask::log_task_start void CompileTask::log_task_start(CompileLog* log) { log->begin_head("task"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/compileTask.hpp --- a/hotspot/src/share/vm/compiler/compileTask.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/compileTask.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -133,6 +133,7 @@ void log_task(xmlStream* log); void log_task_queued(); + void log_task_dequeued(const char* comment); void log_task_start(CompileLog* log); void log_task_done(CompileLog* log); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/compilerOracle.cpp --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -24,149 +24,17 @@ #include "precompiled.hpp" #include "compiler/compilerOracle.hpp" +#include "compiler/methodMatcher.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" -#include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "runtime/handles.inline.hpp" #include "runtime/jniHandles.hpp" #include "runtime/os.hpp" -class MethodMatcher : public CHeapObj { - public: - enum Mode { - Exact, - Prefix = 1, - Suffix = 2, - Substring = Prefix | Suffix, - Any, - Unknown = -1 - }; - - protected: - Symbol* _class_name; - Symbol* _method_name; - Symbol* _signature; - Mode _class_mode; - Mode _method_mode; - MethodMatcher* _next; - - static bool match(Symbol* candidate, Symbol* match, Mode match_mode); - - Symbol* class_name() const { return _class_name; } - Symbol* method_name() const { return _method_name; } - Symbol* signature() const { return _signature; } - - public: - MethodMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, MethodMatcher* next); - MethodMatcher(Symbol* class_name, Symbol* method_name, MethodMatcher* next); - - // utility method - MethodMatcher* find(methodHandle method) { - Symbol* class_name = method->method_holder()->name(); - Symbol* method_name = method->name(); - for (MethodMatcher* current = this; current != NULL; current = current->_next) { - if (match(class_name, current->class_name(), current->_class_mode) && - match(method_name, current->method_name(), current->_method_mode) && - (current->signature() == NULL || current->signature() == method->signature())) { - return current; - } - } - return NULL; - } - - bool match(methodHandle method) { - return find(method) != NULL; - } - - MethodMatcher* next() const { return _next; } - - static void print_symbol(Symbol* h, Mode mode) { - ResourceMark rm; - - if (mode == Suffix || mode == Substring || mode == Any) { - tty->print("*"); - } - if (mode != Any) { - h->print_symbol_on(tty); - } - if (mode == Prefix || mode == Substring) { - tty->print("*"); - } - } - - void print_base() { - print_symbol(class_name(), _class_mode); - tty->print("."); - print_symbol(method_name(), _method_mode); - if (signature() != NULL) { - signature()->print_symbol_on(tty); - } - } - - virtual void print() { - print_base(); - tty->cr(); - } -}; - -MethodMatcher::MethodMatcher(Symbol* class_name, Symbol* method_name, MethodMatcher* next) { - _class_name = class_name; - _method_name = method_name; - _next = next; - _class_mode = MethodMatcher::Exact; - _method_mode = MethodMatcher::Exact; - _signature = NULL; -} - - -MethodMatcher::MethodMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, MethodMatcher* next): - _class_mode(class_mode) - , _method_mode(method_mode) - , _next(next) - , _class_name(class_name) - , _method_name(method_name) - , _signature(signature) { -} - -bool MethodMatcher::match(Symbol* candidate, Symbol* match, Mode match_mode) { - if (match_mode == Any) { - return true; - } - - if (match_mode == Exact) { - return candidate == match; - } - - ResourceMark rm; - const char * candidate_string = candidate->as_C_string(); - const char * match_string = match->as_C_string(); - - switch (match_mode) { - case Prefix: - return strstr(candidate_string, match_string) == candidate_string; - - case Suffix: { - size_t clen = strlen(candidate_string); - size_t mlen = strlen(match_string); - return clen >= mlen && strcmp(candidate_string + clen - mlen, match_string) == 0; - } - - case Substring: - return strstr(candidate_string, match_string) != NULL; - - default: - return false; - } -} - enum OptionType { IntxType, UintxType, @@ -202,114 +70,6 @@ return DoubleType; } -template -static const T copy_value(const T value) { - return value; -} - -template<> const ccstr copy_value(const ccstr value) { - return (const ccstr)os::strdup_check_oom(value); -} - -template -class TypedMethodOptionMatcher : public MethodMatcher { - const char* _option; - OptionType _type; - const T _value; - -public: - TypedMethodOptionMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, const char* opt, - const T value, MethodMatcher* next) : - MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next), - _type(get_type_for()), _value(copy_value(value)) { - _option = os::strdup_check_oom(opt); - } - - ~TypedMethodOptionMatcher() { - os::free((void*)_option); - } - - TypedMethodOptionMatcher* match(methodHandle method, const char* opt) { - TypedMethodOptionMatcher* current = this; - while (current != NULL) { - current = (TypedMethodOptionMatcher*)current->find(method); - if (current == NULL) { - return NULL; - } - if (strcmp(current->_option, opt) == 0) { - return current; - } - current = current->next(); - } - return NULL; - } - - TypedMethodOptionMatcher* next() { - return (TypedMethodOptionMatcher*)_next; - } - - OptionType get_type(void) { - return _type; - }; - - T value() { return _value; } - - void print() { - ttyLocker ttyl; - print_base(); - tty->print(" %s", _option); - tty->print(" "); - tty->cr(); - } -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" intx %s", _option); - tty->print(" = " INTX_FORMAT, _value); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" uintx %s", _option); - tty->print(" = " UINTX_FORMAT, _value); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" bool %s", _option); - tty->print(" = %s", _value ? "true" : "false"); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" const char* %s", _option); - tty->print(" = '%s'", _value); - tty->cr(); -}; - -template<> -void TypedMethodOptionMatcher::print() { - ttyLocker ttyl; - print_base(); - tty->print(" double %s", _option); - tty->print(" = %f", _value); - tty->cr(); -}; - // this must parallel the command_names below enum OracleCommand { UnknownCommand = -1, @@ -342,8 +102,198 @@ }; class MethodMatcher; -static MethodMatcher* lists[OracleCommandCount] = { 0, }; +class TypedMethodOptionMatcher; + +static BasicMatcher* lists[OracleCommandCount] = { 0, }; +static TypedMethodOptionMatcher* option_list = NULL; + +class TypedMethodOptionMatcher : public MethodMatcher { + private: + TypedMethodOptionMatcher* _next; + const char* _option; + OptionType _type; + public: + + union { + bool bool_value; + intx intx_value; + uintx uintx_value; + double double_value; + ccstr ccstr_value; + } _u; + + TypedMethodOptionMatcher() : MethodMatcher(), + _next(NULL), + _type(UnknownType) { + _option = NULL; + memset(&_u, 0, sizeof(_u)); + } + + static TypedMethodOptionMatcher* parse_method_pattern(char*& line, const char*& error_msg); + TypedMethodOptionMatcher* match(methodHandle method, const char* opt, OptionType type); + + void init(const char* opt, OptionType type, TypedMethodOptionMatcher* next) { + _next = next; + _type = type; + _option = os::strdup_check_oom(opt); + } + + void set_next(TypedMethodOptionMatcher* next) {_next = next; } + TypedMethodOptionMatcher* next() { return _next; } + OptionType type() { return _type; } + template T value(); + template void set_value(T value); + void print(); + void print_all(); + TypedMethodOptionMatcher* clone(); + ~TypedMethodOptionMatcher(); +}; + +// A few templated accessors instead of a full template class. +template<> intx TypedMethodOptionMatcher::value() { + return _u.intx_value; +} + +template<> uintx TypedMethodOptionMatcher::value() { + return _u.uintx_value; +} + +template<> bool TypedMethodOptionMatcher::value() { + return _u.bool_value; +} + +template<> double TypedMethodOptionMatcher::value() { + return _u.double_value; +} + +template<> ccstr TypedMethodOptionMatcher::value() { + return _u.ccstr_value; +} + +template<> void TypedMethodOptionMatcher::set_value(intx value) { + _u.intx_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(uintx value) { + _u.uintx_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(double value) { + _u.double_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(bool value) { + _u.bool_value = value; +} + +template<> void TypedMethodOptionMatcher::set_value(ccstr value) { + _u.ccstr_value = (const ccstr)os::strdup_check_oom(value); +} +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(tty); + switch (_type) { + case IntxType: + tty->print_cr(" intx %s = " INTX_FORMAT, _option, value()); + break; + case UintxType: + tty->print_cr(" uintx %s = " UINTX_FORMAT, _option, value()); + break; + case BoolType: + tty->print_cr(" bool %s = %s", _option, value() ? "true" : "false"); + break; + case DoubleType: + tty->print_cr(" double %s = %f", _option, value()); + break; + case CcstrType: + tty->print_cr(" const char* %s = '%s'", _option, value()); + break; + default: + ShouldNotReachHere(); + } +} + +void TypedMethodOptionMatcher::print_all() { + print(); + if (_next != NULL) { + tty->print(" "); + _next->print_all(); + } + } + +TypedMethodOptionMatcher* TypedMethodOptionMatcher::clone() { + TypedMethodOptionMatcher* m = new TypedMethodOptionMatcher(); + m->_class_mode = _class_mode; + m->_class_name = _class_name; + m->_method_mode = _method_mode; + m->_method_name = _method_name; + m->_signature = _signature; + // Need to ref count the symbols + if (_class_name != NULL) { + _class_name->increment_refcount(); + } + if (_method_name != NULL) { + _method_name->increment_refcount(); + } + if (_signature != NULL) { + _signature->increment_refcount(); + } + return m; +} + +TypedMethodOptionMatcher::~TypedMethodOptionMatcher() { + if (_option != NULL) { + os::free((void*)_option); + } + if (_class_name != NULL) { + _class_name->decrement_refcount(); + } + if (_method_name != NULL) { + _method_name->decrement_refcount(); + } + if (_signature != NULL) { + _signature->decrement_refcount(); + } +} + +TypedMethodOptionMatcher* TypedMethodOptionMatcher::parse_method_pattern(char*& line, const char*& error_msg) { + assert(error_msg == NULL, "Dont call here with error_msg already set"); + TypedMethodOptionMatcher* tom = new TypedMethodOptionMatcher(); + MethodMatcher::parse_method_pattern(line, error_msg, tom); + if (error_msg != NULL) { + delete tom; + return NULL; + } + return tom; +} + +TypedMethodOptionMatcher* TypedMethodOptionMatcher::match(methodHandle method, const char* opt, OptionType type) { + TypedMethodOptionMatcher* current = this; + while (current != NULL) { + // Fastest compare first. + if (current->type() == type) { + if (strcmp(current->_option, opt) == 0) { + if (current->matches(method)) { + return current; + } + } + } + current = current->next(); + } + return NULL; +} + +template +static void add_option_string(TypedMethodOptionMatcher* matcher, + const char* option, + T value) { + assert(matcher != option_list, "No circular lists please"); + matcher->init(option, get_type_for(), option_list); + matcher->set_value(value); + option_list = matcher; + return; +} static bool check_predicate(OracleCommand command, methodHandle method) { return ((lists[command] != NULL) && @@ -351,51 +301,27 @@ lists[command]->match(method)); } - -static MethodMatcher* add_predicate(OracleCommand command, - Symbol* class_name, MethodMatcher::Mode c_mode, - Symbol* method_name, MethodMatcher::Mode m_mode, - Symbol* signature) { +static void add_predicate(OracleCommand command, BasicMatcher* bm) { assert(command != OptionCommand, "must use add_option_string"); - if (command == LogCommand && !LogCompilation && lists[LogCommand] == NULL) + if (command == LogCommand && !LogCompilation && lists[LogCommand] == NULL) { tty->print_cr("Warning: +LogCompilation must be enabled in order for individual methods to be logged."); - lists[command] = new MethodMatcher(class_name, c_mode, method_name, m_mode, signature, lists[command]); - return lists[command]; -} + } + bm->set_next(lists[command]); + lists[command] = bm; -template -static MethodMatcher* add_option_string(Symbol* class_name, MethodMatcher::Mode c_mode, - Symbol* method_name, MethodMatcher::Mode m_mode, - Symbol* signature, - const char* option, - T value) { - lists[OptionCommand] = new TypedMethodOptionMatcher(class_name, c_mode, method_name, m_mode, - signature, option, value, lists[OptionCommand]); - return lists[OptionCommand]; -} - -template -static bool get_option_value(methodHandle method, const char* option, T& value) { - TypedMethodOptionMatcher* m; - if (lists[OptionCommand] != NULL - && (m = ((TypedMethodOptionMatcher*)lists[OptionCommand])->match(method, option)) != NULL - && m->get_type() == get_type_for()) { - value = m->value(); - return true; - } else { - return false; - } -} - -bool CompilerOracle::has_option_string(methodHandle method, const char* option) { - bool value = false; - get_option_value(method, option, value); - return value; + return; } template bool CompilerOracle::has_option_value(methodHandle method, const char* option, T& value) { - return ::get_option_value(method, option, value); + if (option_list != NULL) { + TypedMethodOptionMatcher* m = option_list->match(method, option, get_type_for()); + if (m != NULL) { + value = m->value(); + return true; + } + } + return false; } // Explicit instantiation for all OptionTypes supported. @@ -405,6 +331,12 @@ template bool CompilerOracle::has_option_value(methodHandle method, const char* option, ccstr& value); template bool CompilerOracle::has_option_value(methodHandle method, const char* option, double& value); +bool CompilerOracle::has_option_string(methodHandle method, const char* option) { + bool value = false; + has_option_value(method, option, value); + return value; +} + bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) { quietly = true; if (lists[ExcludeCommand] != NULL) { @@ -420,19 +352,18 @@ return false; } - bool CompilerOracle::should_inline(methodHandle method) { return (check_predicate(InlineCommand, method)); } - +// Check both DontInlineCommand and ExcludeCommand here +// - consistent behavior for all compilers bool CompilerOracle::should_not_inline(methodHandle method) { - return (check_predicate(DontInlineCommand, method)); + return check_predicate(DontInlineCommand, method) || check_predicate(ExcludeCommand, method); } - bool CompilerOracle::should_print(methodHandle method) { - return (check_predicate(PrintCommand, method)); + return check_predicate(PrintCommand, method); } bool CompilerOracle::should_print_methods() { @@ -445,12 +376,10 @@ return (check_predicate(LogCommand, method)); } - bool CompilerOracle::should_break_at(methodHandle method) { return check_predicate(BreakCommand, method); } - static OracleCommand parse_command_name(const char * line, int* bytes_read) { assert(ARRAY_SIZE(command_names) == OracleCommandCount, "command_names size mismatch"); @@ -516,84 +445,12 @@ tty->cr(); }; -// The JVM specification defines the allowed characters. -// Tokens that are disallowed by the JVM specification can have -// a meaning to the parser so we need to include them here. -// The parser does not enforce all rules of the JVMS - a successful parse -// does not mean that it is an allowed name. Illegal names will -// be ignored since they never can match a class or method. -// -// '\0' and 0xf0-0xff are disallowed in constant string values -// 0x20 ' ', 0x09 '\t' and, 0x2c ',' are used in the matching -// 0x5b '[' and 0x5d ']' can not be used because of the matcher -// 0x28 '(' and 0x29 ')' are used for the signature -// 0x2e '.' is always replaced before the matching -// 0x2f '/' is only used in the class name as package separator - -#define RANGEBASE "\x1\x2\x3\x4\x5\x6\x7\x8\xa\xb\xc\xd\xe\xf" \ - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ - "\x21\x22\x23\x24\x25\x26\x27\x2a\x2b\x2c\x2d" \ - "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ - "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ - "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5c\x5e\x5f" \ - "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ - "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" \ - "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \ - "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \ - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \ - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \ - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \ - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \ - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" - -#define RANGE0 "[*" RANGEBASE "]" -#define RANGESLASH "[*" RANGEBASE "/]" - -static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) { - int match = MethodMatcher::Exact; - while (name[0] == '*') { - match |= MethodMatcher::Suffix; - // Copy remaining string plus NUL to the beginning - memmove(name, name + 1, strlen(name + 1) + 1); - } - - if (strcmp(name, "*") == 0) return MethodMatcher::Any; - - size_t len = strlen(name); - while (len > 0 && name[len - 1] == '*') { - match |= MethodMatcher::Prefix; - name[--len] = '\0'; - } - - if (strstr(name, "*") != NULL) { - error_msg = " Embedded * not allowed"; - return MethodMatcher::Unknown; - } - return (MethodMatcher::Mode)match; -} - -static bool scan_line(const char * line, - char class_name[], MethodMatcher::Mode* c_mode, - char method_name[], MethodMatcher::Mode* m_mode, - int* bytes_read, const char*& error_msg) { - *bytes_read = 0; - error_msg = NULL; - if (2 == sscanf(line, "%*[ \t]%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, bytes_read)) { - *c_mode = check_mode(class_name, error_msg); - *m_mode = check_mode(method_name, error_msg); - return *c_mode != MethodMatcher::Unknown && *m_mode != MethodMatcher::Unknown; - } - return false; -} - // Scan next flag and value in line, return MethodMatcher object on success, NULL on failure. // On failure, error_msg contains description for the first error. // For future extensions: set error_msg on first error. -static MethodMatcher* scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, - Symbol* c_name, MethodMatcher::Mode c_match, - Symbol* m_name, MethodMatcher::Mode m_match, - Symbol* signature, - char* errorbuf, const int buf_size) { +static void scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, + TypedMethodOptionMatcher* matcher, + char* errorbuf, const int buf_size) { total_bytes_read = 0; int bytes_read = 0; char flag[256]; @@ -608,7 +465,8 @@ intx value; if (sscanf(line, "%*[ \t]" INTX_FORMAT "%n", &value, &bytes_read) == 1) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + add_option_string(matcher, flag, value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s ", flag, type); } @@ -616,7 +474,8 @@ uintx value; if (sscanf(line, "%*[ \t]" UINTX_FORMAT "%n", &value, &bytes_read) == 1) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + add_option_string(matcher, flag, value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -625,7 +484,8 @@ char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + add_option_string(matcher, flag, (ccstr)value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -646,7 +506,8 @@ next_value += bytes_read; end_value = next_value-1; } - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + add_option_string(matcher, flag, (ccstr)value); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -655,10 +516,12 @@ if (sscanf(line, "%*[ \t]%255[a-zA-Z]%n", value, &bytes_read) == 1) { if (strcmp(value, "true") == 0) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, true); + add_option_string(matcher, flag, true); + return; } else if (strcmp(value, "false") == 0) { total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, false); + add_option_string(matcher, flag, false); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -673,7 +536,8 @@ char value[512] = ""; jio_snprintf(value, sizeof(value), "%s.%s", buffer[0], buffer[1]); total_bytes_read += bytes_read; - return add_option_string(c_name, c_match, m_name, m_match, signature, flag, atof(value)); + add_option_string(matcher, flag, atof(value)); + return; } else { jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); } @@ -683,7 +547,7 @@ } else { jio_snprintf(errorbuf, buf_size, " Flag name for type %s should be alphanumeric ", type); } - return NULL; + return; } int skip_whitespace(char* line) { @@ -693,31 +557,20 @@ return whitespace_read; } +void CompilerOracle::print_parse_error(const char*& error_msg, char* original_line) { + assert(error_msg != NULL, "Must have error_message"); + + ttyLocker ttyl; + tty->print_cr("CompileCommand: An error occurred during parsing"); + tty->print_cr("Line: %s", original_line); + tty->print_cr("Error: %s", error_msg); + CompilerOracle::print_tip(); +} + void CompilerOracle::parse_from_line(char* line) { if (line[0] == '\0') return; if (line[0] == '#') return; - bool have_colon = (strstr(line, "::") != NULL); - for (char* lp = line; *lp != '\0'; lp++) { - // Allow '.' to separate the class name from the method name. - // This is the preferred spelling of methods: - // exclude java/lang/String.indexOf(I)I - // Allow ',' for spaces (eases command line quoting). - // exclude,java/lang/String.indexOf - // For backward compatibility, allow space as separator also. - // exclude java/lang/String indexOf - // exclude,java/lang/String,indexOf - // For easy cut-and-paste of method names, allow VM output format - // as produced by Method::print_short_name: - // exclude java.lang.String::indexOf - // For simple implementation convenience here, convert them all to space. - if (have_colon) { - if (*lp == '.') *lp = '/'; // dots build the package prefix - if (*lp == ':') *lp = ' '; - } - if (*lp == ',' || *lp == '.') *lp = ' '; - } - char* original_line = line; int bytes_read; OracleCommand command = parse_command_name(line, &bytes_read); @@ -742,109 +595,86 @@ return; } - MethodMatcher::Mode c_match = MethodMatcher::Exact; - MethodMatcher::Mode m_match = MethodMatcher::Exact; - char class_name[256]; - char method_name[256]; - char sig[1024]; - char errorbuf[1024]; - const char* error_msg = NULL; // description of first error that appears - MethodMatcher* match = NULL; + const char* error_msg = NULL; + if (command == OptionCommand) { + // Look for trailing options. + // + // Two types of trailing options are + // supported: + // + // (1) CompileCommand=option,Klass::method,flag + // (2) CompileCommand=option,Klass::method,type,flag,value + // + // Type (1) is used to enable a boolean flag for a method. + // + // Type (2) is used to support options with a value. Values can have the + // the following types: intx, uintx, bool, ccstr, ccstrlist, and double. + // + // For future extensions: extend scan_flag_and_value() - if (scan_line(line, class_name, &c_match, method_name, &m_match, &bytes_read, error_msg)) { - EXCEPTION_MARK; - Symbol* c_name = SymbolTable::new_symbol(class_name, CHECK); - Symbol* m_name = SymbolTable::new_symbol(method_name, CHECK); - Symbol* signature = NULL; - - line += bytes_read; - - // there might be a signature following the method. - // signatures always begin with ( so match that by hand - line += skip_whitespace(line); - if (1 == sscanf(line, "(%254[[);/" RANGEBASE "]%n", sig + 1, &bytes_read)) { - sig[0] = '('; - line += bytes_read; - signature = SymbolTable::new_symbol(sig, CHECK); + char option[256]; // stores flag for Type (1) and type of Type (2) + line++; // skip the ',' + TypedMethodOptionMatcher* archetype = TypedMethodOptionMatcher::parse_method_pattern(line, error_msg); + if (archetype == NULL) { + assert(error_msg != NULL, "Must have error_message"); + print_parse_error(error_msg, original_line); + return; } - if (command == OptionCommand) { - // Look for trailing options. - // - // Two types of trailing options are - // supported: - // - // (1) CompileCommand=option,Klass::method,flag - // (2) CompileCommand=option,Klass::method,type,flag,value - // - // Type (1) is used to enable a boolean flag for a method. - // - // Type (2) is used to support options with a value. Values can have the - // the following types: intx, uintx, bool, ccstr, ccstrlist, and double. - // - // For future extensions: extend scan_flag_and_value() - char option[256]; // stores flag for Type (1) and type of Type (2) + line += skip_whitespace(line); + + // This is unnecessarily complex. Should retire multi-option lines and skip while loop + while (sscanf(line, "%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) { + line += bytes_read; - line += skip_whitespace(line); - while (sscanf(line, "%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) { - if (match != NULL && !_quiet) { - // Print out the last match added - ttyLocker ttyl; - tty->print("CompileCommand: %s ", command_names[command]); - match->print(); + // typed_matcher is used as a blueprint for each option, deleted at the end + TypedMethodOptionMatcher* typed_matcher = archetype->clone(); + if (strcmp(option, "intx") == 0 + || strcmp(option, "uintx") == 0 + || strcmp(option, "bool") == 0 + || strcmp(option, "ccstr") == 0 + || strcmp(option, "ccstrlist") == 0 + || strcmp(option, "double") == 0 + ) { + char errorbuf[1024] = {0}; + // Type (2) option: parse flag name and value. + scan_flag_and_value(option, line, bytes_read, typed_matcher, errorbuf, sizeof(errorbuf)); + if (*errorbuf != '\0') { + error_msg = errorbuf; + print_parse_error(error_msg, original_line); + return; } line += bytes_read; - - if (strcmp(option, "intx") == 0 - || strcmp(option, "uintx") == 0 - || strcmp(option, "bool") == 0 - || strcmp(option, "ccstr") == 0 - || strcmp(option, "ccstrlist") == 0 - || strcmp(option, "double") == 0 - ) { + } else { + // Type (1) option + add_option_string(typed_matcher, option, true); + } + if (typed_matcher != NULL && !_quiet) { + // Print out the last match added + assert(error_msg == NULL, "No error here"); + ttyLocker ttyl; + tty->print("CompileCommand: %s ", command_names[command]); + typed_matcher->print(); + } + line += skip_whitespace(line); + } // while( + delete archetype; + } else { // not an OptionCommand) + assert(error_msg == NULL, "Don't call here with error_msg already set"); - // Type (2) option: parse flag name and value. - match = scan_flag_and_value(option, line, bytes_read, - c_name, c_match, m_name, m_match, signature, - errorbuf, sizeof(errorbuf)); - if (match == NULL) { - error_msg = errorbuf; - break; - } - line += bytes_read; - } else { - // Type (1) option - match = add_option_string(c_name, c_match, m_name, m_match, signature, option, true); - } - line += skip_whitespace(line); - } // while( - } else { - match = add_predicate(command, c_name, c_match, m_name, m_match, signature); + BasicMatcher* matcher = BasicMatcher::parse_method_pattern(line, error_msg); + if (error_msg != NULL) { + assert(matcher == NULL, "consistency"); + print_parse_error(error_msg, original_line); + return; } - } - ttyLocker ttyl; - if (error_msg != NULL) { - // an error has happened - tty->print_cr("CompileCommand: An error occured during parsing"); - tty->print_cr(" \"%s\"", original_line); - if (error_msg != NULL) { - tty->print_cr("%s", error_msg); - } - CompilerOracle::print_tip(); - - } else { - // check for remaining characters - bytes_read = 0; - sscanf(line, "%*[ \t]%n", &bytes_read); - if (line[bytes_read] != '\0') { - tty->print_cr("CompileCommand: Bad pattern"); - tty->print_cr(" \"%s\"", original_line); - tty->print_cr(" Unrecognized text %s after command ", line); - CompilerOracle::print_tip(); - } else if (match != NULL && !_quiet) { + add_predicate(command, matcher); + if (!_quiet) { + ttyLocker ttyl; tty->print("CompileCommand: %s ", command_names[command]); - match->print(); + matcher->print(tty); + tty->cr(); } } } @@ -1045,10 +875,12 @@ Symbol* m_name = SymbolTable::new_symbol(methodName, CHECK); Symbol* signature = NULL; - add_predicate(CompileOnlyCommand, c_name, c_match, m_name, m_match, signature); + BasicMatcher* bm = new BasicMatcher(); + bm->init(c_name, c_match, m_name, m_match, signature); + add_predicate(CompileOnlyCommand, bm); if (PrintVMOptions) { tty->print("CompileOnly: compileonly "); - lists[CompileOnlyCommand]->print(); + lists[CompileOnlyCommand]->print_all(tty); } className = NULL; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/compilerOracle.hpp --- a/hotspot/src/share/vm/compiler/compilerOracle.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/compilerOracle.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -35,6 +35,7 @@ private: static bool _quiet; static void print_tip(); + static void print_parse_error(const char*& error_msg, char* original_line); public: diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/disassembler.cpp --- a/hotspot/src/share/vm/compiler/disassembler.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/disassembler.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -56,8 +56,6 @@ #include "shark/sharkEntry.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void* Disassembler::_library = NULL; bool Disassembler::_tried_to_load_library = false; @@ -330,16 +328,19 @@ if (Universe::is_fully_initialized()) { if (StubRoutines::contains(adr)) { StubCodeDesc* desc = StubCodeDesc::desc_for(adr); - if (desc == NULL) + if (desc == NULL) { desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset); + } if (desc != NULL) { st->print("Stub::%s", desc->name()); - if (desc->begin() != adr) - st->print("%+d 0x%p",adr - desc->begin(), adr); - else if (WizardMode) st->print(" " PTR_FORMAT, adr); + if (desc->begin() != adr) { + st->print(INTX_FORMAT_W(+) " " PTR_FORMAT, adr - desc->begin(), p2i(adr)); + } else if (WizardMode) { + st->print(" " PTR_FORMAT, p2i(adr)); + } return; } - st->print("Stub:: " PTR_FORMAT, adr); + st->print("Stub:: " PTR_FORMAT, p2i(adr)); return; } @@ -347,13 +348,13 @@ if (bs->is_a(BarrierSet::CardTableModRef) && adr == (address)(barrier_set_cast(bs)->byte_map_base)) { st->print("word_map_base"); - if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr); + if (WizardMode) st->print(" " INTPTR_FORMAT, p2i(adr)); return; } } // Fall through to a simple (hexadecimal) numeral. - st->print(PTR_FORMAT, adr); + st->print(PTR_FORMAT, p2i(adr)); } void decode_env::print_insn_labels() { @@ -365,7 +366,7 @@ } _strings.print_block_comment(st, (intptr_t)(p - _start)); if (_print_pc) { - st->print(" " PTR_FORMAT ": ", p); + st->print(" " PTR_FORMAT ": ", p2i(p)); } } @@ -386,13 +387,16 @@ address pc1 = pc + perline; if (pc1 > pc_limit) pc1 = pc_limit; for (; pc < pc1; pc += incr) { - if (pc == pc0) + if (pc == pc0) { st->print(BYTES_COMMENT); - else if ((uint)(pc - pc0) % sizeof(int) == 0) + } else if ((uint)(pc - pc0) % sizeof(int) == 0) { st->print(" "); // put out a space on word boundaries - if (incr == sizeof(int)) - st->print("%08lx", *(int*)pc); - else st->print("%02x", (*pc)&0xFF); + } + if (incr == sizeof(int)) { + st->print("%08x", *(int*)pc); + } else { + st->print("%02x", (*pc)&0xFF); + } } st->cr(); } @@ -487,8 +491,14 @@ void Disassembler::decode(CodeBlob* cb, outputStream* st) { if (!load_library()) return; + if (cb->is_nmethod()) { + decode((nmethod*)cb, st); + return; + } decode_env env(cb, st); - env.output()->print_cr("Decoding CodeBlob " PTR_FORMAT, cb); + env.output()->print_cr("----------------------------------------------------------------------"); + env.output()->print_cr("%s", cb->name()); + env.output()->print_cr(" at [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(cb->code_begin()), p2i(cb->code_end()), ((jlong)(cb->code_end() - cb->code_begin())) * sizeof(unsigned char*)); env.decode_instructions(cb->code_begin(), cb->code_end()); } @@ -501,8 +511,7 @@ void Disassembler::decode(nmethod* nm, outputStream* st) { if (!load_library()) return; decode_env env(nm, st); - env.output()->print_cr("Decoding compiled method " PTR_FORMAT ":", nm); - env.output()->print_cr("Code:"); + env.output()->print_cr("----------------------------------------------------------------------"); #ifdef SHARK SharkEntry* entry = (SharkEntry *) nm->code_begin(); @@ -513,6 +522,21 @@ unsigned char* end = nm->code_end(); #endif // SHARK + nm->method()->method_holder()->name()->print_symbol_on(env.output()); + env.output()->print("."); + nm->method()->name()->print_symbol_on(env.output()); + nm->method()->signature()->print_symbol_on(env.output()); +#if INCLUDE_JVMCI + { + char buffer[O_BUFLEN]; + char* jvmciName = nm->jvmci_installed_code_name(buffer, O_BUFLEN); + if (jvmciName != NULL) { + env.output()->print(" (%s)", jvmciName); + } + } +#endif + env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(p), p2i(end), ((jlong)(end - p))); + // If there has been profiling, print the buckets. if (FlatProfiler::bucket_start_for(p) != NULL) { unsigned char* p1 = p; @@ -533,9 +557,9 @@ int offset = 0; for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) { if ((offset % 8) == 0) { - env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p, offset, *((int32_t*) p), *((int64_t*) p)); + env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p2i(p), offset, *((int32_t*) p), *((int64_t*) p)); } else { - env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p, offset, *((int32_t*) p)); + env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p2i(p), offset, *((int32_t*) p)); } } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/methodLiveness.cpp --- a/hotspot/src/share/vm/compiler/methodLiveness.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/methodLiveness.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -32,8 +32,6 @@ #include "memory/allocation.inline.hpp" #include "utilities/bitMap.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // The MethodLiveness class performs a simple liveness analysis on a method // in order to decide which locals are live (that is, will be used again) at // a particular bytecode index (bci). @@ -540,7 +538,7 @@ _time_flow.seconds() * 100 / _time_total.seconds()); tty->print_cr (" Query : %3.3f sec. (%2.2f%%)", _time_query.seconds(), _time_query.seconds() * 100 / _time_total.seconds()); - tty->print_cr (" #bytes : %8d (%3.0f bytes per sec)", + tty->print_cr (" #bytes : %8ld (%3.0f bytes per sec)", _total_bytes, _total_bytes / _time_total.seconds()); tty->print_cr (" #methods : %8d (%3.0f methods per sec)", @@ -554,7 +552,7 @@ _max_method_blocks); tty->print_cr (" avg bytes : %3.3f", (float)_total_bytes / _total_methods); - tty->print_cr (" #blocks : %8d", + tty->print_cr (" #blocks : %8ld", _total_blocks); tty->print_cr (" avg normal predecessors : %3.3f max normal predecessors : %3d", (float)_total_edges / _total_blocks, @@ -564,7 +562,7 @@ _max_block_exc_edges); tty->print_cr (" avg visits : %3.3f", (float)_total_visits / _total_blocks); - tty->print_cr (" #locals queried : %8d #live : %8d %%live : %2.2f%%", + tty->print_cr (" #locals queried : %8ld #live : %8ld %%live : %2.2f%%", _total_locals_queried, _total_live_locals_queried, 100.0 * _total_live_locals_queried / _total_locals_queried); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/methodMatcher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/compiler/methodMatcher.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "compiler/methodMatcher.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" + +// The JVM specification defines the allowed characters. +// Tokens that are disallowed by the JVM specification can have +// a meaning to the parser so we need to include them here. +// The parser does not enforce all rules of the JVMS - a successful parse +// does not mean that it is an allowed name. Illegal names will +// be ignored since they never can match a class or method. +// +// '\0' and 0xf0-0xff are disallowed in constant string values +// 0x20 ' ', 0x09 '\t' and, 0x2c ',' are used in the matching +// 0x5b '[' and 0x5d ']' can not be used because of the matcher +// 0x28 '(' and 0x29 ')' are used for the signature +// 0x2e '.' is always replaced before the matching +// 0x2f '/' is only used in the class name as package separator + +#define RANGEBASE "\x1\x2\x3\x4\x5\x6\x7\x8\xa\xb\xc\xd\xe\xf" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "\x21\x22\x23\x24\x25\x26\x27\x2a\x2b\x2c\x2d" \ + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ + "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5c\x5e\x5f" \ + "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" \ + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \ + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \ + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \ + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \ + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \ + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \ + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + +#define RANGE0 "[*" RANGEBASE "]" +#define RANGESLASH "[*" RANGEBASE "/]" + +MethodMatcher::MethodMatcher(): + _class_mode(Exact) + , _method_mode(Exact) + , _class_name(NULL) + , _method_name(NULL) + , _signature(NULL) { +} + +MethodMatcher::~MethodMatcher() { + if (_class_name != NULL) { + _class_name->decrement_refcount(); + } + if (_method_name != NULL) { + _method_name->decrement_refcount(); + } + if (_signature != NULL) { + _signature->decrement_refcount(); + } +} + +void MethodMatcher::init(Symbol* class_name, Mode class_mode, + Symbol* method_name, Mode method_mode, + Symbol* signature) { + _class_mode = class_mode; + _method_mode = method_mode; + _class_name = class_name; + _method_name = method_name; + _signature = signature; +} + +bool MethodMatcher::canonicalize(char * line, const char *& error_msg) { + char* colon = strstr(line, "::"); + bool have_colon = (colon != NULL); + if (have_colon) { + // Don't allow multiple '::' + if (colon + 2 != '\0') { + if (strstr(colon+2, "::")) { + error_msg = "Method pattern only allows one '::' allowed"; + return false; + } + } + + bool in_signature = false; + char* pos = line; + if (pos != NULL) { + for (char* lp = pos + 1; *lp != '\0'; lp++) { + if (*lp == '(') { + break; + } + + if (*lp == '/') { + error_msg = "Method pattern uses '/' together with '::'"; + return false; + } + } + } + } else { + // Don't allow mixed package separators + char* pos = strchr(line, '.'); + bool in_signature = false; + if (pos != NULL) { + for (char* lp = pos + 1; *lp != '\0'; lp++) { + if (*lp == '(') { + in_signature = true; + } + + // After any comma the method pattern has ended + if (*lp == ',') { + break; + } + + if (!in_signature && (*lp == '/')) { + error_msg = "Method pattern uses mixed '/' and '.' package separators"; + return false; + } + + if (*lp == '.') { + error_msg = "Method pattern uses multiple '.' in pattern"; + return false; + } + } + } + } + + for (char* lp = line; *lp != '\0'; lp++) { + // Allow '.' to separate the class name from the method name. + // This is the preferred spelling of methods: + // exclude java/lang/String.indexOf(I)I + // Allow ',' for spaces (eases command line quoting). + // exclude,java/lang/String.indexOf + // For backward compatibility, allow space as separator also. + // exclude java/lang/String indexOf + // exclude,java/lang/String,indexOf + // For easy cut-and-paste of method names, allow VM output format + // as produced by Method::print_short_name: + // exclude java.lang.String::indexOf + // For simple implementation convenience here, convert them all to space. + + if (have_colon) { + if (*lp == '.') *lp = '/'; // dots build the package prefix + if (*lp == ':') *lp = ' '; + } + if (*lp == ',' || *lp == '.') *lp = ' '; + } + return true; +} + +bool MethodMatcher::match(Symbol* candidate, Symbol* match, Mode match_mode) const { + if (match_mode == Any) { + return true; + } + + if (match_mode == Exact) { + return candidate == match; + } + + ResourceMark rm; + const char * candidate_string = candidate->as_C_string(); + const char * match_string = match->as_C_string(); + + switch (match_mode) { + case Prefix: + return strstr(candidate_string, match_string) == candidate_string; + + case Suffix: { + size_t clen = strlen(candidate_string); + size_t mlen = strlen(match_string); + return clen >= mlen && strcmp(candidate_string + clen - mlen, match_string) == 0; + } + + case Substring: + return strstr(candidate_string, match_string) != NULL; + + default: + return false; + } +} + +static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) { + int match = MethodMatcher::Exact; + if (name[0] == '*') { + if (strlen(name) == 1) { + return MethodMatcher::Any; + } + match |= MethodMatcher::Suffix; + memmove(name, name + 1, strlen(name + 1) + 1); + } + + size_t len = strlen(name); + if (len > 0 && name[len - 1] == '*') { + match |= MethodMatcher::Prefix; + name[--len] = '\0'; + } + + if (strlen(name) == 0) { + error_msg = "** Not a valid pattern"; + return MethodMatcher::Any; + } + + if (strstr(name, "*") != NULL) { + error_msg = " Embedded * not allowed"; + return MethodMatcher::Unknown; + } + return (MethodMatcher::Mode)match; +} + +// Skip any leading spaces +void skip_leading_spaces(char*& line, int* total_bytes_read ) { + int bytes_read = 0; + sscanf(line, "%*[ \t]%n", &bytes_read); + if (bytes_read > 0) { + line += bytes_read; + *total_bytes_read += bytes_read; + } +} + +void MethodMatcher::parse_method_pattern(char*& line, const char*& error_msg, MethodMatcher* matcher) { + MethodMatcher::Mode c_match; + MethodMatcher::Mode m_match; + char class_name[256] = {0}; + char method_name[256] = {0}; + char sig[1024] = {0}; + int bytes_read = 0; + int total_bytes_read = 0; + + assert(error_msg == NULL, "Dont call here with error_msg already set"); + + if (!MethodMatcher::canonicalize(line, error_msg)) { + assert(error_msg != NULL, "Message must be set if parsing failed"); + return; + } + + skip_leading_spaces(line, &total_bytes_read); + + if (2 == sscanf(line, "%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, &bytes_read)) { + c_match = check_mode(class_name, error_msg); + m_match = check_mode(method_name, error_msg); + + if ((strchr(class_name, '<') != NULL) || (strchr(class_name, '>') != NULL)) { + error_msg = "Chars '<' and '>' not allowed in class name"; + return; + } + if ((strchr(method_name, '<') != NULL) || (strchr(method_name, '>') != NULL)) { + if ((strncmp("", method_name, 255) != 0) && (strncmp("", method_name, 255) != 0)) { + error_msg = "Chars '<' and '>' only allowed in and "; + return; + } + } + + if (c_match == MethodMatcher::Unknown || m_match == MethodMatcher::Unknown) { + assert(error_msg != NULL, "Must have been set by check_mode()"); + return; + } + + EXCEPTION_MARK; + Symbol* signature = NULL; + line += bytes_read; + bytes_read = 0; + + skip_leading_spaces(line, &total_bytes_read); + + // there might be a signature following the method. + // signatures always begin with ( so match that by hand + if (line[0] == '(') { + line++; + sig[0] = '('; + // scan the rest + if (1 == sscanf(line, "%254[[);/" RANGEBASE "]%n", sig+1, &bytes_read)) { + if (strchr(sig, '*') != NULL) { + error_msg = " Wildcard * not allowed in signature"; + return; + } + line += bytes_read; + } + signature = SymbolTable::new_symbol(sig, CHECK); + } + Symbol* c_name = SymbolTable::new_symbol(class_name, CHECK); + Symbol* m_name = SymbolTable::new_symbol(method_name, CHECK); + + matcher->init(c_name, c_match, m_name, m_match, signature); + return; + } else { + error_msg = "Could not parse method pattern"; + } +} + +bool MethodMatcher::matches(methodHandle method) const { + Symbol* class_name = method->method_holder()->name(); + Symbol* method_name = method->name(); + Symbol* signature = method->signature(); + + if (match(class_name, this->class_name(), _class_mode) && + match(method_name, this->method_name(), _method_mode) && + ((this->signature() == NULL) || match(signature, this->signature(), Prefix))) { + return true; + } + return false; +} + +void MethodMatcher::print_symbol(outputStream* st, Symbol* h, Mode mode) { + ResourceMark rm; + + if (mode == Suffix || mode == Substring || mode == Any) { + st->print("*"); + } + if (mode != Any) { + h->print_symbol_on(st); + } + if (mode == Prefix || mode == Substring) { + st->print("*"); + } +} + +void MethodMatcher::print_base(outputStream* st) { + print_symbol(st, class_name(), _class_mode); + st->print("."); + print_symbol(st, method_name(), _method_mode); + if (signature() != NULL) { + signature()->print_symbol_on(st); + } +} + + + + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/methodMatcher.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/compiler/methodMatcher.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_COMPILER_METHODMATCHER_HPP +#define SHARE_VM_COMPILER_METHODMATCHER_HPP + +#include "memory/allocation.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "memory/resourceArea.hpp" + +class MethodMatcher : public CHeapObj { + public: + enum Mode { + Exact, + Prefix = 1, + Suffix = 2, + Substring = Prefix | Suffix, + Any, + Unknown = -1 + }; + + protected: + Symbol* _class_name; + Symbol* _method_name; + Symbol* _signature; + Mode _class_mode; + Mode _method_mode; + + public: + Symbol* class_name() const { return _class_name; } + Mode class_mode() const { return _class_mode; } + Symbol* method_name() const { return _method_name; } + Mode method_mode() const { return _method_mode; } + Symbol* signature() const { return _signature; } + + MethodMatcher(); + ~MethodMatcher(); + + void init(Symbol* class_name, Mode class_mode, Symbol* method_name, Mode method_mode, Symbol* signature); + static void parse_method_pattern(char*& line, const char*& error_msg, MethodMatcher* m); + static void print_symbol(outputStream* st, Symbol* h, Mode mode); + bool matches(methodHandle method) const; + void print_base(outputStream* st); + + private: + static bool canonicalize(char * line, const char *& error_msg); + bool match(Symbol* candidate, Symbol* match, Mode match_mode) const; +}; + +class BasicMatcher : public MethodMatcher { +private: + BasicMatcher* _next; +public: + + BasicMatcher() : MethodMatcher(), + _next(NULL) { + } + + BasicMatcher(BasicMatcher* next) : + _next(next) { + } + + static BasicMatcher* parse_method_pattern(char* line, const char*& error_msg) { + assert(error_msg == NULL, "Dont call here with error_msg already set"); + BasicMatcher* bm = new BasicMatcher(); + MethodMatcher::parse_method_pattern(line, error_msg, bm); + if (error_msg != NULL) { + delete bm; + return NULL; + } + + // check for bad trailing characters + int bytes_read = 0; + sscanf(line, "%*[ \t]%n", &bytes_read); + if (line[bytes_read] != '\0') { + error_msg = "Unrecognized trailing text after method pattern"; + delete bm; + return NULL; + } + return bm; + } + + bool match(methodHandle method) { + for (BasicMatcher* current = this; current != NULL; current = current->next()) { + if (current->matches(method)) { + return true; + } + } + return false; + } + + void set_next(BasicMatcher* next) { _next = next; } + BasicMatcher* next() { return _next; } + + void print(outputStream* st) { print_base(st); } + void print_all(outputStream* st) { + print_base(st); + if (_next != NULL) { + _next->print_all(st); + } + } +}; + +#endif // SHARE_VM_COMPILER_METHODMATCHER_HPP + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/oopMap.cpp --- a/hotspot/src/share/vm/compiler/oopMap.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/oopMap.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -39,6 +39,9 @@ #ifdef COMPILER2 #include "opto/optoreg.hpp" #endif +#ifdef SPARC +#include "vmreg_sparc.inline.hpp" +#endif // OopMapStream @@ -58,7 +61,6 @@ _valid_omv = false; } - void OopMapStream::find_next() { while(_position++ < _size) { _omv.read_from(_stream); @@ -156,9 +158,7 @@ void OopMap::set_value(VMReg reg) { - // At this time, we only need value entries in our OopMap when ZapDeadCompiledLocals is active. - if (ZapDeadCompiledLocals) - set_xxx(reg, OopMapValue::value_value, VMRegImpl::Bad()); + // At this time, we don't need value entries in our OopMap. } @@ -199,7 +199,6 @@ set_om_data(new_data); } - void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) { assert(om_size() != -1,"Cannot grow a fixed OopMapSet"); @@ -276,10 +275,15 @@ static void add_derived_oop(oop* base, oop* derived) { #ifndef TIERED COMPILER1_PRESENT(ShouldNotReachHere();) +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + ShouldNotReachHere(); + } +#endif #endif // TIERED -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI DerivedPointerTable::add(derived, base); -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI } @@ -288,7 +292,7 @@ // Print oopmap and regmap tty->print_cr("------ "); CodeBlob* cb = fr->cb(); - ImmutableOopMapSet* maps = cb->oop_maps(); + const ImmutableOopMapSet* maps = cb->oop_maps(); const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc()); map->print(); if( cb->is_nmethod() ) { @@ -325,7 +329,7 @@ NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);) - ImmutableOopMapSet* maps = cb->oop_maps(); + const ImmutableOopMapSet* maps = cb->oop_maps(); const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc()); assert(map != NULL, "no ptr map found"); @@ -337,6 +341,11 @@ if (!oms.is_done()) { #ifndef TIERED COMPILER1_PRESENT(ShouldNotReachHere();) +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + ShouldNotReachHere(); + } +#endif #endif // !TIERED // Protect the operation on the derived pointers. This // protects the addition of derived pointers to the shared @@ -345,72 +354,73 @@ do { omv = oms.current(); oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); - if ( loc != NULL ) { - oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map); - oop *derived_loc = loc; - oop val = *base_loc; - if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { - // Ignore NULL oops and decoded NULL narrow oops which - // equal to Universe::narrow_oop_base when a narrow oop - // implicit null check is used in compiled code. - // The narrow_oop_base could be NULL or be the address - // of the page below heap depending on compressed oops mode. - } else - derived_oop_fn(base_loc, derived_loc); + guarantee(loc != NULL, "missing saved register"); + oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map); + oop *derived_loc = loc; + oop val = *base_loc; + if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { + // Ignore NULL oops and decoded NULL narrow oops which + // equal to Universe::narrow_oop_base when a narrow oop + // implicit null check is used in compiled code. + // The narrow_oop_base could be NULL or be the address + // of the page below heap depending on compressed oops mode. + } else { + derived_oop_fn(base_loc, derived_loc); } oms.next(); } while (!oms.is_done()); } } - // We want coop, value and oop oop_types - int mask = OopMapValue::oop_value | OopMapValue::value_value | OopMapValue::narrowoop_value; + // We want coop and oop oop_types + int mask = OopMapValue::oop_value | OopMapValue::narrowoop_value; { for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) { omv = oms.current(); oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); - if ( loc != NULL ) { - if ( omv.type() == OopMapValue::oop_value ) { - oop val = *loc; - if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { - // Ignore NULL oops and decoded NULL narrow oops which - // equal to Universe::narrow_oop_base when a narrow oop - // implicit null check is used in compiled code. - // The narrow_oop_base could be NULL or be the address - // of the page below heap depending on compressed oops mode. - continue; - } + // It should be an error if no location can be found for a + // register mentioned as contained an oop of some kind. Maybe + // this was allowed previously because value_value items might + // be missing? + guarantee(loc != NULL, "missing saved register"); + if ( omv.type() == OopMapValue::oop_value ) { + oop val = *loc; + if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) { + // Ignore NULL oops and decoded NULL narrow oops which + // equal to Universe::narrow_oop_base when a narrow oop + // implicit null check is used in compiled code. + // The narrow_oop_base could be NULL or be the address + // of the page below heap depending on compressed oops mode. + continue; + } #ifdef ASSERT - if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) || - !Universe::heap()->is_in_or_null(*loc)) { - tty->print_cr("# Found non oop pointer. Dumping state at failure"); - // try to dump out some helpful debugging information - trace_codeblob_maps(fr, reg_map); - omv.print(); - tty->print_cr("register r"); - omv.reg()->print(); - tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc); - // do the real assert. - assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer"); - } + if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) || + !Universe::heap()->is_in_or_null(*loc)) { + tty->print_cr("# Found non oop pointer. Dumping state at failure"); + // try to dump out some helpful debugging information + trace_codeblob_maps(fr, reg_map); + omv.print(); + tty->print_cr("register r"); + omv.reg()->print(); + tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc); + // do the real assert. + assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer"); + } #endif // ASSERT - oop_fn->do_oop(loc); - } else if ( omv.type() == OopMapValue::value_value ) { - assert((*loc) == (oop)NULL || !Universe::is_narrow_oop_base(*loc), - "found invalid value pointer"); - value_fn->do_oop(loc); - } else if ( omv.type() == OopMapValue::narrowoop_value ) { - narrowOop *nl = (narrowOop*)loc; + oop_fn->do_oop(loc); + } else if ( omv.type() == OopMapValue::narrowoop_value ) { + narrowOop *nl = (narrowOop*)loc; #ifndef VM_LITTLE_ENDIAN - if (!omv.reg()->is_stack()) { - // compressed oops in registers only take up 4 bytes of an - // 8 byte register but they are in the wrong part of the - // word so adjust loc to point at the right place. - nl = (narrowOop*)((address)nl + 4); - } + VMReg vmReg = omv.reg(); + // Don't do this on SPARC float registers as they can be individually addressed + if (!vmReg->is_stack() SPARC_ONLY(&& !vmReg->is_FloatRegister())) { + // compressed oops in registers only take up 4 bytes of an + // 8 byte register but they are in the wrong part of the + // word so adjust loc to point at the right place. + nl = (narrowOop*)((address)nl + 4); + } #endif - oop_fn->do_oop(nl); - } + oop_fn->do_oop(nl); } } } @@ -451,7 +461,7 @@ // Check that runtime stubs save all callee-saved registers #ifdef COMPILER2 - assert(cb->is_compiled_by_c1() || !cb->is_runtime_stub() || + assert(cb->is_compiled_by_c1() || cb->is_compiled_by_jvmci() || !cb->is_runtime_stub() || (nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT), "must save all"); #endif // COMPILER2 @@ -465,13 +475,18 @@ bool ImmutableOopMap::has_derived_pointer() const { #ifndef TIERED COMPILER1_PRESENT(return false); +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + return false; + } +#endif #endif // !TIERED -#ifdef COMPILER2 - OopMapStream oms((OopMap*)this,OopMapValue::derived_oop_value); +#if defined(COMPILER2) || INCLUDE_JVMCI + OopMapStream oms(this,OopMapValue::derived_oop_value); return oms.is_done(); #else return false; -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI } #endif //PRODUCT @@ -485,9 +500,6 @@ case OopMapValue::oop_value: st->print("Oop"); break; - case OopMapValue::value_value: - st->print("Value"); - break; case OopMapValue::narrowoop_value: st->print("NarrowOop"); break; @@ -607,74 +619,9 @@ } #endif -class ImmutableOopMapBuilder { -private: - class Mapping; - -private: - const OopMapSet* _set; - const OopMap* _empty; - const OopMap* _last; - int _empty_offset; - int _last_offset; - int _offset; - Mapping* _mapping; - ImmutableOopMapSet* _new_set; - - /* Used for bookkeeping when building ImmutableOopMaps */ - class Mapping : public ResourceObj { - public: - enum kind_t { OOPMAP_UNKNOWN = 0, OOPMAP_NEW = 1, OOPMAP_EMPTY = 2, OOPMAP_DUPLICATE = 3 }; - - kind_t _kind; - int _offset; - int _size; - const OopMap* _map; - const OopMap* _other; - - Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(NULL) {} - - void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { - _kind = kind; - _offset = offset; - _size = size; - _map = map; - _other = other; - } - }; - -public: - ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _new_set(NULL), _empty(NULL), _last(NULL), _empty_offset(-1), _last_offset(-1), _offset(0) { - _mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size()); - } - - int heap_size(); - ImmutableOopMapSet* build(); -private: - bool is_empty(const OopMap* map) const { - return map->count() == 0; - } - - bool is_last_duplicate(const OopMap* map) { - if (_last != NULL && _last->count() > 0 && _last->equals(map)) { - return true; - } - return false; - } - -#ifdef ASSERT - void verify(address buffer, int size, const ImmutableOopMapSet* set); -#endif - - bool has_empty() const { - return _empty_offset != -1; - } - - int size_for(const OopMap* map) const; - void fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); - int fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); - void fill(ImmutableOopMapSet* set, int size); -}; +ImmutableOopMapBuilder::ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _new_set(NULL), _empty(NULL), _last(NULL), _empty_offset(-1), _last_offset(-1), _offset(0), _required(-1) { + _mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size()); +} int ImmutableOopMapBuilder::size_for(const OopMap* map) const { return align_size_up(sizeof(ImmutableOopMap) + map->data_size(), 8); @@ -719,6 +666,7 @@ int total = base + pairs + _offset; DEBUG_ONLY(total += 8); + _required = total; return total; } @@ -770,19 +718,23 @@ } #endif +ImmutableOopMapSet* ImmutableOopMapBuilder::generate_into(address buffer) { + DEBUG_ONLY(memset(&buffer[_required-8], 0xff, 8)); + + _new_set = new (buffer) ImmutableOopMapSet(_set, _required); + fill(_new_set, _required); + + DEBUG_ONLY(verify(buffer, _required, _new_set)); + + return _new_set; +} + ImmutableOopMapSet* ImmutableOopMapBuilder::build() { - int required = heap_size(); + _required = heap_size(); // We need to allocate a chunk big enough to hold the ImmutableOopMapSet and all of its ImmutableOopMaps - address buffer = (address) NEW_C_HEAP_ARRAY(unsigned char, required, mtCode); - DEBUG_ONLY(memset(&buffer[required-8], 0xff, 8)); - - _new_set = new (buffer) ImmutableOopMapSet(_set, required); - fill(_new_set, required); - - DEBUG_ONLY(verify(buffer, required, _new_set)); - - return _new_set; + address buffer = (address) NEW_C_HEAP_ARRAY(unsigned char, _required, mtCode); + return generate_into(buffer); } ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) { @@ -794,7 +746,7 @@ //------------------------------DerivedPointerTable--------------------------- -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI class DerivedPointerEntry : public CHeapObj { private: @@ -887,4 +839,4 @@ _active = false; } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/compiler/oopMap.hpp --- a/hotspot/src/share/vm/compiler/oopMap.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/compiler/oopMap.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ // Interface for generating the frame map for compiled code. A frame map // describes for a specific pc whether each register and frame stack slot is: // Oop - A GC root for current frame -// Value - Live non-oop, non-float value: int, either half of double // Dead - Dead; can be Zapped for debugging // CalleeXX - Callee saved; also describes which caller register is saved // DerivedXX - A derived oop; original oop is described. @@ -54,7 +53,7 @@ public: // Constants - enum { type_bits = 5, + enum { type_bits = 4, register_bits = BitsPerShort - type_bits }; enum { type_shift = 0, @@ -68,10 +67,9 @@ enum oop_types { // must fit in type_bits unused_value =0, // powers of 2, for masking OopMapStream oop_value = 1, - value_value = 2, - narrowoop_value = 4, - callee_saved_value = 8, - derived_oop_value= 16 }; + narrowoop_value = 2, + callee_saved_value = 4, + derived_oop_value= 8 }; // Constructors OopMapValue () { set_value(0); set_content_reg(VMRegImpl::Bad()); } @@ -96,13 +94,11 @@ // Querying bool is_oop() { return mask_bits(value(), type_mask_in_place) == oop_value; } - bool is_value() { return mask_bits(value(), type_mask_in_place) == value_value; } bool is_narrowoop() { return mask_bits(value(), type_mask_in_place) == narrowoop_value; } bool is_callee_saved() { return mask_bits(value(), type_mask_in_place) == callee_saved_value; } bool is_derived_oop() { return mask_bits(value(), type_mask_in_place) == derived_oop_value; } void set_oop() { set_value((value() & register_mask_in_place) | oop_value); } - void set_value() { set_value((value() & register_mask_in_place) | value_value); } void set_narrowoop() { set_value((value() & register_mask_in_place) | narrowoop_value); } void set_callee_saved() { set_value((value() & register_mask_in_place) | callee_saved_value); } void set_derived_oop() { set_value((value() & register_mask_in_place) | derived_oop_value); } @@ -188,6 +184,8 @@ void copy_data_to(address addr) const; OopMap* deep_copy(); + bool has_derived_pointer() const PRODUCT_RETURN0; + bool legal_vm_reg_name(VMReg local) { return OopMapValue::legal_vm_reg_name(local); } @@ -354,13 +352,82 @@ #endif }; +class ImmutableOopMapBuilder { +private: + class Mapping; + +private: + const OopMapSet* _set; + const OopMap* _empty; + const OopMap* _last; + int _empty_offset; + int _last_offset; + int _offset; + int _required; + Mapping* _mapping; + ImmutableOopMapSet* _new_set; + + /* Used for bookkeeping when building ImmutableOopMaps */ + class Mapping : public ResourceObj { + public: + enum kind_t { OOPMAP_UNKNOWN = 0, OOPMAP_NEW = 1, OOPMAP_EMPTY = 2, OOPMAP_DUPLICATE = 3 }; + + kind_t _kind; + int _offset; + int _size; + const OopMap* _map; + const OopMap* _other; + + Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(NULL) {} + + void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { + _kind = kind; + _offset = offset; + _size = size; + _map = map; + _other = other; + } + }; + +public: + ImmutableOopMapBuilder(const OopMapSet* set); + + int heap_size(); + ImmutableOopMapSet* build(); + ImmutableOopMapSet* generate_into(address buffer); +private: + bool is_empty(const OopMap* map) const { + return map->count() == 0; + } + + bool is_last_duplicate(const OopMap* map) { + if (_last != NULL && _last->count() > 0 && _last->equals(map)) { + return true; + } + return false; + } + +#ifdef ASSERT + void verify(address buffer, int size, const ImmutableOopMapSet* set); +#endif + + bool has_empty() const { + return _empty_offset != -1; + } + + int size_for(const OopMap* map) const; + void fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); + int fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset, const ImmutableOopMapSet* set); + void fill(ImmutableOopMapSet* set, int size); +}; + // Derived pointer support. This table keeps track of all derived points on a // stack. It is cleared before each scavenge/GC. During the traversal of all // oops, it is filled in with references to all locations that contains a // derived oop (assumed to be very few). When the GC is complete, the derived // pointers are updated based on their base pointers new value and an offset. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI class DerivedPointerTable : public AllStatic { friend class VMStructs; private: @@ -396,6 +463,6 @@ } } }; -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI #endif // SHARE_VM_COMPILER_OOPMAP_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/adaptiveFreeList.cpp --- a/hotspot/src/share/vm/gc/cms/adaptiveFreeList.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/adaptiveFreeList.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -133,17 +133,17 @@ + _allocation_stats.coal_births() + 1) // Total Production Stock + 1 >= (_allocation_stats.split_deaths() + _allocation_stats.coal_deaths() + (ssize_t)count()), // Total Current Stock + depletion - err_msg("FreeList " PTR_FORMAT " of size " SIZE_FORMAT - " violates Conservation Principle: " - "prev_sweep(" SIZE_FORMAT ")" - " + split_births(" SIZE_FORMAT ")" - " + coal_births(" SIZE_FORMAT ") + 1 >= " - " split_deaths(" SIZE_FORMAT ")" - " coal_deaths(" SIZE_FORMAT ")" - " + count(" SSIZE_FORMAT ")", - p2i(this), size(), _allocation_stats.prev_sweep(), _allocation_stats.split_births(), - _allocation_stats.coal_births(), _allocation_stats.split_deaths(), - _allocation_stats.coal_deaths(), count())); + "FreeList " PTR_FORMAT " of size " SIZE_FORMAT + " violates Conservation Principle: " + "prev_sweep(" SIZE_FORMAT ")" + " + split_births(" SIZE_FORMAT ")" + " + coal_births(" SIZE_FORMAT ") + 1 >= " + " split_deaths(" SIZE_FORMAT ")" + " coal_deaths(" SIZE_FORMAT ")" + " + count(" SSIZE_FORMAT ")", + p2i(this), size(), _allocation_stats.prev_sweep(), _allocation_stats.split_births(), + _allocation_stats.coal_births(), _allocation_stats.split_deaths(), + _allocation_stats.coal_deaths(), count()); } #endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/allocationStats.hpp --- a/hotspot/src/share/vm/gc/cms/allocationStats.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/allocationStats.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -105,9 +105,9 @@ ssize_t demand = prev_sweep() - (ssize_t)count + split_births() + coal_births() - split_deaths() - coal_deaths(); assert(demand >= 0, - err_msg("Demand (" SSIZE_FORMAT ") should be non-negative for " - PTR_FORMAT " (size=" SIZE_FORMAT ")", - demand, p2i(this), count)); + "Demand (" SSIZE_FORMAT ") should be non-negative for " + PTR_FORMAT " (size=" SIZE_FORMAT ")", + demand, p2i(this), count); // Defensive: adjust for imprecision in event counting if (demand < 0) { demand = 0; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp --- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1959,9 +1959,9 @@ MemRegion ur = used_region(); MemRegion urasm = used_region_at_save_marks(); assert(ur.contains(urasm), - err_msg(" Error at save_marks(): [" PTR_FORMAT "," PTR_FORMAT ")" - " should contain [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(ur.start()), p2i(ur.end()), p2i(urasm.start()), p2i(urasm.end()))); + " Error at save_marks(): [" PTR_FORMAT "," PTR_FORMAT ")" + " should contain [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(ur.start()), p2i(ur.end()), p2i(urasm.start()), p2i(urasm.end())); #endif // inform allocator that promotions should be tracked. assert(_promoInfo.noPromotions(), "_promoInfo inconsistency"); @@ -2875,9 +2875,9 @@ smallSplitBirth(rem); } assert(n * word_sz == fc->size(), - err_msg("Chunk size " SIZE_FORMAT " is not exactly splittable by " - SIZE_FORMAT " sized chunks of size " SIZE_FORMAT, - fc->size(), n, word_sz)); + "Chunk size " SIZE_FORMAT " is not exactly splittable by " + SIZE_FORMAT " sized chunks of size " SIZE_FORMAT, + fc->size(), n, word_sz); return fc; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1593,7 +1593,7 @@ SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer(); gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start()); - GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL, gc_tracer->gc_id()); + GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL); // Temporarily widen the span of the weak reference processing to // the entire heap. @@ -1654,7 +1654,7 @@ _collectorState = Resetting; assert(_restart_addr == NULL, "Should have been NULL'd before baton was passed"); - reset(false /* == !concurrent */); + reset_stw(); _cmsGen->reset_after_compaction(); _concurrent_cycles_since_last_unload = 0; @@ -1934,7 +1934,7 @@ } case Resetting: // CMS heap resizing has been completed - reset(true); + reset_concurrent(); assert(_collectorState == Idling, "Collector state should " "have changed"); @@ -2367,7 +2367,9 @@ // way with the marking information used by GC. NoRefDiscovery no_discovery(ref_processor()); - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;) +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif // Clear any marks from a previous round verification_mark_bm()->clear_all(); @@ -2825,7 +2827,6 @@ public: CMSPhaseAccounting(CMSCollector *collector, const char *phase, - const GCId gc_id, bool print_cr = true); ~CMSPhaseAccounting(); @@ -2834,7 +2835,6 @@ const char *_phase; elapsedTimer _wallclock; bool _print_cr; - const GCId _gc_id; public: // Not MT-safe; so do not pass around these StackObj's @@ -2850,15 +2850,14 @@ CMSPhaseAccounting::CMSPhaseAccounting(CMSCollector *collector, const char *phase, - const GCId gc_id, bool print_cr) : - _collector(collector), _phase(phase), _print_cr(print_cr), _gc_id(gc_id) { + _collector(collector), _phase(phase), _print_cr(print_cr) { if (PrintCMSStatistics != 0) { _collector->resetYields(); } if (PrintGCDetails) { - gclog_or_tty->gclog_stamp(_gc_id); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print_cr("[%s-concurrent-%s-start]", _collector->cmsGen()->short_name(), _phase); } @@ -2872,7 +2871,7 @@ _collector->stopTimer(); _wallclock.stop(); if (PrintGCDetails) { - gclog_or_tty->gclog_stamp(_gc_id); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print("[%s-concurrent-%s: %3.3f/%3.3f secs]", _collector->cmsGen()->short_name(), _phase, _collector->timerValue(), _wallclock.seconds()); @@ -2951,7 +2950,7 @@ setup_cms_unloading_and_verification_state(); NOT_PRODUCT(GCTraceTime t("\ncheckpointRootsInitialWork", - PrintGCDetails && Verbose, true, _gc_timer_cm, _gc_tracer_cm->gc_id());) + PrintGCDetails && Verbose, true, _gc_timer_cm);) // Reset all the PLAB chunk arrays if necessary. if (_survivor_plab_array != NULL && !CMSPLABRecordAlways) { @@ -2987,7 +2986,9 @@ } { - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;) +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif if (CMSParallelInitialMarkEnabled) { // The parallel version. WorkGang* workers = gch->workers(); @@ -3054,7 +3055,7 @@ CMSTokenSyncWithLocks ts(true, bitMapLock()); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "mark", _gc_tracer_cm->gc_id(), !PrintGCDetails); + CMSPhaseAccounting pa(this, "mark", !PrintGCDetails); bool res = markFromRootsWork(); if (res) { _collectorState = Precleaning; @@ -3476,7 +3477,7 @@ // been published), so we do not need to check for // uninitialized objects before pushing here. void Par_ConcMarkingClosure::do_oop(oop obj) { - assert(obj->is_oop_or_null(true), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; // Check if oop points into the CMS generation // and is not marked @@ -3751,7 +3752,7 @@ _start_sampling = false; } TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "preclean", _gc_tracer_cm->gc_id(), !PrintGCDetails); + CMSPhaseAccounting pa(this, "preclean", !PrintGCDetails); preclean_work(CMSPrecleanRefLists1, CMSPrecleanSurvivors1); } CMSTokenSync x(true); // is cms thread @@ -3780,7 +3781,7 @@ // we will never do an actual abortable preclean cycle. if (get_eden_used() > CMSScheduleRemarkEdenSizeThreshold) { TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "abortable-preclean", _gc_tracer_cm->gc_id(), !PrintGCDetails); + CMSPhaseAccounting pa(this, "abortable-preclean", !PrintGCDetails); // We need more smarts in the abortable preclean // loop below to deal with cases where allocation // in young gen is very very slow, and our precleaning @@ -3925,7 +3926,7 @@ GCTimer *gc_timer = NULL; // Currently not tracing concurrent phases rp->preclean_discovered_references( rp->is_alive_non_header(), &keep_alive, &complete_trace, &yield_cl, - gc_timer, _gc_tracer_cm->gc_id()); + gc_timer); } if (clean_survivor) { // preclean the active survivor space(s) @@ -4261,7 +4262,7 @@ // expect it to be false and set to true FlagSetting fl(gch->_is_gc_active, false); NOT_PRODUCT(GCTraceTime t("Scavenge-Before-Remark", - PrintGCDetails && Verbose, true, _gc_timer_cm, _gc_tracer_cm->gc_id());) + PrintGCDetails && Verbose, true, _gc_timer_cm);) gch->do_collection(true, // full (i.e. force, see below) false, // !clear_all_soft_refs 0, // size @@ -4279,7 +4280,7 @@ } void CMSCollector::checkpointRootsFinalWork() { - NOT_PRODUCT(GCTraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());) + NOT_PRODUCT(GCTraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, _gc_timer_cm);) assert(haveFreelistLocks(), "must have free list locks"); assert_lock_strong(bitMapLock()); @@ -4316,7 +4317,9 @@ } { - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;) +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif // Note on the role of the mod union table: // Since the marker in "markFromRoots" marks concurrently with @@ -4329,11 +4332,10 @@ // the most recent young generation GC, minus those cleaned up by the // concurrent precleaning. if (CMSParallelRemarkEnabled) { - GCTraceTime t("Rescan (parallel) ", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("Rescan (parallel) ", PrintGCDetails, false, _gc_timer_cm); do_remark_parallel(); } else { - GCTraceTime t("Rescan (non-parallel) ", PrintGCDetails, false, - _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("Rescan (non-parallel) ", PrintGCDetails, false, _gc_timer_cm); do_remark_non_parallel(); } } @@ -4341,7 +4343,7 @@ verify_overflow_empty(); { - NOT_PRODUCT(GCTraceTime ts("refProcessingWork", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id());) + NOT_PRODUCT(GCTraceTime ts("refProcessingWork", PrintGCDetails, false, _gc_timer_cm);) refProcessingWork(); } verify_work_stacks_empty(); @@ -5116,7 +5118,7 @@ NULL, // space is set further below &_markBitMap, &_markStack, &mrias_cl); { - GCTraceTime t("grey object rescan", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("grey object rescan", PrintGCDetails, false, _gc_timer_cm); // Iterate over the dirty cards, setting the corresponding bits in the // mod union table. { @@ -5153,7 +5155,7 @@ Universe::verify(); } { - GCTraceTime t("root rescan", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("root rescan", PrintGCDetails, false, _gc_timer_cm); verify_work_stacks_empty(); @@ -5175,7 +5177,7 @@ } { - GCTraceTime t("visit unhandled CLDs", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("visit unhandled CLDs", PrintGCDetails, false, _gc_timer_cm); verify_work_stacks_empty(); @@ -5194,7 +5196,7 @@ } { - GCTraceTime t("dirty klass scan", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("dirty klass scan", PrintGCDetails, false, _gc_timer_cm); verify_work_stacks_empty(); @@ -5403,7 +5405,7 @@ _span, &_markBitMap, &_markStack, &cmsKeepAliveClosure, false /* !preclean */); { - GCTraceTime t("weak refs processing", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("weak refs processing", PrintGCDetails, false, _gc_timer_cm); ReferenceProcessorStats stats; if (rp->processing_is_mt()) { @@ -5428,15 +5430,13 @@ &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure, &task_executor, - _gc_timer_cm, - _gc_tracer_cm->gc_id()); + _gc_timer_cm); } else { stats = rp->process_discovered_references(&_is_alive_closure, &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure, NULL, - _gc_timer_cm, - _gc_tracer_cm->gc_id()); + _gc_timer_cm); } _gc_tracer_cm->report_gc_reference_stats(stats); @@ -5447,7 +5447,7 @@ if (should_unload_classes()) { { - GCTraceTime t("class unloading", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("class unloading", PrintGCDetails, false, _gc_timer_cm); // Unload classes and purge the SystemDictionary. bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure); @@ -5460,13 +5460,13 @@ } { - GCTraceTime t("scrub symbol table", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("scrub symbol table", PrintGCDetails, false, _gc_timer_cm); // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); } { - GCTraceTime t("scrub string table", PrintGCDetails, false, _gc_timer_cm, _gc_tracer_cm->gc_id()); + GCTraceTime t("scrub string table", PrintGCDetails, false, _gc_timer_cm); // Delete entries for dead interned strings. StringTable::unlink(&_is_alive_closure); } @@ -5534,7 +5534,7 @@ _intra_sweep_timer.start(); { TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting pa(this, "sweep", _gc_tracer_cm->gc_id(), !PrintGCDetails); + CMSPhaseAccounting pa(this, "sweep", !PrintGCDetails); // First sweep the old gen { CMSTokenSyncWithLocks ts(true, _cmsGen->freelistLock(), @@ -5704,74 +5704,77 @@ // Reset CMS data structures (for now just the marking bit map) // preparatory for the next cycle. -void CMSCollector::reset(bool concurrent) { - if (concurrent) { - CMSTokenSyncWithLocks ts(true, bitMapLock()); - - // If the state is not "Resetting", the foreground thread - // has done a collection and the resetting. - if (_collectorState != Resetting) { - assert(_collectorState == Idling, "The state should only change" - " because the foreground collector has finished the collection"); - return; - } - - // Clear the mark bitmap (no grey objects to start with) - // for the next cycle. - TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - CMSPhaseAccounting cmspa(this, "reset", _gc_tracer_cm->gc_id(), !PrintGCDetails); - - HeapWord* curAddr = _markBitMap.startWord(); - while (curAddr < _markBitMap.endWord()) { - size_t remaining = pointer_delta(_markBitMap.endWord(), curAddr); - MemRegion chunk(curAddr, MIN2(CMSBitMapYieldQuantum, remaining)); - _markBitMap.clear_large_range(chunk); - if (ConcurrentMarkSweepThread::should_yield() && - !foregroundGCIsActive() && - CMSYield) { - assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(), - "CMS thread should hold CMS token"); - assert_lock_strong(bitMapLock()); - bitMapLock()->unlock(); - ConcurrentMarkSweepThread::desynchronize(true); - stopTimer(); - if (PrintCMSStatistics != 0) { - incrementYields(); - } - - // See the comment in coordinator_yield() - for (unsigned i = 0; i < CMSYieldSleepCount && - ConcurrentMarkSweepThread::should_yield() && - !CMSCollector::foregroundGCIsActive(); ++i) { - os::sleep(Thread::current(), 1, false); - } - - ConcurrentMarkSweepThread::synchronize(true); - bitMapLock()->lock_without_safepoint_check(); - startTimer(); +void CMSCollector::reset_concurrent() { + CMSTokenSyncWithLocks ts(true, bitMapLock()); + + // If the state is not "Resetting", the foreground thread + // has done a collection and the resetting. + if (_collectorState != Resetting) { + assert(_collectorState == Idling, "The state should only change" + " because the foreground collector has finished the collection"); + return; + } + + // Clear the mark bitmap (no grey objects to start with) + // for the next cycle. + TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); + CMSPhaseAccounting cmspa(this, "reset", !PrintGCDetails); + + HeapWord* curAddr = _markBitMap.startWord(); + while (curAddr < _markBitMap.endWord()) { + size_t remaining = pointer_delta(_markBitMap.endWord(), curAddr); + MemRegion chunk(curAddr, MIN2(CMSBitMapYieldQuantum, remaining)); + _markBitMap.clear_large_range(chunk); + if (ConcurrentMarkSweepThread::should_yield() && + !foregroundGCIsActive() && + CMSYield) { + assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(), + "CMS thread should hold CMS token"); + assert_lock_strong(bitMapLock()); + bitMapLock()->unlock(); + ConcurrentMarkSweepThread::desynchronize(true); + stopTimer(); + if (PrintCMSStatistics != 0) { + incrementYields(); } - curAddr = chunk.end(); - } - // A successful mostly concurrent collection has been done. - // Because only the full (i.e., concurrent mode failure) collections - // are being measured for gc overhead limits, clean the "near" flag - // and count. - size_policy()->reset_gc_overhead_limit_count(); - _collectorState = Idling; - } else { - // already have the lock - assert(_collectorState == Resetting, "just checking"); - assert_lock_strong(bitMapLock()); - _markBitMap.clear_all(); - _collectorState = Idling; - } - + + // See the comment in coordinator_yield() + for (unsigned i = 0; i < CMSYieldSleepCount && + ConcurrentMarkSweepThread::should_yield() && + !CMSCollector::foregroundGCIsActive(); ++i) { + os::sleep(Thread::current(), 1, false); + } + + ConcurrentMarkSweepThread::synchronize(true); + bitMapLock()->lock_without_safepoint_check(); + startTimer(); + } + curAddr = chunk.end(); + } + // A successful mostly concurrent collection has been done. + // Because only the full (i.e., concurrent mode failure) collections + // are being measured for gc overhead limits, clean the "near" flag + // and count. + size_policy()->reset_gc_overhead_limit_count(); + _collectorState = Idling; + + register_gc_end(); +} + +// Same as above but for STW paths +void CMSCollector::reset_stw() { + // already have the lock + assert(_collectorState == Resetting, "just checking"); + assert_lock_strong(bitMapLock()); + GCIdMarkAndRestore gc_id_mark(_cmsThread->gc_id()); + _markBitMap.clear_all(); + _collectorState = Idling; register_gc_end(); } void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) { TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer_cm->gc_id()); + GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); switch (op) { @@ -6458,7 +6461,7 @@ // isMarked() query is "safe". bool ScanMarkedObjectsAgainClosure::do_object_bm(oop p, MemRegion mr) { // Ignore mark word because we are running concurrent with mutators - assert(p->is_oop_or_null(true), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(p))); + assert(p->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(p)); HeapWord* addr = (HeapWord*)p; assert(_span.contains(addr), "we are scanning the CMS generation"); bool is_obj_array = false; @@ -6893,7 +6896,7 @@ } void PushAndMarkVerifyClosure::do_oop(oop obj) { - assert(obj->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr) && !_verification_bm->isMarked(addr)) { // Oop lies in _span and isn't yet grey or black @@ -6991,7 +6994,7 @@ void PushOrMarkClosure::do_oop(oop obj) { // Ignore mark word because we are running concurrent with mutators. - assert(obj->is_oop_or_null(true), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; if (_span.contains(addr) && !_bitMap->isMarked(addr)) { // Oop lies in _span and isn't yet grey or black @@ -7029,7 +7032,7 @@ void Par_PushOrMarkClosure::do_oop(oop obj) { // Ignore mark word because we are running concurrent with mutators. - assert(obj->is_oop_or_null(true), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(true), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; if (_whole_span.contains(addr) && !_bit_map->isMarked(addr)) { // Oop lies in _span and isn't yet grey or black @@ -7106,7 +7109,7 @@ // path and may be at the end of the global overflow list (so // the mark word may be NULL). assert(obj->is_oop_or_null(true /* ignore mark word */), - err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; // Check if oop points into the CMS generation // and is not marked @@ -7186,7 +7189,7 @@ // the debugger, is_oop_or_null(false) may subsequently start // to hold. assert(obj->is_oop_or_null(true), - err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); HeapWord* addr = (HeapWord*)obj; // Check if oop points into the CMS generation // and is not marked @@ -7423,7 +7426,7 @@ // coalesced chunk to the appropriate free list. if (inFreeRange()) { assert(freeFinger() >= _sp->bottom() && freeFinger() < _limit, - err_msg("freeFinger() " PTR_FORMAT " is out-of-bounds", p2i(freeFinger()))); + "freeFinger() " PTR_FORMAT " is out-of-bounds", p2i(freeFinger())); flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger())); if (CMSTraceSweeper) { @@ -7825,10 +7828,10 @@ assert(inFreeRange(), "Should only be called if currently in a free range."); HeapWord* const eob = ((HeapWord*)fc) + chunk_size; assert(_sp->used_region().contains(eob - 1), - err_msg("eob = " PTR_FORMAT " eob-1 = " PTR_FORMAT " _limit = " PTR_FORMAT - " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")" - " when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")", - p2i(eob), p2i(eob-1), p2i(_limit), p2i(_sp->bottom()), p2i(_sp->end()), p2i(fc), chunk_size)); + "eob = " PTR_FORMAT " eob-1 = " PTR_FORMAT " _limit = " PTR_FORMAT + " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")" + " when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")", + p2i(eob), p2i(eob-1), p2i(_limit), p2i(_sp->bottom()), p2i(_sp->end()), p2i(fc), chunk_size); if (eob >= _limit) { assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit"); if (CMSTraceSweeper) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -296,8 +296,8 @@ size_t end() { assert(_index <= capacity(), - err_msg("_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT "): out of bounds", - _index, _capacity)); + "_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT "): out of bounds", + _index, _capacity); return _index; } // exclusive @@ -322,9 +322,9 @@ } else { ++_overflows; assert(_index == _capacity, - err_msg("_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT - "): out of bounds at overflow#" SIZE_FORMAT, - _index, _capacity, _overflows)); + "_index (" SIZE_FORMAT ") > _capacity (" SIZE_FORMAT + "): out of bounds at overflow#" SIZE_FORMAT, + _index, _capacity, _overflows); } } }; @@ -799,8 +799,10 @@ // Concurrent sweeping work void sweepWork(ConcurrentMarkSweepGeneration* old_gen); - // (Concurrent) resetting of support data structures - void reset(bool concurrent); + // Concurrent resetting of support data structures + void reset_concurrent(); + // Resetting of support data structures from a STW full GC + void reset_stw(); // Clear _expansion_cause fields of constituent generations void clear_expansion_cause(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp --- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,6 +26,7 @@ #include "classfile/systemDictionary.hpp" #include "gc/cms/concurrentMarkSweepGeneration.inline.hpp" #include "gc/cms/concurrentMarkSweepThread.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/oop.inline.hpp" @@ -124,6 +125,7 @@ while (!_should_terminate) { sleepBeforeNextCycle(); if (_should_terminate) break; + GCIdMark gc_id_mark; GCCause::Cause cause = _collector->_full_gc_requested ? _collector->_full_gc_cause : GCCause::_cms_concurrent_mark; _collector->collect_in_background(cause); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -43,7 +43,7 @@ uint n_threads) { assert(n_threads > 0, "expected n_threads > 0"); assert(n_threads <= ParallelGCThreads, - err_msg("n_threads: %u > ParallelGCThreads: %u", n_threads, ParallelGCThreads)); + "n_threads: %u > ParallelGCThreads: %u", n_threads, ParallelGCThreads); // Make sure the LNC array is valid for the space. jbyte** lowest_non_clean; @@ -370,18 +370,18 @@ - lowest_non_clean_base_chunk_index; if (last_chunk_index_to_check > last_chunk_index) { assert(last_block + last_block_size > used.end(), - err_msg("Inconsistency detected: last_block [" PTR_FORMAT "," PTR_FORMAT "]" - " does not exceed used.end() = " PTR_FORMAT "," - " yet last_chunk_index_to_check " INTPTR_FORMAT - " exceeds last_chunk_index " INTPTR_FORMAT, - p2i(last_block), p2i(last_block + last_block_size), - p2i(used.end()), - last_chunk_index_to_check, last_chunk_index)); + "Inconsistency detected: last_block [" PTR_FORMAT "," PTR_FORMAT "]" + " does not exceed used.end() = " PTR_FORMAT "," + " yet last_chunk_index_to_check " INTPTR_FORMAT + " exceeds last_chunk_index " INTPTR_FORMAT, + p2i(last_block), p2i(last_block + last_block_size), + p2i(used.end()), + last_chunk_index_to_check, last_chunk_index); assert(sp->used_region().end() > used.end(), - err_msg("Expansion did not happen: " - "[" PTR_FORMAT "," PTR_FORMAT ") -> [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(sp->used_region().start()), p2i(sp->used_region().end()), - p2i(used.start()), p2i(used.end()))); + "Expansion did not happen: " + "[" PTR_FORMAT "," PTR_FORMAT ") -> [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(sp->used_region().start()), p2i(sp->used_region().end()), + p2i(used.start()), p2i(used.end())); NOISY(tty->print_cr(" process_chunk_boundary: heap expanded; explicitly bounding last_chunk");) last_chunk_index_to_check = last_chunk_index; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/parNewGeneration.cpp --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -896,7 +896,7 @@ size_policy->minor_collection_begin(); } - GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL, _gc_tracer.gc_id()); + GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); // Capture heap used before collection (for printing). size_t gch_prev_used = gch->used(); @@ -959,15 +959,17 @@ ParNewRefProcTaskExecutor task_executor(*this, *_old_gen, thread_state_set); stats = rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers, &task_executor, - _gc_timer, _gc_tracer.gc_id()); + _gc_timer); } else { thread_state_set.flush(); gch->save_marks(); stats = rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers, NULL, - _gc_timer, _gc_tracer.gc_id()); + _gc_timer); } _gc_tracer.report_gc_reference_stats(stats); + _gc_tracer.report_tenuring_threshold(tenuring_threshold()); + if (!promotion_failed()) { // Swap the survivor spaces. eden()->clear(SpaceDecorator::Mangle); @@ -1030,7 +1032,6 @@ rp->verify_no_references_recorded(); gch->trace_heap_after_gc(gc_tracer()); - _gc_tracer.report_tenuring_threshold(tenuring_threshold()); _gc_timer->register_gc_end(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/promotionInfo.hpp --- a/hotspot/src/share/vm/gc/cms/promotionInfo.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/promotionInfo.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -73,7 +73,7 @@ } else { res = (PromotedObject*)(_next & next_mask); } - assert(oop(res)->is_oop_or_null(true /* ignore mark word */), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res)))); + assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res))); return res; } inline void setNext(PromotedObject* x) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp --- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -58,7 +58,7 @@ void VM_CMS_Operation::verify_before_gc() { if (VerifyBeforeGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm, _collector->_gc_tracer_cm->gc_id()); + GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); @@ -70,7 +70,7 @@ void VM_CMS_Operation::verify_after_gc() { if (VerifyAfterGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { - GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm, _collector->_gc_tracer_cm->gc_id()); + GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm); HandleMark hm; FreelistLocker x(_collector); MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); @@ -134,6 +134,7 @@ return; } HS_PRIVATE_CMS_INITMARK_BEGIN(); + GCIdMark gc_id_mark(_gc_id); _collector->_gc_timer_cm->register_gc_pause_start("Initial Mark"); @@ -161,6 +162,7 @@ return; } HS_PRIVATE_CMS_REMARK_BEGIN(); + GCIdMark gc_id_mark(_gc_id); _collector->_gc_timer_cm->register_gc_pause_start("Final Mark"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp --- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -27,6 +27,7 @@ #include "gc/cms/concurrentMarkSweepGeneration.hpp" #include "gc/shared/gcCause.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/vmGCOperations.hpp" #include "runtime/vm_operations.hpp" @@ -53,6 +54,7 @@ protected: CMSCollector* _collector; // associated collector bool _prologue_succeeded; // whether doit_prologue succeeded + uint _gc_id; bool lost_race() const; @@ -63,7 +65,8 @@ public: VM_CMS_Operation(CMSCollector* collector): _collector(collector), - _prologue_succeeded(false) {} + _prologue_succeeded(false), + _gc_id(GCId::current()) {} ~VM_CMS_Operation() {} // The legal collector state for executing this CMS op. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp --- a/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/cms/yieldingWorkgroup.hpp" +#include "gc/shared/gcId.hpp" #include "utilities/macros.hpp" YieldingFlexibleGangWorker::YieldingFlexibleGangWorker(YieldingFlexibleWorkGang* gang, int id) @@ -340,6 +341,7 @@ // Now, release the gang mutex and do the work. { MutexUnlockerEx mul(gang_monitor, Mutex::_no_safepoint_check_flag); + GCIdMark gc_id_mark(data.task()->gc_id()); data.task()->work(id); // This might include yielding } // Reacquire monitor and note completion of this worker diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp --- a/hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/bufferingOopClosure.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -153,10 +153,10 @@ boc.done(); - #define assert_testCount(got, expected) \ - assert((got) == (expected), \ - err_msg("Expected: %d, got: %d, when running testCount(%d, %d, %d)", \ - (got), (expected), num_narrow, num_full, do_oop_order)) + #define assert_testCount(got, expected) \ + assert((got) == (expected), \ + "Expected: %d, got: %d, when running testCount(%d, %d, %d)", \ + (got), (expected), num_narrow, num_full, do_oop_order) assert_testCount(num_narrow, coc.narrow_oop_count()); assert_testCount(num_full, coc.full_oop_count()); @@ -190,11 +190,11 @@ fr.oops_do(&boc, 0); - #define assert_testIsBufferEmptyOrFull(got, expected) \ - assert((got) == (expected), \ - err_msg("Expected: %d, got: %d. testIsBufferEmptyOrFull(%d, %d, %s, %s)", \ - (got), (expected), num_narrow, num_full, \ - BOOL_TO_STR(expect_empty), BOOL_TO_STR(expect_full))) + #define assert_testIsBufferEmptyOrFull(got, expected) \ + assert((got) == (expected), \ + "Expected: %d, got: %d. testIsBufferEmptyOrFull(%d, %d, %s, %s)", \ + (got), (expected), num_narrow, num_full, \ + BOOL_TO_STR(expect_empty), BOOL_TO_STR(expect_full)) assert_testIsBufferEmptyOrFull(expect_empty, boc.is_buffer_empty()); assert_testIsBufferEmptyOrFull(expect_full, boc.is_buffer_full()); @@ -232,8 +232,8 @@ boc.done(); assert(boc.is_buffer_empty(), - err_msg("Should be empty after call to done(). testEmptyAfterDone(%d, %d)", - num_narrow, num_full)); + "Should be empty after call to done(). testEmptyAfterDone(%d, %d)", + num_narrow, num_full); } static void testEmptyAfterDone() { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp --- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -91,10 +91,8 @@ #ifndef PRODUCT void CollectionSetChooser::verify() { - guarantee(_end <= regions_length(), - err_msg("_end: %u regions length: %u", _end, regions_length())); - guarantee(_front <= _end, - err_msg("_front: %u _end: %u", _front, _end)); + guarantee(_end <= regions_length(), "_end: %u regions length: %u", _end, regions_length()); + guarantee(_front <= _end, "_front: %u _end: %u", _front, _end); uint index = 0; size_t sum_of_reclaimable_bytes = 0; while (index < _front) { @@ -108,19 +106,19 @@ guarantee(curr != NULL, "Regions in _regions array cannot be NULL"); guarantee(!curr->is_young(), "should not be young!"); guarantee(!curr->is_pinned(), - err_msg("Pinned region should not be in collection set (index %u)", curr->hrm_index())); + "Pinned region should not be in collection set (index %u)", curr->hrm_index()); if (prev != NULL) { guarantee(order_regions(prev, curr) != 1, - err_msg("GC eff prev: %1.4f GC eff curr: %1.4f", - prev->gc_efficiency(), curr->gc_efficiency())); + "GC eff prev: %1.4f GC eff curr: %1.4f", + prev->gc_efficiency(), curr->gc_efficiency()); } sum_of_reclaimable_bytes += curr->reclaimable_bytes(); prev = curr; } guarantee(sum_of_reclaimable_bytes == _remaining_reclaimable_bytes, - err_msg("reclaimable bytes inconsistent, " - "remaining: " SIZE_FORMAT " sum: " SIZE_FORMAT, - _remaining_reclaimable_bytes, sum_of_reclaimable_bytes)); + "reclaimable bytes inconsistent, " + "remaining: " SIZE_FORMAT " sum: " SIZE_FORMAT, + _remaining_reclaimable_bytes, sum_of_reclaimable_bytes); } #endif // !PRODUCT @@ -151,7 +149,7 @@ void CollectionSetChooser::add_region(HeapRegion* hr) { assert(!hr->is_pinned(), - err_msg("Pinned region shouldn't be added to the collection set (index %u)", hr->hrm_index())); + "Pinned region shouldn't be added to the collection set (index %u)", hr->hrm_index()); assert(!hr->is_young(), "should not be young!"); _regions.append(hr); _end++; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp --- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -73,9 +73,7 @@ HeapRegion* res = NULL; if (_front < _end) { res = regions_at(_front); - assert(res != NULL, - err_msg("Unexpected NULL hr in _regions at index %u", - _front)); + assert(res != NULL, "Unexpected NULL hr in _regions at index %u", _front); } return res; } @@ -88,9 +86,9 @@ assert(_front < _end, "pre-condition"); regions_at_put(_front, NULL); assert(hr->reclaimable_bytes() <= _remaining_reclaimable_bytes, - err_msg("remaining reclaimable bytes inconsistent " - "from region: " SIZE_FORMAT " remaining: " SIZE_FORMAT, - hr->reclaimable_bytes(), _remaining_reclaimable_bytes)); + "remaining reclaimable bytes inconsistent " + "from region: " SIZE_FORMAT " remaining: " SIZE_FORMAT, + hr->reclaimable_bytes(), _remaining_reclaimable_bytes); _remaining_reclaimable_bytes -= hr->reclaimable_bytes(); _front += 1; return hr; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/concurrentMark.cpp --- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,6 +41,7 @@ #include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionSet.inline.hpp" #include "gc/g1/suspendibleThreadSet.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.hpp" @@ -245,10 +246,6 @@ CMMarkStack::CMMarkStack(ConcurrentMark* cm) : _base(NULL), _cm(cm) -#ifdef ASSERT - , _drain_in_progress(false) - , _drain_in_progress_yields(false) -#endif {} bool CMMarkStack::allocate(size_t capacity) { @@ -362,30 +359,6 @@ } } -template -bool CMMarkStack::drain(OopClosureClass* cl, CMBitMap* bm, bool yield_after) { - assert(!_drain_in_progress || !_drain_in_progress_yields || yield_after - || SafepointSynchronize::is_at_safepoint(), - "Drain recursion must be yield-safe."); - bool res = true; - debug_only(_drain_in_progress = true); - debug_only(_drain_in_progress_yields = yield_after); - while (!isEmpty()) { - oop newOop = pop(); - assert(G1CollectedHeap::heap()->is_in_reserved(newOop), "Bad pop"); - assert(newOop->is_oop(), "Expected an oop"); - assert(bm == NULL || bm->isMarked((HeapWord*)newOop), - "only grey objects on this stack"); - newOop->oop_iterate(cl); - if (yield_after && _cm->do_yield_check()) { - res = false; - break; - } - } - debug_only(_drain_in_progress = false); - return res; -} - void CMMarkStack::note_start_of_gc() { assert(_saved_index == -1, "note_start_of_gc()/end_of_gc() bracketed incorrectly"); @@ -399,7 +372,7 @@ // only check this once per GC anyway, so it won't be a performance // issue in any way. guarantee(_saved_index == _index, - err_msg("saved index: %d index: %d", _saved_index, _index)); + "saved index: %d index: %d", _saved_index, _index); _saved_index = -1; } @@ -520,7 +493,6 @@ _has_overflown(false), _concurrent(false), _has_aborted(false), - _aborted_gc_id(GCId::undefined()), _restart_for_overflow(false), _concurrent_marking_in_progress(false), @@ -794,8 +766,8 @@ // in a STW phase. assert(!concurrent_marking_in_progress(), "invariant"); assert(out_of_regions(), - err_msg("only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT, - p2i(_finger), p2i(_heap_end))); + "only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT, + p2i(_finger), p2i(_heap_end)); } } @@ -991,7 +963,7 @@ force_overflow()->update(); if (G1Log::fine()) { - gclog_or_tty->gclog_stamp(concurrent_gc_id()); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print_cr("[GC concurrent-mark-reset-for-overflow]"); } } @@ -1181,7 +1153,7 @@ // should not attempt to do any further work. if (root_regions()->scan_in_progress()) { if (G1Log::fine()) { - gclog_or_tty->gclog_stamp(concurrent_gc_id()); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print_cr("[GC concurrent-root-region-scan-start]"); } @@ -1195,7 +1167,7 @@ _parallel_workers->run_task(&task); if (G1Log::fine()) { - gclog_or_tty->gclog_stamp(concurrent_gc_id()); + gclog_or_tty->gclog_stamp(); gclog_or_tty->print_cr("[GC concurrent-root-region-scan-end, %1.7lf secs]", os::elapsedTime() - scan_start); } @@ -1235,7 +1207,8 @@ } // Helper class to get rid of some boilerplate code. -class G1CMTraceTime : public GCTraceTime { +class G1CMTraceTime : public StackObj { + GCTraceTimeImpl _gc_trace_time; static bool doit_and_prepend(bool doit) { if (doit) { gclog_or_tty->put(' '); @@ -1245,8 +1218,7 @@ public: G1CMTraceTime(const char* title, bool doit) - : GCTraceTime(title, doit_and_prepend(doit), false, G1CollectedHeap::heap()->gc_timer_cm(), - G1CollectedHeap::heap()->concurrent_mark()->concurrent_gc_id()) { + : _gc_trace_time(title, doit_and_prepend(doit), false, G1CollectedHeap::heap()->gc_timer_cm()) { } }; @@ -1415,9 +1387,9 @@ HeapWord* start = hr->bottom(); assert(start <= hr->end() && start <= ntams && ntams <= hr->end(), - err_msg("Preconditions not met - " - "start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT, - p2i(start), p2i(ntams), p2i(hr->end()))); + "Preconditions not met - " + "start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT, + p2i(start), p2i(ntams), p2i(hr->end())); // Find the first marked object at or after "start". start = _bm->getNextMarkedWordAddress(start, ntams); @@ -1717,11 +1689,11 @@ } assert(end_idx <= _card_bm->size(), - err_msg("oob: end_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, - end_idx, _card_bm->size())); + "oob: end_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, + end_idx, _card_bm->size()); assert(start_idx < _card_bm->size(), - err_msg("oob: start_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, - start_idx, _card_bm->size())); + "oob: start_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT, + start_idx, _card_bm->size()); _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */); } @@ -2391,8 +2363,7 @@ &g1_keep_alive, &g1_drain_mark_stack, executor, - g1h->gc_timer_cm(), - concurrent_gc_id()); + g1h->gc_timer_cm()); g1h->gc_tracer_cm()->report_gc_reference_stats(stats); // The do_oop work routines of the keep_alive and drain_marking_stack @@ -2471,7 +2442,7 @@ // object; it could instead have been a stale reference. oop obj = static_cast(entry); assert(obj->is_oop(true /* ignore mark word */), - err_msg("Invalid oop in SATB buffer: " PTR_FORMAT, p2i(obj))); + "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(obj)); _task->make_reference_grey(obj, hr); } } @@ -2588,9 +2559,9 @@ SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); guarantee(has_overflown() || satb_mq_set.completed_buffers_num() == 0, - err_msg("Invariant: has_overflown = %s, num buffers = %d", - BOOL_TO_STR(has_overflown()), - satb_mq_set.completed_buffers_num())); + "Invariant: has_overflown = %s, num buffers = %d", + BOOL_TO_STR(has_overflown()), + satb_mq_set.completed_buffers_num()); print_stats(); } @@ -2724,11 +2695,11 @@ void operator()(oop obj) const { guarantee(obj->is_oop(), - err_msg("Non-oop " PTR_FORMAT ", phase: %s, info: %d", - p2i(obj), _phase, _info)); + "Non-oop " PTR_FORMAT ", phase: %s, info: %d", + p2i(obj), _phase, _info); guarantee(!_g1h->obj_in_cs(obj), - err_msg("obj: " PTR_FORMAT " in CSet, phase: %s, info: %d", - p2i(obj), _phase, _info)); + "obj: " PTR_FORMAT " in CSet, phase: %s, info: %d", + p2i(obj), _phase, _info); } }; @@ -2761,8 +2732,8 @@ // here. HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger); guarantee(global_hr == NULL || global_finger == global_hr->bottom(), - err_msg("global finger: " PTR_FORMAT " region: " HR_FORMAT, - p2i(global_finger), HR_FORMAT_PARAMS(global_hr))); + "global finger: " PTR_FORMAT " region: " HR_FORMAT, + p2i(global_finger), HR_FORMAT_PARAMS(global_hr)); } // Verify the task fingers @@ -2775,8 +2746,8 @@ HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger); guarantee(task_hr == NULL || task_finger == task_hr->bottom() || !task_hr->in_collection_set(), - err_msg("task finger: " PTR_FORMAT " region: " HR_FORMAT, - p2i(task_finger), HR_FORMAT_PARAMS(task_hr))); + "task finger: " PTR_FORMAT " region: " HR_FORMAT, + p2i(task_finger), HR_FORMAT_PARAMS(task_hr)); } } } @@ -2816,10 +2787,10 @@ HeapWord* end = hr->end(); assert(start <= limit && limit <= hr->top() && hr->top() <= hr->end(), - err_msg("Preconditions not met - " - "start: " PTR_FORMAT ", limit: " PTR_FORMAT ", " - "top: " PTR_FORMAT ", end: " PTR_FORMAT, - p2i(start), p2i(limit), p2i(hr->top()), p2i(hr->end()))); + "Preconditions not met - " + "start: " PTR_FORMAT ", limit: " PTR_FORMAT ", " + "top: " PTR_FORMAT ", end: " PTR_FORMAT, + p2i(start), p2i(limit), p2i(hr->top()), p2i(hr->end())); assert(hr->next_marked_bytes() == 0, "Precondition"); @@ -2988,8 +2959,6 @@ } _first_overflow_barrier_sync.abort(); _second_overflow_barrier_sync.abort(); - _aborted_gc_id = _g1h->gc_tracer_cm()->gc_id(); - assert(!_aborted_gc_id.is_undefined(), "ConcurrentMark::abort() executed more than once?"); _has_aborted = true; SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); @@ -3004,13 +2973,6 @@ _g1h->register_concurrent_cycle_end(); } -const GCId& ConcurrentMark::concurrent_gc_id() { - if (has_aborted()) { - return _aborted_gc_id; - } - return _g1h->gc_tracer_cm()->gc_id(); -} - static void print_ms_time_info(const char* prefix, const char* name, NumberSeq& ns) { gclog_or_tty->print_cr("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).", diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/concurrentMark.hpp --- a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -28,7 +28,6 @@ #include "classfile/javaClasses.hpp" #include "gc/g1/g1RegionToSpaceMapper.hpp" #include "gc/g1/heapRegionSet.hpp" -#include "gc/shared/gcId.hpp" #include "gc/shared/taskqueue.hpp" class G1CollectedHeap; @@ -183,15 +182,6 @@ bool _overflow; bool _should_expand; - DEBUG_ONLY(bool _drain_in_progress;) - DEBUG_ONLY(bool _drain_in_progress_yields;) - - oop pop() { - if (!isEmpty()) { - return _base[--_index] ; - } - return NULL; - } public: CMMarkStack(ConcurrentMark* cm); @@ -213,17 +203,6 @@ // operations, which use the same locking strategy. bool par_pop_arr(oop* ptr_arr, int max, int* n); - // Drain the mark stack, applying the given closure to all fields of - // objects on the stack. (That is, continue until the stack is empty, - // even if closure applications add entries to the stack.) The "bm" - // argument, if non-null, may be used to verify that only marked objects - // are on the mark stack. If "yield_after" is "true", then the - // concurrent marker performing the drain offers to yield after - // processing each object. If a yield occurs, stops the drain operation - // and returns false. Otherwise, returns true. - template - bool drain(OopClosureClass* cl, CMBitMap* bm, bool yield_after = false); - bool isEmpty() { return _index == 0; } int maxElems() { return _capacity; } @@ -425,7 +404,6 @@ volatile bool _concurrent; // Set at the end of a Full GC so that marking aborts volatile bool _has_aborted; - GCId _aborted_gc_id; // Used when remark aborts due to an overflow to indicate that // another concurrent marking phase should start @@ -768,8 +746,6 @@ bool has_aborted() { return _has_aborted; } - const GCId& concurrent_gc_id(); - // This prints the global/local fingers. It is used for debugging. NOT_PRODUCT(void print_finger();) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp --- a/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -197,9 +197,9 @@ assert(_bmStartWord <= (addr) && (addr) < (_bmStartWord + _bmWordSize), \ "outside underlying space?"); \ assert(G1CollectedHeap::heap()->is_in_exact(addr), \ - err_msg("Trying to access not available bitmap " PTR_FORMAT \ - " corresponding to " PTR_FORMAT " (%u)", \ - p2i(this), p2i(addr), G1CollectedHeap::heap()->addr_to_region(addr))); + "Trying to access not available bitmap " PTR_FORMAT \ + " corresponding to " PTR_FORMAT " (%u)", \ + p2i(this), p2i(addr), G1CollectedHeap::heap()->addr_to_region(addr)); inline void CMBitMap::mark(HeapWord* addr) { check_mark(addr); @@ -225,8 +225,7 @@ template inline void CMMarkStack::iterate(Fn fn) { - assert(_saved_index == _index, - err_msg("saved index: %d index: %d", _saved_index, _index)); + assert(_saved_index == _index, "saved index: %d index: %d", _saved_index, _index); for (int i = 0; i < _index; ++i) { fn(_base[i]); } @@ -385,7 +384,7 @@ increment_refs_reached(); HeapWord* objAddr = (HeapWord*) obj; - assert(obj->is_oop_or_null(true /* ignore mark word */), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(obj))); + assert(obj->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj)); if (_g1h->is_in_g1_reserved(objAddr)) { assert(obj != NULL, "null check is implicit"); if (!_nextMarkBitMap->isMarked(objAddr)) { @@ -427,9 +426,9 @@ // assert that word_size is under an upper bound which is its // containing region's capacity. assert(word_size * HeapWordSize <= hr->capacity(), - err_msg("size: " SIZE_FORMAT " capacity: " SIZE_FORMAT " " HR_FORMAT, - word_size * HeapWordSize, hr->capacity(), - HR_FORMAT_PARAMS(hr))); + "size: " SIZE_FORMAT " capacity: " SIZE_FORMAT " " HR_FORMAT, + word_size * HeapWordSize, hr->capacity(), + HR_FORMAT_PARAMS(hr)); if (addr < hr->next_top_at_mark_start()) { if (!_nextMarkBitMap->isMarked(addr)) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp --- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,6 +30,7 @@ #include "gc/g1/g1MMUTracker.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/vm_operations_g1.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcTrace.hpp" #include "memory/resourceArea.hpp" #include "runtime/vmThread.hpp" @@ -85,7 +86,7 @@ SuspendibleThreadSetJoiner sts_joiner(join_sts); va_list args; va_start(args, fmt); - gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id()); + gclog_or_tty->gclog_stamp(); gclog_or_tty->vprint_cr(fmt, args); va_end(args); } @@ -108,6 +109,7 @@ break; } + assert(GCId::current() != GCId::undefined(), "GC id should have been set up by the initial mark GC."); { ResourceMark rm; HandleMark hm; @@ -194,7 +196,7 @@ // reclaimed by cleanup. double cleanup_start_sec = os::elapsedTime(); - cm_log(G1Log::fine(), true, "[GC concurrent-cleanup-start]"); + cm_log(G1Log::fine(), false, "[GC concurrent-cleanup-start]"); // Now do the concurrent cleanup operation. _cm->completeCleanup(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -91,7 +91,7 @@ } size_t G1AllocRegion::retire(bool fill_up) { - assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly")); + assert_alloc_region(_alloc_region != NULL, "not initialized properly"); size_t result = 0; @@ -101,15 +101,14 @@ // We never have to check whether the active region is empty or not, // and potentially free it if it is, given that it's guaranteed that // it will never be empty. - assert(!alloc_region->is_empty(), - ar_ext_msg(this, "the alloc region should never be empty")); + assert_alloc_region(!alloc_region->is_empty(), + "the alloc region should never be empty"); if (fill_up) { result = fill_up_remaining_space(alloc_region, _bot_updates); } - assert(alloc_region->used() >= _used_bytes_before, - ar_ext_msg(this, "invariant")); + assert_alloc_region(alloc_region->used() >= _used_bytes_before, "invariant"); size_t allocated_bytes = alloc_region->used() - _used_bytes_before; retire_region(alloc_region, allocated_bytes); _used_bytes_before = 0; @@ -122,8 +121,8 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, bool force) { - assert(_alloc_region == _dummy_region, ar_ext_msg(this, "pre-condition")); - assert(_used_bytes_before == 0, ar_ext_msg(this, "pre-condition")); + assert_alloc_region(_alloc_region == _dummy_region, "pre-condition"); + assert_alloc_region(_used_bytes_before == 0, "pre-condition"); trace("attempting region allocation"); HeapRegion* new_alloc_region = allocate_new_region(word_size, force); @@ -132,7 +131,7 @@ // Need to do this before the allocation _used_bytes_before = new_alloc_region->used(); HeapWord* result = allocate(new_alloc_region, word_size, _bot_updates); - assert(result != NULL, ar_ext_msg(this, "the allocation should succeeded")); + assert_alloc_region(result != NULL, "the allocation should succeeded"); OrderAccess::storestore(); // Note that we first perform the allocation and then we store the @@ -148,17 +147,10 @@ ShouldNotReachHere(); } -void G1AllocRegion::fill_in_ext_msg(ar_ext_msg* msg, const char* message) { - msg->append("[%s] %s c: %u b: %s r: " PTR_FORMAT " u: " SIZE_FORMAT, - _name, message, _count, BOOL_TO_STR(_bot_updates), - p2i(_alloc_region), _used_bytes_before); -} - void G1AllocRegion::init() { trace("initializing"); - assert(_alloc_region == NULL && _used_bytes_before == 0, - ar_ext_msg(this, "pre-condition")); - assert(_dummy_region != NULL, ar_ext_msg(this, "should have been set")); + assert_alloc_region(_alloc_region == NULL && _used_bytes_before == 0, "pre-condition"); + assert_alloc_region(_dummy_region != NULL, "should have been set"); _alloc_region = _dummy_region; _count = 0; trace("initialized"); @@ -168,11 +160,10 @@ trace("setting"); // We explicitly check that the region is not empty to make sure we // maintain the "the alloc region cannot be empty" invariant. - assert(alloc_region != NULL && !alloc_region->is_empty(), - ar_ext_msg(this, "pre-condition")); - assert(_alloc_region == _dummy_region && - _used_bytes_before == 0 && _count == 0, - ar_ext_msg(this, "pre-condition")); + assert_alloc_region(alloc_region != NULL && !alloc_region->is_empty(), "pre-condition"); + assert_alloc_region(_alloc_region == _dummy_region && + _used_bytes_before == 0 && _count == 0, + "pre-condition"); _used_bytes_before = alloc_region->used(); _alloc_region = alloc_region; @@ -184,8 +175,7 @@ trace("update"); // We explicitly check that the region is not empty to make sure we // maintain the "the alloc region cannot be empty" invariant. - assert(alloc_region != NULL && !alloc_region->is_empty(), - ar_ext_msg(this, "pre-condition")); + assert_alloc_region(alloc_region != NULL && !alloc_region->is_empty(), "pre-condition"); _alloc_region = alloc_region; _alloc_region->set_allocation_context(allocation_context()); @@ -197,8 +187,7 @@ trace("releasing"); HeapRegion* alloc_region = _alloc_region; retire(false /* fill_up */); - assert(_alloc_region == _dummy_region, - ar_ext_msg(this, "post-condition of retire()")); + assert_alloc_region(_alloc_region == _dummy_region, "post-condition of retire()"); _alloc_region = NULL; trace("released"); return (alloc_region == _dummy_region) ? NULL : alloc_region; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -34,8 +34,6 @@ // 0 -> no tracing, 1 -> basic tracing, 2 -> basic + allocation tracing #define G1_ALLOC_REGION_TRACING 0 -class ar_ext_msg; - // A class that holds a region that is active in satisfying allocation // requests, potentially issued in parallel. When the active region is // full it will be retired and replaced with a new one. The @@ -44,7 +42,6 @@ // replaced. class G1AllocRegion VALUE_OBJ_CLASS_SPEC { - friend class ar_ext_msg; private: // The active allocating region we are currently allocating out @@ -131,8 +128,6 @@ // to allocate a new region even if the max has been reached. HeapWord* new_alloc_region_and_allocate(size_t word_size, bool force); - void fill_in_ext_msg(ar_ext_msg* msg, const char* message); - protected: // Retire the active allocating region. If fill_up is true then make // sure that the region is full before we retire it so that no one @@ -278,11 +273,4 @@ virtual HeapRegion* release(); }; -class ar_ext_msg : public err_msg { -public: - ar_ext_msg(G1AllocRegion* alloc_region, const char *message) : err_msg("%s", "") { - alloc_region->fill_in_ext_msg(this, message); - } -}; - #endif // SHARE_VM_GC_G1_G1ALLOCREGION_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1AllocRegion.inline.hpp --- a/hotspot/src/share/vm/gc/g1/g1AllocRegion.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1AllocRegion.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -28,10 +28,18 @@ #include "gc/g1/g1AllocRegion.hpp" #include "gc/g1/heapRegion.inline.hpp" +#define assert_alloc_region(p, message) \ + do { \ + assert((p), "[%s] %s c: %u b: %s r: " PTR_FORMAT " u: " SIZE_FORMAT, \ + _name, (message), _count, BOOL_TO_STR(_bot_updates), \ + p2i(_alloc_region), _used_bytes_before); \ + } while (0) + + inline HeapWord* G1AllocRegion::allocate(HeapRegion* alloc_region, size_t word_size, bool bot_updates) { - assert(alloc_region != NULL, err_msg("pre-condition")); + assert(alloc_region != NULL, "pre-condition"); if (!bot_updates) { return alloc_region->allocate_no_bot_updates(word_size); @@ -50,8 +58,8 @@ size_t desired_word_size, size_t* actual_word_size, bool bot_updates) { - assert(alloc_region != NULL, err_msg("pre-condition")); - assert(!alloc_region->is_empty(), err_msg("pre-condition")); + assert(alloc_region != NULL, "pre-condition"); + assert(!alloc_region->is_empty(), "pre-condition"); if (!bot_updates) { return alloc_region->par_allocate_no_bot_updates(min_word_size, desired_word_size, actual_word_size); @@ -69,10 +77,10 @@ size_t desired_word_size, size_t* actual_word_size, bool bot_updates) { - assert(bot_updates == _bot_updates, ar_ext_msg(this, "pre-condition")); + assert_alloc_region(bot_updates == _bot_updates, "pre-condition"); HeapRegion* alloc_region = _alloc_region; - assert(alloc_region != NULL, ar_ext_msg(this, "not initialized properly")); + assert_alloc_region(alloc_region != NULL, "not initialized properly"); HeapWord* result = par_allocate(alloc_region, min_word_size, desired_word_size, actual_word_size, bot_updates); if (result != NULL) { @@ -113,8 +121,8 @@ inline HeapWord* G1AllocRegion::attempt_allocation_force(size_t word_size, bool bot_updates) { - assert(bot_updates == _bot_updates, ar_ext_msg(this, "pre-condition")); - assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly")); + assert_alloc_region(bot_updates == _bot_updates, "pre-condition"); + assert_alloc_region(_alloc_region != NULL, "not initialized properly"); trace("forcing alloc", word_size, word_size); HeapWord* result = new_alloc_region_and_allocate(word_size, true /* force */); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1Allocator.cpp --- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -54,7 +54,7 @@ HeapRegion* retained_region = *retained_old; *retained_old = NULL; assert(retained_region == NULL || !retained_region->is_archive(), - err_msg("Archive region should not be alloc region (index %u)", retained_region->hrm_index())); + "Archive region should not be alloc region (index %u)", retained_region->hrm_index()); // We will discard the current GC alloc region if: // a) it's in the collection set (it can happen!), @@ -147,8 +147,8 @@ size_t temp = 0; HeapWord* result = par_allocate_during_gc(dest, word_size, word_size, &temp, context); assert(result == NULL || temp == word_size, - err_msg("Requested " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT, - word_size, temp, p2i(result))); + "Requested " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT, + word_size, temp, p2i(result)); return result; } @@ -276,16 +276,16 @@ context); assert(buf == NULL || ((actual_plab_size >= required_in_plab) && (actual_plab_size <= plab_word_size)), - err_msg("Requested at minimum " SIZE_FORMAT ", desired " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT, - required_in_plab, plab_word_size, actual_plab_size, p2i(buf))); + "Requested at minimum " SIZE_FORMAT ", desired " SIZE_FORMAT " words, but got " SIZE_FORMAT " at " PTR_FORMAT, + required_in_plab, plab_word_size, actual_plab_size, p2i(buf)); if (buf != NULL) { alloc_buf->set_buf(buf, actual_plab_size); HeapWord* const obj = alloc_buf->allocate(word_sz); - assert(obj != NULL, err_msg("PLAB should have been big enough, tried to allocate " - SIZE_FORMAT " requiring " SIZE_FORMAT " PLAB size " SIZE_FORMAT, - word_sz, required_in_plab, plab_word_size)); + assert(obj != NULL, "PLAB should have been big enough, tried to allocate " + SIZE_FORMAT " requiring " SIZE_FORMAT " PLAB size " SIZE_FORMAT, + word_sz, required_in_plab, plab_word_size); return obj; } // Otherwise. @@ -354,7 +354,7 @@ if (hr == NULL) { return false; } - assert(hr->is_empty(), err_msg("expected empty region (index %u)", hr->hrm_index())); + assert(hr->is_empty(), "expected empty region (index %u)", hr->hrm_index()); hr->set_archive(); _g1h->old_set_add(hr); _g1h->hr_printer()->alloc(hr, G1HRPrinter::Archive); @@ -383,15 +383,15 @@ } HeapWord* old_top = _allocation_region->top(); assert(_bottom >= _allocation_region->bottom(), - err_msg("inconsistent allocation state: " PTR_FORMAT " < " PTR_FORMAT, - p2i(_bottom), p2i(_allocation_region->bottom()))); + "inconsistent allocation state: " PTR_FORMAT " < " PTR_FORMAT, + p2i(_bottom), p2i(_allocation_region->bottom())); assert(_max <= _allocation_region->end(), - err_msg("inconsistent allocation state: " PTR_FORMAT " > " PTR_FORMAT, - p2i(_max), p2i(_allocation_region->end()))); + "inconsistent allocation state: " PTR_FORMAT " > " PTR_FORMAT, + p2i(_max), p2i(_allocation_region->end())); assert(_bottom <= old_top && old_top <= _max, - err_msg("inconsistent allocation state: expected " - PTR_FORMAT " <= " PTR_FORMAT " <= " PTR_FORMAT, - p2i(_bottom), p2i(old_top), p2i(_max))); + "inconsistent allocation state: expected " + PTR_FORMAT " <= " PTR_FORMAT " <= " PTR_FORMAT, + p2i(_bottom), p2i(old_top), p2i(_max)); // Allocate the next word_size words in the current allocation chunk. // If allocation would cross the _max boundary, insert a filler and begin @@ -430,9 +430,9 @@ void G1ArchiveAllocator::complete_archive(GrowableArray* ranges, size_t end_alignment_in_bytes) { assert((end_alignment_in_bytes >> LogHeapWordSize) < HeapRegion::min_region_size_in_words(), - err_msg("alignment " SIZE_FORMAT " too large", end_alignment_in_bytes)); + "alignment " SIZE_FORMAT " too large", end_alignment_in_bytes); assert(is_size_aligned(end_alignment_in_bytes, HeapWordSize), - err_msg("alignment " SIZE_FORMAT " is not HeapWord (%u) aligned", end_alignment_in_bytes, HeapWordSize)); + "alignment " SIZE_FORMAT " is not HeapWord (%u) aligned", end_alignment_in_bytes, HeapWordSize); // If we've allocated nothing, simply return. if (_allocation_region == NULL) { @@ -465,8 +465,8 @@ // MemRegions to the GrowableArray provided by the caller. int index = _allocated_regions.length() - 1; assert(_allocated_regions.at(index) == _allocation_region, - err_msg("expected region %u at end of array, found %u", - _allocation_region->hrm_index(), _allocated_regions.at(index)->hrm_index())); + "expected region %u at end of array, found %u", + _allocation_region->hrm_index(), _allocated_regions.at(index)->hrm_index()); HeapWord* base_address = _allocation_region->bottom(); HeapWord* top = base_address; @@ -482,7 +482,7 @@ index = index - 1; } - assert(top != base_address, err_msg("zero-sized range, address " PTR_FORMAT, p2i(base_address))); + assert(top != base_address, "zero-sized range, address " PTR_FORMAT, p2i(base_address)); ranges->append(MemRegion(base_address, pointer_delta(top, base_address))); _allocated_regions.clear(); _allocation_region = NULL; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1Allocator.hpp --- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -295,9 +295,9 @@ virtual G1PLAB* alloc_buffer(InCSetState dest, AllocationContext_t context) { assert(dest.is_valid(), - err_msg("Allocation buffer index out-of-bounds: " CSETSTATE_FORMAT, dest.value())); + "Allocation buffer index out-of-bounds: " CSETSTATE_FORMAT, dest.value()); assert(_alloc_buffers[dest.value()] != NULL, - err_msg("Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value())); + "Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value()); return _alloc_buffers[dest.value()]; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp --- a/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1Allocator.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,7 +36,7 @@ HeapWord* G1Allocator::attempt_allocation_locked(size_t word_size, AllocationContext_t context) { HeapWord* result = mutator_alloc_region(context)->attempt_allocation_locked(word_size, false /* bot_updates */); assert(result != NULL || mutator_alloc_region(context)->get() == NULL, - err_msg("Must not have a mutator alloc region if there is no memory, but is " PTR_FORMAT, p2i(mutator_alloc_region(context)->get()))); + "Must not have a mutator alloc region if there is no memory, but is " PTR_FORMAT, p2i(mutator_alloc_region(context)->get())); return result; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1BiasedArray.cpp --- a/hotspot/src/share/vm/gc/g1/g1BiasedArray.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1BiasedArray.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,19 +36,21 @@ #ifndef PRODUCT void G1BiasedMappedArrayBase::verify_index(idx_t index) const { guarantee(_base != NULL, "Array not initialized"); - guarantee(index < length(), err_msg("Index out of bounds index: " SIZE_FORMAT " length: " SIZE_FORMAT, index, length())); + guarantee(index < length(), "Index out of bounds index: " SIZE_FORMAT " length: " SIZE_FORMAT, index, length()); } void G1BiasedMappedArrayBase::verify_biased_index(idx_t biased_index) const { guarantee(_biased_base != NULL, "Array not initialized"); guarantee(biased_index >= bias() && biased_index < (bias() + length()), - err_msg("Biased index out of bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, biased_index, bias(), length())); + "Biased index out of bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, + biased_index, bias(), length()); } void G1BiasedMappedArrayBase::verify_biased_index_inclusive_end(idx_t biased_index) const { guarantee(_biased_base != NULL, "Array not initialized"); guarantee(biased_index >= bias() && biased_index <= (bias() + length()), - err_msg("Biased index out of inclusive bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, biased_index, bias(), length())); + "Biased index out of inclusive bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, + biased_index, bias(), length()); } class TestMappedArray : public G1BiasedMappedArray { @@ -65,7 +67,7 @@ REGION_SIZE_IN_WORDS * HeapWordSize); // Check address calculation (bounds) assert(array.bottom_address_mapped() == fake_heap, - err_msg("bottom mapped address should be " PTR_FORMAT ", but is " PTR_FORMAT, p2i(fake_heap), p2i(array.bottom_address_mapped()))); + "bottom mapped address should be " PTR_FORMAT ", but is " PTR_FORMAT, p2i(fake_heap), p2i(array.bottom_address_mapped())); assert(array.end_address_mapped() == (fake_heap + REGION_SIZE_IN_WORDS * NUM_REGIONS), "must be"); int* bottom = array.address_mapped_to(fake_heap); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp --- a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -56,7 +56,7 @@ void initialize_base(address base, size_t length, size_t bias, size_t elem_size, uint shift_by) { assert(base != NULL, "just checking"); assert(length > 0, "just checking"); - assert(shift_by < sizeof(uintptr_t) * 8, err_msg("Shifting by %u, larger than word size?", shift_by)); + assert(shift_by < sizeof(uintptr_t) * 8, "Shifting by %u, larger than word size?", shift_by); _base = base; _length = length; _biased_base = base - (bias * elem_size); @@ -69,13 +69,13 @@ void initialize(HeapWord* bottom, HeapWord* end, size_t target_elem_size_in_bytes, size_t mapping_granularity_in_bytes) { assert(mapping_granularity_in_bytes > 0, "just checking"); assert(is_power_of_2(mapping_granularity_in_bytes), - err_msg("mapping granularity must be power of 2, is %zd", mapping_granularity_in_bytes)); + "mapping granularity must be power of 2, is %zd", mapping_granularity_in_bytes); assert((uintptr_t)bottom % mapping_granularity_in_bytes == 0, - err_msg("bottom mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, - mapping_granularity_in_bytes, p2i(bottom))); + "bottom mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + mapping_granularity_in_bytes, p2i(bottom)); assert((uintptr_t)end % mapping_granularity_in_bytes == 0, - err_msg("end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, - mapping_granularity_in_bytes, p2i(end))); + "end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + mapping_granularity_in_bytes, p2i(end)); size_t num_target_elems = pointer_delta(end, bottom, mapping_granularity_in_bytes); idx_t bias = (uintptr_t)bottom / mapping_granularity_in_bytes; address base = create_new_base_array(num_target_elems, target_elem_size_in_bytes); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp --- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -69,14 +69,14 @@ #ifdef ASSERT void G1BlockOffsetSharedArray::check_index(size_t index, const char* msg) const { assert((index) < (_reserved.word_size() >> LogN_words), - err_msg("%s - index: " SIZE_FORMAT ", _vs.committed_size: " SIZE_FORMAT, - msg, (index), (_reserved.word_size() >> LogN_words))); + "%s - index: " SIZE_FORMAT ", _vs.committed_size: " SIZE_FORMAT, + msg, (index), (_reserved.word_size() >> LogN_words)); assert(G1CollectedHeap::heap()->is_in_exact(address_for_index_raw(index)), - err_msg("Index " SIZE_FORMAT " corresponding to " PTR_FORMAT - " (%u) is not in committed area.", - (index), - p2i(address_for_index_raw(index)), - G1CollectedHeap::heap()->addr_to_region(address_for_index_raw(index)))); + "Index " SIZE_FORMAT " corresponding to " PTR_FORMAT + " (%u) is not in committed area.", + (index), + p2i(address_for_index_raw(index)), + G1CollectedHeap::heap()->addr_to_region(address_for_index_raw(index))); } #endif // ASSERT @@ -192,27 +192,27 @@ u_char entry = _array->offset_array(c); if (c - start_card > BlockOffsetArray::power_to_cards_back(1)) { guarantee(entry > N_words, - err_msg("Should be in logarithmic region - " - "entry: %u, " - "_array->offset_array(c): %u, " - "N_words: %u", - (uint)entry, (uint)_array->offset_array(c), (uint)N_words)); + "Should be in logarithmic region - " + "entry: %u, " + "_array->offset_array(c): %u, " + "N_words: %u", + (uint)entry, (uint)_array->offset_array(c), (uint)N_words); } size_t backskip = BlockOffsetArray::entry_to_cards_back(entry); 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, - err_msg("Monotonicity - landing_card offset: %u, " - "entry: %u", - (uint)_array->offset_array(landing_card), (uint)entry)); + "Monotonicity - landing_card offset: %u, " + "entry: %u", + (uint)_array->offset_array(landing_card), (uint)entry); } else { guarantee(landing_card == start_card - 1, "Tautology"); // Note that N_words is the maximum offset value guarantee(_array->offset_array(landing_card) <= N_words, - err_msg("landing card offset: %u, " - "N_words: %u", - (uint)_array->offset_array(landing_card), (uint)N_words)); + "landing card offset: %u, " + "N_words: %u", + (uint)_array->offset_array(landing_card), (uint)N_words); } } } @@ -271,9 +271,9 @@ HeapWord* next_boundary = _array->address_for_index(n_index) + (n_index == next_index ? 0 : N_words); assert(next_boundary <= _array->_end, - err_msg("next_boundary is beyond the end of the covered region " - " next_boundary " PTR_FORMAT " _array->_end " PTR_FORMAT, - p2i(next_boundary), p2i(_array->_end))); + "next_boundary is beyond the end of the covered region " + " next_boundary " PTR_FORMAT " _array->_end " PTR_FORMAT, + p2i(next_boundary), p2i(_array->_end)); if (addr >= gsp()->top()) return gsp()->top(); while (next_boundary < addr) { while (n <= next_boundary) { @@ -361,25 +361,23 @@ // is checked by an assertion above. size_t start_index = _array->index_for(blk_start); HeapWord* boundary = _array->address_for_index(start_index); - assert((_array->offset_array(orig_index) == 0 && - blk_start == boundary) || - (_array->offset_array(orig_index) > 0 && - _array->offset_array(orig_index) <= N_words), - err_msg("offset array should have been set - " - "orig_index offset: %u, " - "blk_start: " PTR_FORMAT ", " - "boundary: " PTR_FORMAT, - (uint)_array->offset_array(orig_index), - p2i(blk_start), p2i(boundary))); + assert((_array->offset_array(orig_index) == 0 && blk_start == boundary) || + (_array->offset_array(orig_index) > 0 && _array->offset_array(orig_index) <= N_words), + "offset array should have been set - " + "orig_index offset: %u, " + "blk_start: " PTR_FORMAT ", " + "boundary: " PTR_FORMAT, + (uint)_array->offset_array(orig_index), + p2i(blk_start), p2i(boundary)); for (size_t j = orig_index + 1; j <= end_index; j++) { assert(_array->offset_array(j) > 0 && _array->offset_array(j) <= (u_char) (N_words+BlockOffsetArray::N_powers-1), - err_msg("offset array should have been set - " - "%u not > 0 OR %u not <= %u", - (uint) _array->offset_array(j), - (uint) _array->offset_array(j), - (uint) (N_words+BlockOffsetArray::N_powers-1))); + "offset array should have been set - " + "%u not > 0 OR %u not <= %u", + (uint) _array->offset_array(j), + (uint) _array->offset_array(j), + (uint) (N_words+BlockOffsetArray::N_powers-1)); } #endif } @@ -402,8 +400,8 @@ size_t obj_size = block_size(obj); obj_end = obj + obj_size; guarantee(obj_end > obj && obj_end <= gsp()->top(), - err_msg("Invalid object end. obj: " PTR_FORMAT " obj_size: " SIZE_FORMAT " obj_end: " PTR_FORMAT " top: " PTR_FORMAT, - p2i(obj), obj_size, p2i(obj_end), p2i(gsp()->top()))); + "Invalid object end. obj: " PTR_FORMAT " obj_size: " SIZE_FORMAT " obj_end: " PTR_FORMAT " top: " PTR_FORMAT, + p2i(obj), obj_size, p2i(obj_end), p2i(gsp()->top())); } } else { // Because we refine the BOT based on which cards are dirty there is not much we can verify here. @@ -414,13 +412,13 @@ size_t max_backskip = current_card - start_card; guarantee(backskip <= max_backskip, - err_msg("Going backwards beyond the start_card. start_card: " SIZE_FORMAT " current_card: " SIZE_FORMAT " backskip: " SIZE_FORMAT, - start_card, current_card, backskip)); + "Going backwards beyond the start_card. start_card: " SIZE_FORMAT " current_card: " SIZE_FORMAT " backskip: " SIZE_FORMAT, + start_card, current_card, backskip); HeapWord* backskip_address = _array->address_for_index(current_card - backskip); guarantee(backskip_address >= gsp()->bottom(), - err_msg("Going backwards beyond bottom of the region: bottom: " PTR_FORMAT ", backskip_address: " PTR_FORMAT, - p2i(gsp()->bottom()), p2i(backskip_address))); + "Going backwards beyond bottom of the region: bottom: " PTR_FORMAT ", backskip_address: " PTR_FORMAT, + p2i(gsp()->bottom()), p2i(backskip_address)); } } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp --- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -80,8 +80,8 @@ virtual void set_bottom(HeapWord* new_bottom) { assert(new_bottom <= _end, - err_msg("new_bottom (" PTR_FORMAT ") > _end (" PTR_FORMAT ")", - p2i(new_bottom), p2i(_end))); + "new_bottom (" PTR_FORMAT ") > _end (" PTR_FORMAT ")", + p2i(new_bottom), p2i(_end)); _bottom = new_bottom; resize(pointer_delta(_end, _bottom)); } @@ -149,9 +149,8 @@ void check_offset(size_t offset, const char* msg) const { assert(offset <= N_words, - err_msg("%s - " - "offset: " SIZE_FORMAT ", N_words: %u", - msg, offset, (uint)N_words)); + "%s - offset: " SIZE_FORMAT ", N_words: %u", + msg, offset, (uint)N_words); } // Bounds checking accessors: diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp --- a/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1BlockOffsetTable.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -81,8 +81,8 @@ char* pc = (char*)p; assert(pc >= (char*)_reserved.start() && pc < (char*)_reserved.end(), - err_msg("p (" PTR_FORMAT ") not in reserved [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(_reserved.start()), p2i(_reserved.end()))); + "p (" PTR_FORMAT ") not in reserved [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(_reserved.start()), p2i(_reserved.end())); size_t result = index_for_raw(p); check_index(result, "bad index from address"); return result; @@ -93,10 +93,9 @@ check_index(index, "index out of range"); HeapWord* result = address_for_index_raw(index); assert(result >= _reserved.start() && result < _reserved.end(), - err_msg("bad address from index result " PTR_FORMAT - " _reserved.start() " PTR_FORMAT " _reserved.end() " - PTR_FORMAT, - p2i(result), p2i(_reserved.start()), p2i(_reserved.end()))); + "bad address from index result " PTR_FORMAT + " _reserved.start() " PTR_FORMAT " _reserved.end() " PTR_FORMAT, + p2i(result), p2i(_reserved.start()), p2i(_reserved.end())); return result; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1CardCounts.cpp --- a/hotspot/src/share/vm/gc/g1/g1CardCounts.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CardCounts.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -53,8 +53,8 @@ void G1CardCounts::clear_range(size_t from_card_num, size_t to_card_num) { if (has_count_table()) { assert(from_card_num < to_card_num, - err_msg("Wrong order? from: " SIZE_FORMAT ", to: " SIZE_FORMAT, - from_card_num, to_card_num)); + "Wrong order? from: " SIZE_FORMAT ", to: " SIZE_FORMAT, + from_card_num, to_card_num); Copy::fill_to_bytes(&_card_counts[from_card_num], (to_card_num - from_card_num)); } } @@ -96,8 +96,8 @@ if (has_count_table()) { size_t card_num = ptr_2_card_num(card_ptr); assert(card_num < _reserved_max_card_num, - err_msg("Card " SIZE_FORMAT " outside of card counts table (max size " SIZE_FORMAT ")", - card_num, _reserved_max_card_num)); + "Card " SIZE_FORMAT " outside of card counts table (max size " SIZE_FORMAT ")", + card_num, _reserved_max_card_num); count = (uint) _card_counts[card_num]; if (count < G1ConcRSHotCardLimit) { _card_counts[card_num] = diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1CardCounts.hpp --- a/hotspot/src/share/vm/gc/g1/g1CardCounts.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CardCounts.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -79,19 +79,19 @@ size_t ptr_2_card_num(const jbyte* card_ptr) { assert(card_ptr >= _ct_bot, - err_msg("Invalid card pointer: " - "card_ptr: " PTR_FORMAT ", " - "_ct_bot: " PTR_FORMAT, - p2i(card_ptr), p2i(_ct_bot))); + "Invalid card pointer: " + "card_ptr: " PTR_FORMAT ", " + "_ct_bot: " PTR_FORMAT, + p2i(card_ptr), p2i(_ct_bot)); size_t card_num = pointer_delta(card_ptr, _ct_bot, sizeof(jbyte)); assert(card_num < _reserved_max_card_num, - err_msg("card pointer out of range: " PTR_FORMAT, p2i(card_ptr))); + "card pointer out of range: " PTR_FORMAT, p2i(card_ptr)); return card_num; } jbyte* card_num_2_ptr(size_t card_num) { assert(card_num < _reserved_max_card_num, - err_msg("card num out of range: " SIZE_FORMAT, card_num)); + "card num out of range: " SIZE_FORMAT, card_num); return (jbyte*) (_ct_bot + card_num); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp --- a/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -197,7 +197,9 @@ } void G1CodeRootSet::allocate_small_table() { - _table = new CodeRootSetTable(SmallSize); + CodeRootSetTable* temp = new CodeRootSetTable(SmallSize); + + OrderAccess::release_store_ptr(&_table, temp); } void CodeRootSetTable::purge_list_append(CodeRootSetTable* table) { @@ -350,11 +352,11 @@ assert(set1.is_empty(), "Code root set must be initially empty but is not."); assert(G1CodeRootSet::static_mem_size() == sizeof(void*), - err_msg("The code root set's static memory usage is incorrect, " SIZE_FORMAT " bytes", G1CodeRootSet::static_mem_size())); + "The code root set's static memory usage is incorrect, " SIZE_FORMAT " bytes", G1CodeRootSet::static_mem_size()); set1.add((nmethod*)1); - assert(set1.length() == 1, err_msg("Added exactly one element, but set contains " - SIZE_FORMAT " elements", set1.length())); + assert(set1.length() == 1, "Added exactly one element, but set contains " + SIZE_FORMAT " elements", set1.length()); const size_t num_to_add = (size_t)G1CodeRootSet::Threshold + 1; @@ -362,16 +364,16 @@ set1.add((nmethod*)1); } assert(set1.length() == 1, - err_msg("Duplicate detection should not have increased the set size but " - "is " SIZE_FORMAT, set1.length())); + "Duplicate detection should not have increased the set size but " + "is " SIZE_FORMAT, set1.length()); for (size_t i = 2; i <= num_to_add; i++) { set1.add((nmethod*)(uintptr_t)(i)); } assert(set1.length() == num_to_add, - err_msg("After adding in total " SIZE_FORMAT " distinct code roots, they " - "need to be in the set, but there are only " SIZE_FORMAT, - num_to_add, set1.length())); + "After adding in total " SIZE_FORMAT " distinct code roots, they " + "need to be in the set, but there are only " SIZE_FORMAT, + num_to_add, set1.length()); assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable"); @@ -385,8 +387,8 @@ } } assert(num_popped == num_to_add, - err_msg("Managed to pop " SIZE_FORMAT " code roots, but only " SIZE_FORMAT " " - "were added", num_popped, num_to_add)); + "Managed to pop " SIZE_FORMAT " code roots, but only " SIZE_FORMAT " " + "were added", num_popped, num_to_add); assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable"); G1CodeRootSet::purge(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -53,6 +53,7 @@ #include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/vm_operations_g1.hpp" #include "gc/shared/gcHeapSummary.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" @@ -971,11 +972,11 @@ size_t commits = 0; guarantee(reserved.contains(start_address) && reserved.contains(last_address), - err_msg("MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", - p2i(start_address), p2i(last_address))); + "MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", + p2i(start_address), p2i(last_address)); guarantee(start_address > prev_last_addr, - err_msg("Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , - p2i(start_address), p2i(prev_last_addr))); + "Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , + p2i(start_address), p2i(prev_last_addr)); prev_last_addr = last_address; // Check for ranges that start in the same G1 region in which the previous @@ -1017,7 +1018,7 @@ while (curr_region != NULL) { assert(curr_region->is_empty() && !curr_region->is_pinned(), - err_msg("Region already in use (index %u)", curr_region->hrm_index())); + "Region already in use (index %u)", curr_region->hrm_index()); _hr_printer.alloc(curr_region, G1HRPrinter::Archive); curr_region->set_allocation_context(AllocationContext::system()); curr_region->set_archive(); @@ -1055,11 +1056,11 @@ HeapWord* last_address = ranges[i].last(); assert(reserved.contains(start_address) && reserved.contains(last_address), - err_msg("MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", - p2i(start_address), p2i(last_address))); + "MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", + p2i(start_address), p2i(last_address)); assert(start_address > prev_last_addr, - err_msg("Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , - p2i(start_address), p2i(prev_last_addr))); + "Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , + p2i(start_address), p2i(prev_last_addr)); HeapRegion* start_region = _hrm.addr_to_region(start_address); HeapRegion* last_region = _hrm.addr_to_region(last_address); @@ -1076,7 +1077,7 @@ HeapRegion* curr_region = start_region; while (curr_region != NULL) { guarantee(curr_region->is_archive(), - err_msg("Expected archive region at index %u", curr_region->hrm_index())); + "Expected archive region at index %u", curr_region->hrm_index()); if (curr_region != last_region) { curr_region = _hrm.next_region_in_heap(curr_region); } else { @@ -1139,11 +1140,11 @@ HeapWord* last_address = ranges[i].last(); assert(reserved.contains(start_address) && reserved.contains(last_address), - err_msg("MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", - p2i(start_address), p2i(last_address))); + "MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]", + p2i(start_address), p2i(last_address)); assert(start_address > prev_last_addr, - err_msg("Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , - p2i(start_address), p2i(prev_last_addr))); + "Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT , + p2i(start_address), p2i(prev_last_addr)); size_used += ranges[i].byte_size(); prev_last_addr = last_address; @@ -1168,7 +1169,7 @@ HeapRegion* curr_region = start_region; while (curr_region != NULL) { guarantee(curr_region->is_archive(), - err_msg("Expected archive region at index %u", curr_region->hrm_index())); + "Expected archive region at index %u", curr_region->hrm_index()); uint curr_index = curr_region->hrm_index(); _old_set.remove(curr_region); curr_region->set_free(); @@ -1450,6 +1451,7 @@ gc_timer->register_gc_start(); SerialOldTracer* gc_tracer = G1MarkSweep::gc_tracer(); + GCIdMark gc_id_mark; gc_tracer->report_gc_start(gc_cause(), gc_timer->gc_start()); SvcGCMarker sgcm(SvcGCMarker::FULL); @@ -1476,7 +1478,7 @@ TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); { - GCTraceTime t(GCCauseString("Full GC", gc_cause()), G1Log::fine(), true, NULL, gc_tracer->gc_id()); + GCTraceTime t(GCCauseString("Full GC", gc_cause()), G1Log::fine(), true, NULL); TraceCollectorStats tcs(g1mm()->full_collection_counters()); TraceMemoryManagerStats tms(true /* fullGC */, gc_cause()); @@ -1507,7 +1509,9 @@ check_bitmaps("Full GC Start"); pre_full_gc_dump(gc_timer); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif // Disable discovery and empty the discovered lists // for the CM ref processor. @@ -1567,7 +1571,9 @@ // not been removed from the discovered lists. ref_processor_stw()->enqueue_discovered_references(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif MemoryService::track_memory_usage(); @@ -1755,9 +1761,9 @@ // 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)); + "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., @@ -1799,21 +1805,20 @@ } } - -HeapWord* -G1CollectedHeap::satisfy_failed_allocation(size_t word_size, - AllocationContext_t context, - bool* succeeded) { - assert_at_safepoint(true /* should_be_vm_thread */); - - *succeeded = true; +HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size, + AllocationContext_t context, + bool do_gc, + bool clear_all_soft_refs, + bool expect_null_mutator_alloc_region, + bool* gc_succeeded) { + *gc_succeeded = true; // Let's attempt the allocation first. HeapWord* result = attempt_allocation_at_safepoint(word_size, context, - false /* expect_null_mutator_alloc_region */); + expect_null_mutator_alloc_region); if (result != NULL) { - assert(*succeeded, "sanity"); + assert(*gc_succeeded, "sanity"); return result; } @@ -1823,41 +1828,58 @@ // do something smarter than full collection to satisfy a failed alloc.) result = expand_and_allocate(word_size, context); if (result != NULL) { - assert(*succeeded, "sanity"); + assert(*gc_succeeded, "sanity"); return result; } - // Expansion didn't work, we'll try to do a Full GC. - bool gc_succeeded = do_collection(false, /* explicit_gc */ - false, /* clear_all_soft_refs */ - word_size); - if (!gc_succeeded) { - *succeeded = false; - return NULL; - } - - // Retry the allocation - result = attempt_allocation_at_safepoint(word_size, - context, - true /* expect_null_mutator_alloc_region */); - if (result != NULL) { - assert(*succeeded, "sanity"); + if (do_gc) { + // Expansion didn't work, we'll try to do a Full GC. + *gc_succeeded = do_collection(false, /* explicit_gc */ + clear_all_soft_refs, + word_size); + } + + return NULL; +} + +HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size, + AllocationContext_t context, + bool* succeeded) { + assert_at_safepoint(true /* should_be_vm_thread */); + + // Attempts to allocate followed by Full GC. + HeapWord* result = + satisfy_failed_allocation_helper(word_size, + context, + true, /* do_gc */ + false, /* clear_all_soft_refs */ + false, /* expect_null_mutator_alloc_region */ + succeeded); + + if (result != NULL || !*succeeded) { return result; } - // Then, try a Full GC that will collect all soft references. - gc_succeeded = do_collection(false, /* explicit_gc */ - true, /* clear_all_soft_refs */ - word_size); - if (!gc_succeeded) { - *succeeded = false; - return NULL; - } - - // Retry the allocation once more - result = attempt_allocation_at_safepoint(word_size, - context, - true /* expect_null_mutator_alloc_region */); + // Attempts to allocate followed by Full GC that will collect all soft references. + result = satisfy_failed_allocation_helper(word_size, + context, + true, /* do_gc */ + true, /* clear_all_soft_refs */ + true, /* expect_null_mutator_alloc_region */ + succeeded); + + if (result != NULL || !*succeeded) { + return result; + } + + // Attempts to allocate, no GC + result = satisfy_failed_allocation_helper(word_size, + context, + false, /* do_gc */ + false, /* clear_all_soft_refs */ + true, /* expect_null_mutator_alloc_region */ + succeeded); + if (result != NULL) { assert(*succeeded, "sanity"); return result; @@ -2538,9 +2560,9 @@ void G1CollectedHeap::increment_old_marking_cycles_started() { assert(_old_marking_cycles_started == _old_marking_cycles_completed || - _old_marking_cycles_started == _old_marking_cycles_completed + 1, - err_msg("Wrong marking cycle count (started: %d, completed: %d)", - _old_marking_cycles_started, _old_marking_cycles_completed)); + _old_marking_cycles_started == _old_marking_cycles_completed + 1, + "Wrong marking cycle count (started: %d, completed: %d)", + _old_marking_cycles_started, _old_marking_cycles_completed); _old_marking_cycles_started++; } @@ -2564,17 +2586,17 @@ assert(concurrent || (_old_marking_cycles_started == _old_marking_cycles_completed + 1) || (_old_marking_cycles_started == _old_marking_cycles_completed + 2), - err_msg("for inner caller (Full GC): _old_marking_cycles_started = %u " - "is inconsistent with _old_marking_cycles_completed = %u", - _old_marking_cycles_started, _old_marking_cycles_completed)); + "for inner caller (Full GC): _old_marking_cycles_started = %u " + "is inconsistent with _old_marking_cycles_completed = %u", + _old_marking_cycles_started, _old_marking_cycles_completed); // This is the case for the outer caller, i.e. the concurrent cycle. assert(!concurrent || (_old_marking_cycles_started == _old_marking_cycles_completed + 1), - err_msg("for outer caller (concurrent cycle): " - "_old_marking_cycles_started = %u " - "is inconsistent with _old_marking_cycles_completed = %u", - _old_marking_cycles_started, _old_marking_cycles_completed)); + "for outer caller (concurrent cycle): " + "_old_marking_cycles_started = %u " + "is inconsistent with _old_marking_cycles_completed = %u", + _old_marking_cycles_started, _old_marking_cycles_completed); _old_marking_cycles_completed += 1; @@ -2594,15 +2616,18 @@ } void G1CollectedHeap::register_concurrent_cycle_start(const Ticks& start_time) { + GCIdMarkAndRestore conc_gc_id_mark; collector_state()->set_concurrent_cycle_started(true); _gc_timer_cm->register_gc_start(start_time); _gc_tracer_cm->report_gc_start(gc_cause(), _gc_timer_cm->gc_start()); trace_heap_before_gc(_gc_tracer_cm); + _cmThread->set_gc_id(GCId::current()); } void G1CollectedHeap::register_concurrent_cycle_end() { if (collector_state()->concurrent_cycle_started()) { + GCIdMarkAndRestore conc_gc_id_mark(_cmThread->gc_id()); if (_cm->has_aborted()) { _gc_tracer_cm->report_concurrent_mode_failure(); } @@ -2625,6 +2650,7 @@ // but before the concurrent cycle end has been registered. // Make sure that we only send the heap information once. if (!_heap_summary_sent) { + GCIdMarkAndRestore conc_gc_id_mark(_cmThread->gc_id()); trace_heap_after_gc(_gc_tracer_cm); _heap_summary_sent = true; } @@ -3124,7 +3150,7 @@ _young_ref_counter_closure.reset_count(); k->oops_do(&_young_ref_counter_closure); if (_young_ref_counter_closure.count() > 0) { - guarantee(k->has_modified_oops(), err_msg("Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k))); + guarantee(k->has_modified_oops(), "Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k)); } } }; @@ -3194,8 +3220,8 @@ template void do_oop_work(T *p) { oop obj = oopDesc::load_decode_heap_oop(p); guarantee(obj == NULL || G1MarkSweep::in_archive_range(obj), - err_msg("Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT, - p2i(p), p2i(obj))); + "Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT, + p2i(p), p2i(obj)); } }; @@ -3630,8 +3656,9 @@ // FIXME: what is this about? // I'm ignoring the "fill_newgen()" call if "alloc_event_enabled" // is set. - COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), - "derived pointer present")); +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_empty(), "derived pointer present"); +#endif // always_do_update_barrier = true; resize_all_tlabs(); @@ -3894,7 +3921,7 @@ return; } - gclog_or_tty->gclog_stamp(_gc_tracer_stw->gc_id()); + gclog_or_tty->gclog_stamp(); GCCauseString gc_cause_str = GCCauseString("GC pause", gc_cause()) .append(collector_state()->gcs_are_young() ? "(young)" : "(mixed)") @@ -3952,6 +3979,7 @@ _gc_timer_stw->register_gc_start(); + GCIdMark gc_id_mark; _gc_tracer_stw->report_gc_start(gc_cause(), _gc_timer_stw->gc_start()); SvcGCMarker sgcm(SvcGCMarker::MINOR); @@ -4037,7 +4065,9 @@ check_bitmaps("GC Start"); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif // Please see comment in g1CollectedHeap.hpp and // G1CollectedHeap::ref_processing_init() to see how @@ -4709,11 +4739,11 @@ ~G1StringSymbolTableUnlinkTask() { guarantee(!_process_strings || StringTable::parallel_claimed_index() >= _initial_string_table_size, - err_msg("claim value %d after unlink less than initial string table size %d", - StringTable::parallel_claimed_index(), _initial_string_table_size)); + "claim value %d after unlink less than initial string table size %d", + StringTable::parallel_claimed_index(), _initial_string_table_size); guarantee(!_process_symbols || SymbolTable::parallel_claimed_index() >= _initial_symbol_table_size, - err_msg("claim value %d after unlink less than initial symbol table size %d", - SymbolTable::parallel_claimed_index(), _initial_symbol_table_size)); + "claim value %d after unlink less than initial symbol table size %d", + SymbolTable::parallel_claimed_index(), _initial_symbol_table_size); if (G1TraceStringSymbolTableScrubbing) { gclog_or_tty->print_cr("Cleaned string and symbol table, " @@ -5113,7 +5143,7 @@ } else { assert(!obj->is_forwarded(), "invariant" ); assert(cset_state.is_humongous(), - err_msg("Only allowed InCSet state is IsHumongous, but is %d", cset_state.value())); + "Only allowed InCSet state is IsHumongous, but is %d", cset_state.value()); _g1->set_humongous_is_live(obj); } } @@ -5167,7 +5197,7 @@ _par_scan_state->push_on_queue(p); } else { assert(!Metaspace::contains((const void*)p), - err_msg("Unexpectedly found a pointer from metadata: " PTR_FORMAT, p2i(p))); + "Unexpectedly found a pointer from metadata: " PTR_FORMAT, p2i(p)); _copy_non_heap_obj_cl->do_oop(p); } } @@ -5501,8 +5531,7 @@ &keep_alive, &drain_queue, NULL, - _gc_timer_stw, - _gc_tracer_stw->gc_id()); + _gc_timer_stw); } else { // Parallel reference processing assert(rp->num_q() == no_of_gc_workers, "sanity"); @@ -5513,8 +5542,7 @@ &keep_alive, &drain_queue, &par_task_executor, - _gc_timer_stw, - _gc_tracer_stw->gc_id()); + _gc_timer_stw); } _gc_tracer_stw->report_gc_reference_stats(stats); @@ -5666,7 +5694,9 @@ enqueue_discovered_references(per_thread_states); redirty_logged_cards(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif } void G1CollectedHeap::record_obj_copy_mem_stats() { @@ -5823,7 +5853,7 @@ bool G1CollectedHeap::verify_no_bits_over_tams(const char* bitmap_name, CMBitMapRO* bitmap, HeapWord* tams, HeapWord* end) { guarantee(tams <= end, - err_msg("tams: " PTR_FORMAT " end: " PTR_FORMAT, p2i(tams), p2i(end))); + "tams: " PTR_FORMAT " end: " PTR_FORMAT, p2i(tams), p2i(end)); HeapWord* result = bitmap->getNextMarkedWordAddress(tams, end); if (result < end) { gclog_or_tty->cr(); @@ -6174,9 +6204,8 @@ } guarantee(obj->is_typeArray(), - err_msg("Only eagerly reclaiming type arrays is supported, but the object " - PTR_FORMAT " is not.", - p2i(r->bottom()))); + "Only eagerly reclaiming type arrays is supported, but the object " + PTR_FORMAT " is not.", p2i(r->bottom())); if (G1TraceEagerReclaimHumongousObjects) { gclog_or_tty->print_cr("Dead humongous region %u size " SIZE_FORMAT " start " PTR_FORMAT " length %u with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d", @@ -6405,8 +6434,8 @@ void G1CollectedHeap::decrease_used(size_t bytes) { assert(_summary_bytes_used >= bytes, - err_msg("invariant: _summary_bytes_used: " SIZE_FORMAT " should be >= bytes: " SIZE_FORMAT, - _summary_bytes_used, bytes)); + "invariant: _summary_bytes_used: " SIZE_FORMAT " should be >= bytes: " SIZE_FORMAT, + _summary_bytes_used, bytes); _summary_bytes_used -= bytes; } @@ -6488,9 +6517,9 @@ } } assert(used_unlocked() == recalculate_used(), - err_msg("inconsistent used_unlocked(), " - "value: " SIZE_FORMAT " recalculated: " SIZE_FORMAT, - used_unlocked(), recalculate_used())); + "inconsistent used_unlocked(), " + "value: " SIZE_FORMAT " recalculated: " SIZE_FORMAT, + used_unlocked(), recalculate_used()); } void G1CollectedHeap::set_refine_cte_cl_concurrency(bool concurrent) { @@ -6631,35 +6660,35 @@ if (hr->is_young()) { // TODO } else if (hr->is_starts_humongous()) { - assert(hr->containing_set() == _humongous_set, err_msg("Heap region %u is starts humongous but not in humongous set.", hr->hrm_index())); + assert(hr->containing_set() == _humongous_set, "Heap region %u is starts humongous but not in humongous set.", hr->hrm_index()); _humongous_count.increment(1u, hr->capacity()); } else if (hr->is_empty()) { - assert(_hrm->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrm_index())); + assert(_hrm->is_free(hr), "Heap region %u is empty but not on the free list.", hr->hrm_index()); _free_count.increment(1u, hr->capacity()); } else if (hr->is_old()) { - assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrm_index())); + assert(hr->containing_set() == _old_set, "Heap region %u is old but not in the old set.", hr->hrm_index()); _old_count.increment(1u, hr->capacity()); } else { // There are no other valid region types. Check for one invalid // one we can identify: pinned without old or humongous set. - assert(!hr->is_pinned(), err_msg("Heap region %u is pinned but not old (archive) or humongous.", hr->hrm_index())); + assert(!hr->is_pinned(), "Heap region %u is pinned but not old (archive) or humongous.", hr->hrm_index()); ShouldNotReachHere(); } return false; } void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionManager* free_list) { - guarantee(old_set->length() == _old_count.length(), err_msg("Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count.length())); - guarantee(old_set->total_capacity_bytes() == _old_count.capacity(), err_msg("Old set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - old_set->total_capacity_bytes(), _old_count.capacity())); - - guarantee(humongous_set->length() == _humongous_count.length(), err_msg("Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count.length())); - guarantee(humongous_set->total_capacity_bytes() == _humongous_count.capacity(), err_msg("Hum set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - humongous_set->total_capacity_bytes(), _humongous_count.capacity())); - - guarantee(free_list->num_free_regions() == _free_count.length(), err_msg("Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count.length())); - guarantee(free_list->total_capacity_bytes() == _free_count.capacity(), err_msg("Free list capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - free_list->total_capacity_bytes(), _free_count.capacity())); + guarantee(old_set->length() == _old_count.length(), "Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count.length()); + guarantee(old_set->total_capacity_bytes() == _old_count.capacity(), "Old set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + old_set->total_capacity_bytes(), _old_count.capacity()); + + guarantee(humongous_set->length() == _humongous_count.length(), "Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count.length()); + guarantee(humongous_set->total_capacity_bytes() == _humongous_count.capacity(), "Hum set capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + humongous_set->total_capacity_bytes(), _humongous_count.capacity()); + + guarantee(free_list->num_free_regions() == _free_count.length(), "Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count.length()); + guarantee(free_list->total_capacity_bytes() == _free_count.capacity(), "Free list capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + free_list->total_capacity_bytes(), _free_count.capacity()); } }; @@ -6715,9 +6744,9 @@ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); HeapRegion* hr = _g1h->heap_region_containing(obj); assert(!hr->is_continues_humongous(), - err_msg("trying to add code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT - " starting at " HR_FORMAT, - p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); + "trying to add code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT + " starting at " HR_FORMAT, + p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())); // HeapRegion::add_strong_code_root_locked() avoids adding duplicate entries. hr->add_strong_code_root_locked(_nm); @@ -6742,9 +6771,9 @@ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); HeapRegion* hr = _g1h->heap_region_containing(obj); assert(!hr->is_continues_humongous(), - err_msg("trying to remove code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT - " starting at " HR_FORMAT, - p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()))); + "trying to remove code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT + " starting at " HR_FORMAT, + p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())); hr->remove_strong_code_root(_nm); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -368,17 +368,17 @@ // These are macros so that, if the assert fires, we get the correct // line number, file, etc. -#define heap_locking_asserts_err_msg(_extra_message_) \ - err_msg("%s : Heap_lock locked: %s, at safepoint: %s, is VM thread: %s", \ - (_extra_message_), \ - BOOL_TO_STR(Heap_lock->owned_by_self()), \ - BOOL_TO_STR(SafepointSynchronize::is_at_safepoint()), \ - BOOL_TO_STR(Thread::current()->is_VM_thread())) +#define heap_locking_asserts_params(_extra_message_) \ + "%s : Heap_lock locked: %s, at safepoint: %s, is VM thread: %s", \ + (_extra_message_), \ + BOOL_TO_STR(Heap_lock->owned_by_self()), \ + BOOL_TO_STR(SafepointSynchronize::is_at_safepoint()), \ + BOOL_TO_STR(Thread::current()->is_VM_thread()) #define assert_heap_locked() \ do { \ assert(Heap_lock->owned_by_self(), \ - heap_locking_asserts_err_msg("should be holding the Heap_lock")); \ + heap_locking_asserts_params("should be holding the Heap_lock")); \ } while (0) #define assert_heap_locked_or_at_safepoint(_should_be_vm_thread_) \ @@ -386,7 +386,7 @@ assert(Heap_lock->owned_by_self() || \ (SafepointSynchronize::is_at_safepoint() && \ ((_should_be_vm_thread_) == Thread::current()->is_VM_thread())), \ - heap_locking_asserts_err_msg("should be holding the Heap_lock or " \ + heap_locking_asserts_params("should be holding the Heap_lock or " \ "should be at a safepoint")); \ } while (0) @@ -394,21 +394,21 @@ do { \ assert(Heap_lock->owned_by_self() && \ !SafepointSynchronize::is_at_safepoint(), \ - heap_locking_asserts_err_msg("should be holding the Heap_lock and " \ + heap_locking_asserts_params("should be holding the Heap_lock and " \ "should not be at a safepoint")); \ } while (0) #define assert_heap_not_locked() \ do { \ assert(!Heap_lock->owned_by_self(), \ - heap_locking_asserts_err_msg("should not be holding the Heap_lock")); \ + heap_locking_asserts_params("should not be holding the Heap_lock")); \ } while (0) #define assert_heap_not_locked_and_not_at_safepoint() \ do { \ assert(!Heap_lock->owned_by_self() && \ !SafepointSynchronize::is_at_safepoint(), \ - heap_locking_asserts_err_msg("should not be holding the Heap_lock and " \ + heap_locking_asserts_params("should not be holding the Heap_lock and " \ "should not be at a safepoint")); \ } while (0) @@ -416,13 +416,13 @@ do { \ assert(SafepointSynchronize::is_at_safepoint() && \ ((_should_be_vm_thread_) == Thread::current()->is_VM_thread()), \ - heap_locking_asserts_err_msg("should be at a safepoint")); \ + heap_locking_asserts_params("should be at a safepoint")); \ } while (0) #define assert_not_at_safepoint() \ do { \ assert(!SafepointSynchronize::is_at_safepoint(), \ - heap_locking_asserts_err_msg("should not be at a safepoint")); \ + heap_locking_asserts_params("should not be at a safepoint")); \ } while (0) protected: @@ -571,7 +571,16 @@ HeapWord* satisfy_failed_allocation(size_t word_size, AllocationContext_t context, bool* succeeded); +private: + // Helper method for satisfy_failed_allocation() + HeapWord* satisfy_failed_allocation_helper(size_t word_size, + AllocationContext_t context, + bool do_gc, + bool clear_all_soft_refs, + bool expect_null_mutator_alloc_region, + bool* gc_succeeded); +protected: // Attempting to expand the heap sufficiently // to support an allocation of the given "word_size". If // successful, perform the allocation and return the address of the @@ -1045,6 +1054,7 @@ return CollectedHeap::G1CollectedHeap; } + const G1CollectorState* collector_state() const { return &_collector_state; } G1CollectorState* collector_state() { return &_collector_state; } // The current policy object for the collector. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -67,8 +67,8 @@ inline uint G1CollectedHeap::addr_to_region(HeapWord* addr) const { assert(is_in_reserved(addr), - err_msg("Cannot calculate region index for address " PTR_FORMAT " that is outside of the heap [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(addr), p2i(reserved_region().start()), p2i(reserved_region().end()))); + "Cannot calculate region index for address " PTR_FORMAT " that is outside of the heap [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(addr), p2i(reserved_region().start()), p2i(reserved_region().end())); return (uint)(pointer_delta(addr, reserved_region().start(), sizeof(uint8_t)) >> HeapRegion::LogOfHRGrainBytes); } @@ -80,8 +80,8 @@ inline HeapRegion* G1CollectedHeap::heap_region_containing_raw(const T addr) const { assert(addr != NULL, "invariant"); assert(is_in_g1_reserved((const void*) addr), - err_msg("Address " PTR_FORMAT " is outside of the heap ranging from [" PTR_FORMAT " to " PTR_FORMAT ")", - p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end()))); + "Address " PTR_FORMAT " is outside of the heap ranging from [" PTR_FORMAT " to " PTR_FORMAT ")", + p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end())); return _hrm.addr_to_region((HeapWord*) addr); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -112,6 +112,8 @@ new TruncatedSeq(NumPrevPausesForHeuristics)), _recent_avg_pause_time_ratio(0.0), + _rs_lengths_prediction(0), + _max_survivor_regions(0), _eden_used_bytes_before_gc(0), _survivor_used_bytes_before_gc(0), @@ -264,9 +266,6 @@ _concurrent_mark_remark_times_ms->add(0.05); _concurrent_mark_cleanup_times_ms->add(0.20); _tenuring_threshold = MaxTenuringThreshold; - // _max_survivor_regions will be calculated by - // update_young_list_target_length() during initialization. - _max_survivor_regions = 0; assert(GCTimeRatio > 0, "we should have set it to a default value set_g1_gc_flags() " @@ -315,6 +314,7 @@ } } +const G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); } G1CollectorState* G1CollectorPolicy::collector_state() { return _g1->collector_state(); } G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true), @@ -441,7 +441,7 @@ bool G1CollectorPolicy::predict_will_fit(uint young_length, double base_time_ms, uint base_free_regions, - double target_pause_time_ms) { + double target_pause_time_ms) const { if (young_length >= base_free_regions) { // end condition 1: not enough space for the young regions return false; @@ -480,7 +480,7 @@ } uint G1CollectorPolicy::calculate_young_list_desired_min_length( - uint base_min_length) { + uint base_min_length) const { uint desired_min_length = 0; if (adaptive_young_list_length()) { if (_alloc_rate_ms_seq->num() > 3) { @@ -497,7 +497,7 @@ return MAX2(_young_gen_sizer->min_desired_young_length(), desired_min_length); } -uint G1CollectorPolicy::calculate_young_list_desired_max_length() { +uint G1CollectorPolicy::calculate_young_list_desired_max_length() const { // Here, we might want to also take into account any additional // constraints (i.e., user-defined minimum bound). Currently, we // effectively don't set this bound. @@ -575,7 +575,7 @@ G1CollectorPolicy::calculate_young_list_target_length(size_t rs_lengths, uint base_min_length, uint desired_min_length, - uint desired_max_length) { + uint desired_max_length) const { assert(adaptive_young_list_length(), "pre-condition"); assert(collector_state()->gcs_are_young(), "only call this for young GCs"); @@ -675,7 +675,7 @@ return base_min_length + min_young_length; } -double G1CollectorPolicy::predict_survivor_regions_evac_time() { +double G1CollectorPolicy::predict_survivor_regions_evac_time() const { double survivor_regions_evac_time = 0.0; for (HeapRegion * r = _recorded_survivor_head; r != NULL && r != _recorded_survivor_tail->get_next_young_region(); @@ -813,8 +813,8 @@ update_survivors_policy(); assert(_g1->used() == _g1->recalculate_used(), - err_msg("sanity, used: " SIZE_FORMAT " recalculate_used: " SIZE_FORMAT, - _g1->used(), _g1->recalculate_used())); + "sanity, used: " SIZE_FORMAT " recalculate_used: " SIZE_FORMAT, + _g1->used(), _g1->recalculate_used()); double s_w_t_ms = (start_time_sec - _stop_world_start) * 1000.0; _trace_young_gen_time_data.record_start_collection(s_w_t_ms); @@ -857,7 +857,7 @@ _cur_mark_stop_world_time_ms += elapsed_time_ms; _prev_collection_pause_end_ms += elapsed_time_ms; - _mmu_tracker->add_pause(_mark_remark_start_sec, end_time_sec, _g1->gc_tracer_cm()->gc_id()); + _mmu_tracker->add_pause(_mark_remark_start_sec, end_time_sec); } void G1CollectorPolicy::record_concurrent_mark_cleanup_start() { @@ -952,8 +952,7 @@ collector_state()->set_initiate_conc_mark_if_possible(true); } - _mmu_tracker->add_pause(end_time_sec - pause_time_ms/1000.0, - end_time_sec, _g1->gc_tracer_stw()->gc_id()); + _mmu_tracker->add_pause(end_time_sec - pause_time_ms/1000.0, end_time_sec); if (update_stats) { _trace_young_gen_time_data.record_end_collection(pause_time_ms, phase_times()); @@ -1174,7 +1173,7 @@ } } -void G1CollectorPolicy::print_heap_transition(size_t bytes_before) { +void G1CollectorPolicy::print_heap_transition(size_t bytes_before) const { size_t bytes_after = _g1->used(); size_t capacity = _g1->capacity(); @@ -1187,11 +1186,11 @@ proper_unit_for_byte_size(capacity)); } -void G1CollectorPolicy::print_heap_transition() { +void G1CollectorPolicy::print_heap_transition() const { print_heap_transition(_heap_used_bytes_before_gc); } -void G1CollectorPolicy::print_detailed_heap_transition(bool full) { +void G1CollectorPolicy::print_detailed_heap_transition(bool full) const { YoungList* young_list = _g1->young_list(); size_t eden_used_bytes_after_gc = young_list->eden_used_bytes(); @@ -1268,7 +1267,7 @@ double G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards, - size_t scanned_cards) { + size_t scanned_cards) const { return predict_rs_update_time_ms(pending_cards) + predict_rs_scan_time_ms(scanned_cards) + @@ -1276,7 +1275,7 @@ } double -G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) { +G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) const { size_t rs_length = predict_rs_length_diff(); size_t card_num; if (collector_state()->gcs_are_young()) { @@ -1287,7 +1286,7 @@ return predict_base_elapsed_time_ms(pending_cards, card_num); } -size_t G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) { +size_t G1CollectorPolicy::predict_bytes_to_copy(HeapRegion* hr) const { size_t bytes_to_copy; if (hr->is_marked()) bytes_to_copy = hr->max_live_bytes(); @@ -1302,7 +1301,7 @@ double G1CollectorPolicy::predict_region_elapsed_time_ms(HeapRegion* hr, - bool for_young_gc) { + bool for_young_gc) const { size_t rs_length = hr->rem_set()->occupied(); size_t card_num; @@ -1348,7 +1347,7 @@ _prev_collection_pause_end_ms = end_time_sec * 1000.0; } -size_t G1CollectorPolicy::expansion_amount() { +size_t G1CollectorPolicy::expansion_amount() const { double recent_gc_overhead = recent_avg_pause_time_ratio() * 100.0; double threshold = _gc_overhead_perc; if (recent_gc_overhead > threshold) { @@ -1397,13 +1396,13 @@ #endif // PRODUCT } -bool G1CollectorPolicy::is_young_list_full() { +bool G1CollectorPolicy::is_young_list_full() const { uint young_list_length = _g1->young_list()->length(); uint young_list_target_length = _young_list_target_length; return young_list_length >= young_list_target_length; } -bool G1CollectorPolicy::can_expand_young_list() { +bool G1CollectorPolicy::can_expand_young_list() const { uint young_list_length = _g1->young_list()->length(); uint young_list_max_length = _young_list_max_length; return young_list_length < young_list_max_length; @@ -1557,7 +1556,7 @@ } }; -uint G1CollectorPolicy::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) { +uint G1CollectorPolicy::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const { assert(n_workers > 0, "Active gc workers should be greater than 0"); const uint overpartition_factor = 4; const uint min_chunk_size = MAX2(n_regions / n_workers, 1U); @@ -1584,7 +1583,7 @@ _concurrent_mark_cleanup_times_ms->add(elapsed_time_ms); _cur_mark_stop_world_time_ms += elapsed_time_ms; _prev_collection_pause_end_ms += elapsed_time_ms; - _mmu_tracker->add_pause(_mark_cleanup_start_sec, end_sec, _g1->gc_tracer_cm()->gc_id()); + _mmu_tracker->add_pause(_mark_cleanup_start_sec, end_sec); } // Add the heap region at the head of the non-incremental collection set @@ -1783,7 +1782,7 @@ } #endif // !PRODUCT -double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) { +double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) const { // Returns the given amount of reclaimable bytes (that represents // the amount of reclaimable space still to be collected) as a // percentage of the current heap capacity. @@ -1792,7 +1791,7 @@ } bool G1CollectorPolicy::next_gc_should_be_mixed(const char* true_action_str, - const char* false_action_str) { + const char* false_action_str) const { CollectionSetChooser* cset_chooser = _collectionSetChooser; if (cset_chooser->is_empty()) { ergo_verbose0(ErgoMixedGCs, @@ -1830,7 +1829,7 @@ return true; } -uint G1CollectorPolicy::calc_min_old_cset_length() { +uint G1CollectorPolicy::calc_min_old_cset_length() const { // The min old CSet region bound is based on the maximum desired // number of mixed GCs after a cycle. I.e., even if some old regions // look expensive, we should add them to the CSet anyway to make @@ -1851,13 +1850,13 @@ return (uint) result; } -uint G1CollectorPolicy::calc_max_old_cset_length() { +uint G1CollectorPolicy::calc_max_old_cset_length() const { // The max old CSet region bound is based on the threshold expressed // as a percentage of the heap size. I.e., it should bound the // number of old regions added to the CSet irrespective of how many // of them are available. - G1CollectedHeap* g1h = G1CollectedHeap::heap(); + const G1CollectedHeap* g1h = G1CollectedHeap::heap(); const size_t region_num = g1h->num_regions(); const size_t perc = (size_t) G1OldCSetRegionThresholdPercent; size_t result = region_num * perc / 100; @@ -1876,8 +1875,7 @@ finalize_incremental_cset_building(); guarantee(target_pause_time_ms > 0.0, - err_msg("target_pause_time_ms = %1.6lf should be positive", - target_pause_time_ms)); + "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); guarantee(_collection_set == NULL, "Precondition"); double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -155,7 +155,7 @@ uint max_desired_young_length() { return _max_desired_young_length; } - bool adaptive_young_list_length() { + bool adaptive_young_list_length() const { return _adaptive_size; } }; @@ -242,9 +242,9 @@ void init_cset_region_lengths(uint eden_cset_region_length, uint survivor_cset_region_length); - uint eden_cset_region_length() { return _eden_cset_region_length; } - uint survivor_cset_region_length() { return _survivor_cset_region_length; } - uint old_cset_region_length() { return _old_cset_region_length; } + uint eden_cset_region_length() const { return _eden_cset_region_length; } + uint survivor_cset_region_length() const { return _survivor_cset_region_length; } + uint old_cset_region_length() const { return _old_cset_region_length; } uint _free_regions_at_end_of_collection; @@ -254,13 +254,13 @@ size_t _rs_lengths_prediction; - double sigma() { return _sigma; } + double sigma() const { return _sigma; } // A function that prevents us putting too much stock in small sample // sets. Returns a number between 2.0 and 1.0, depending on the number // of samples. 5 or more samples yields one; fewer scales linearly from // 2.0 at 1 sample to 1.0 at 5. - double confidence_factor(int samples) { + double confidence_factor(int samples) const { if (samples > 4) return 1.0; else return 1.0 + sigma() * ((double)(5 - samples))/2.0; } @@ -303,7 +303,7 @@ bool verify_young_ages(); #endif // PRODUCT - double get_new_prediction(TruncatedSeq* seq) { + double get_new_prediction(TruncatedSeq* seq) const { return MAX2(seq->davg() + sigma() * seq->dsd(), seq->davg() * confidence_factor(seq->num())); } @@ -312,27 +312,27 @@ _max_rs_lengths = rs_lengths; } - size_t predict_rs_length_diff() { + size_t predict_rs_length_diff() const { return (size_t) get_new_prediction(_rs_length_diff_seq); } - double predict_alloc_rate_ms() { + double predict_alloc_rate_ms() const { return get_new_prediction(_alloc_rate_ms_seq); } - double predict_cost_per_card_ms() { + double predict_cost_per_card_ms() const { return get_new_prediction(_cost_per_card_ms_seq); } - double predict_rs_update_time_ms(size_t pending_cards) { + double predict_rs_update_time_ms(size_t pending_cards) const { return (double) pending_cards * predict_cost_per_card_ms(); } - double predict_young_cards_per_entry_ratio() { + double predict_young_cards_per_entry_ratio() const { return get_new_prediction(_young_cards_per_entry_ratio_seq); } - double predict_mixed_cards_per_entry_ratio() { + double predict_mixed_cards_per_entry_ratio() const { if (_mixed_cards_per_entry_ratio_seq->num() < 2) { return predict_young_cards_per_entry_ratio(); } else { @@ -340,17 +340,17 @@ } } - size_t predict_young_card_num(size_t rs_length) { + size_t predict_young_card_num(size_t rs_length) const { return (size_t) ((double) rs_length * predict_young_cards_per_entry_ratio()); } - size_t predict_non_young_card_num(size_t rs_length) { + size_t predict_non_young_card_num(size_t rs_length) const { return (size_t) ((double) rs_length * predict_mixed_cards_per_entry_ratio()); } - double predict_rs_scan_time_ms(size_t card_num) { + double predict_rs_scan_time_ms(size_t card_num) const { if (collector_state()->gcs_are_young()) { return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq); } else { @@ -358,7 +358,7 @@ } } - double predict_mixed_rs_scan_time_ms(size_t card_num) { + double predict_mixed_rs_scan_time_ms(size_t card_num) const { if (_mixed_cost_per_entry_ms_seq->num() < 3) { return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq); } else { @@ -367,7 +367,7 @@ } } - double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) { + double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const { if (_cost_per_byte_ms_during_cm_seq->num() < 3) { return (1.1 * (double) bytes_to_copy) * get_new_prediction(_cost_per_byte_ms_seq); @@ -377,7 +377,7 @@ } } - double predict_object_copy_time_ms(size_t bytes_to_copy) { + double predict_object_copy_time_ms(size_t bytes_to_copy) const { if (collector_state()->during_concurrent_mark()) { return predict_object_copy_time_ms_during_cm(bytes_to_copy); } else { @@ -386,34 +386,34 @@ } } - double predict_constant_other_time_ms() { + double predict_constant_other_time_ms() const { return get_new_prediction(_constant_other_time_ms_seq); } - double predict_young_other_time_ms(size_t young_num) { + double predict_young_other_time_ms(size_t young_num) const { return (double) young_num * get_new_prediction(_young_other_cost_per_region_ms_seq); } - double predict_non_young_other_time_ms(size_t non_young_num) { + double predict_non_young_other_time_ms(size_t non_young_num) const { return (double) non_young_num * get_new_prediction(_non_young_other_cost_per_region_ms_seq); } - double predict_base_elapsed_time_ms(size_t pending_cards); + double predict_base_elapsed_time_ms(size_t pending_cards) const; double predict_base_elapsed_time_ms(size_t pending_cards, - size_t scanned_cards); - size_t predict_bytes_to_copy(HeapRegion* hr); - double predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc); + size_t scanned_cards) const; + size_t predict_bytes_to_copy(HeapRegion* hr) const; + double predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc) const; void set_recorded_rs_lengths(size_t rs_lengths); - uint cset_region_length() { return young_cset_region_length() + + uint cset_region_length() const { return young_cset_region_length() + old_cset_region_length(); } - uint young_cset_region_length() { return eden_cset_region_length() + + uint young_cset_region_length() const { return eden_cset_region_length() + survivor_cset_region_length(); } - double predict_survivor_regions_evac_time(); + double predict_survivor_regions_evac_time() const; void cset_regions_freed() { bool propagate = collector_state()->should_propagate(); @@ -426,21 +426,25 @@ return _mmu_tracker; } - double max_pause_time_ms() { + const G1MMUTracker* mmu_tracker() const { + return _mmu_tracker; + } + + double max_pause_time_ms() const { return _mmu_tracker->max_gc_time() * 1000.0; } - double predict_remark_time_ms() { + double predict_remark_time_ms() const { return get_new_prediction(_concurrent_mark_remark_times_ms); } - double predict_cleanup_time_ms() { + double predict_cleanup_time_ms() const { return get_new_prediction(_concurrent_mark_cleanup_times_ms); } // Returns an estimate of the survival rate of the region at yg-age // "yg_age". - double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) { + double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const { TruncatedSeq* seq = surv_rate_group->get_seq(age); if (seq->num() == 0) gclog_or_tty->print("BARF! age is %d", age); @@ -451,11 +455,11 @@ return pred; } - double predict_yg_surv_rate(int age) { + double predict_yg_surv_rate(int age) const { return predict_yg_surv_rate(age, _short_lived_surv_rate_group); } - double accum_yg_surv_rate_pred(int age) { + double accum_yg_surv_rate_pred(int age) const { return _short_lived_surv_rate_group->accum_surv_rate_pred(age); } @@ -536,7 +540,7 @@ // The ratio of gc time to elapsed time, computed over recent pauses. double _recent_avg_pause_time_ratio; - double recent_avg_pause_time_ratio() { + double recent_avg_pause_time_ratio() const { return _recent_avg_pause_time_ratio; } @@ -556,12 +560,12 @@ // Calculate and return the minimum desired young list target // length. This is the minimum desired young list length according // to the user's inputs. - uint calculate_young_list_desired_min_length(uint base_min_length); + uint calculate_young_list_desired_min_length(uint base_min_length) const; // Calculate and return the maximum desired young list target // length. This is the maximum desired young list length according // to the user's inputs. - uint calculate_young_list_desired_max_length(); + uint calculate_young_list_desired_max_length() const; // Calculate and return the maximum young list target length that // can fit into the pause time goal. The parameters are: rs_lengths @@ -572,11 +576,11 @@ uint calculate_young_list_target_length(size_t rs_lengths, uint base_min_length, uint desired_min_length, - uint desired_max_length); + uint desired_max_length) const; // Calculate and return chunk size (in number of regions) for parallel // concurrent mark cleanup. - uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions); + uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const; // Check whether a given young length (young_length) fits into the // given target pause time and whether the prediction for the amount @@ -584,19 +588,19 @@ // given free space (expressed by base_free_regions). It is used by // calculate_young_list_target_length(). bool predict_will_fit(uint young_length, double base_time_ms, - uint base_free_regions, double target_pause_time_ms); + uint base_free_regions, double target_pause_time_ms) const; // Calculate the minimum number of old regions we'll add to the CSet // during a mixed GC. - uint calc_min_old_cset_length(); + uint calc_min_old_cset_length() const; // Calculate the maximum number of old regions we'll add to the CSet // during a mixed GC. - uint calc_max_old_cset_length(); + uint calc_max_old_cset_length() const; // Returns the given amount of uncollected reclaimable space // as a percentage of the current heap capacity. - double reclaimable_bytes_perc(size_t reclaimable_bytes); + double reclaimable_bytes_perc(size_t reclaimable_bytes) const; public: @@ -604,6 +608,7 @@ virtual G1CollectorPolicy* as_g1_policy() { return this; } + const G1CollectorState* collector_state() const; G1CollectorState* collector_state(); G1GCPhaseTimes* phase_times() const { return _phase_times; } @@ -658,9 +663,9 @@ // Print heap sizing transition (with less and more detail). - void print_heap_transition(size_t bytes_before); - void print_heap_transition(); - void print_detailed_heap_transition(bool full = false); + void print_heap_transition(size_t bytes_before) const; + void print_heap_transition() const; + void print_detailed_heap_transition(bool full = false) const; void record_stop_world_start(); void record_concurrent_pause(); @@ -672,7 +677,7 @@ } // The amount of space we copied during a GC. - size_t bytes_copied_during_gc() { + size_t bytes_copied_during_gc() const { return _bytes_copied_during_gc; } @@ -684,7 +689,7 @@ // next GC should be mixed. The two action strings are used // in the ergo output when the method returns true or false. bool next_gc_should_be_mixed(const char* true_action_str, - const char* false_action_str); + const char* false_action_str) const; // Choose a new collection set. Marks the chosen regions as being // "in_collection_set", and links them together. The head and number of @@ -764,7 +769,7 @@ // If an expansion would be appropriate, because recent GC overhead had // exceeded the desired limit, return an amount to expand by. - virtual size_t expansion_amount(); + virtual size_t expansion_amount() const; // Print tracing information. void print_tracing_info() const; @@ -783,15 +788,15 @@ size_t young_list_target_length() const { return _young_list_target_length; } - bool is_young_list_full(); + bool is_young_list_full() const; - bool can_expand_young_list(); + bool can_expand_young_list() const; - uint young_list_max_length() { + uint young_list_max_length() const { return _young_list_max_length; } - bool adaptive_young_list_length() { + bool adaptive_young_list_length() const { return _young_gen_sizer->adaptive_young_list_length(); } @@ -832,14 +837,14 @@ static const uint REGIONS_UNLIMITED = (uint) -1; - uint max_regions(InCSetState dest) { + uint max_regions(InCSetState dest) const { switch (dest.value()) { case InCSetState::Young: return _max_survivor_regions; case InCSetState::Old: return REGIONS_UNLIMITED; default: - assert(false, err_msg("Unknown dest state: " CSETSTATE_FORMAT, dest.value())); + assert(false, "Unknown dest state: " CSETSTATE_FORMAT, dest.value()); break; } // keep some compilers happy @@ -862,7 +867,7 @@ _recorded_survivor_tail = tail; } - uint recorded_survivor_regions() { + uint recorded_survivor_regions() const { return _recorded_survivor_regions; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1CollectorState.hpp --- a/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -104,24 +104,24 @@ void set_full_collection(bool v) { _full_collection = v; } // Getters - bool gcs_are_young() { return _gcs_are_young; } - bool last_gc_was_young() { return _last_gc_was_young; } - bool last_young_gc() { return _last_young_gc; } - bool during_initial_mark_pause() { return _during_initial_mark_pause; } - bool initiate_conc_mark_if_possible() { return _initiate_conc_mark_if_possible; } - bool during_marking() { return _during_marking; } - bool mark_in_progress() { return _mark_in_progress; } - bool in_marking_window() { return _in_marking_window; } - bool in_marking_window_im() { return _in_marking_window_im; } - bool concurrent_cycle_started() { return _concurrent_cycle_started; } - bool full_collection() { return _full_collection; } + bool gcs_are_young() const { return _gcs_are_young; } + bool last_gc_was_young() const { return _last_gc_was_young; } + bool last_young_gc() const { return _last_young_gc; } + bool during_initial_mark_pause() const { return _during_initial_mark_pause; } + bool initiate_conc_mark_if_possible() const { return _initiate_conc_mark_if_possible; } + bool during_marking() const { return _during_marking; } + bool mark_in_progress() const { return _mark_in_progress; } + bool in_marking_window() const { return _in_marking_window; } + bool in_marking_window_im() const { return _in_marking_window_im; } + bool concurrent_cycle_started() const { return _concurrent_cycle_started; } + bool full_collection() const { return _full_collection; } // Composite booleans (clients worry about flickering) - bool during_concurrent_mark() { + bool during_concurrent_mark() const { return (_in_marking_window && !_in_marking_window_im); } - bool should_propagate() { // XXX should have a more suitable state name or abstraction for this + bool should_propagate() const { // XXX should have a more suitable state name or abstraction for this return (_last_young_gc && !_in_marking_window); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp --- a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -165,9 +165,9 @@ size_t size_second_obj = ((oop)end_first_obj)->size(); HeapWord* end_of_second_obj = end_first_obj + size_second_obj; assert(end == end_of_second_obj, - err_msg("More than two objects were used to fill the area from " PTR_FORMAT " to " PTR_FORMAT ", " - "second objects size " SIZE_FORMAT " ends at " PTR_FORMAT, - p2i(start), p2i(end), size_second_obj, p2i(end_of_second_obj))); + "More than two objects were used to fill the area from " PTR_FORMAT " to " PTR_FORMAT ", " + "second objects size " SIZE_FORMAT " ends at " PTR_FORMAT, + p2i(start), p2i(end), size_second_obj, p2i(end_of_second_obj)); #endif } } @@ -215,7 +215,7 @@ bool during_initial_mark = _g1h->collector_state()->during_initial_mark_pause(); bool during_conc_mark = _g1h->collector_state()->mark_in_progress(); - assert(!hr->is_pinned(), err_msg("Unexpected pinned region at index %u", hr->hrm_index())); + assert(!hr->is_pinned(), "Unexpected pinned region at index %u", hr->hrm_index()); assert(hr->in_collection_set(), "bad CS"); if (_hrclaimer->claim_region(hr->hrm_index())) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1EvacStats.cpp --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -45,13 +45,13 @@ if (_allocated == 0) { assert((_unused == 0), - err_msg("Inconsistency in PLAB stats: " - "_allocated: " SIZE_FORMAT ", " - "_wasted: " SIZE_FORMAT ", " - "_region_end_waste: " SIZE_FORMAT ", " - "_unused: " SIZE_FORMAT ", " - "_used : " SIZE_FORMAT, - _allocated, _wasted, _region_end_waste, _unused, used())); + "Inconsistency in PLAB stats: " + "_allocated: " SIZE_FORMAT ", " + "_wasted: " SIZE_FORMAT ", " + "_region_end_waste: " SIZE_FORMAT ", " + "_unused: " SIZE_FORMAT ", " + "_used : " SIZE_FORMAT, + _allocated, _wasted, _region_end_waste, _unused, used()); _allocated = 1; } // The size of the PLAB caps the amount of space that can be wasted at the diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -130,8 +130,8 @@ WorkerDataArray* thread_work_items() { return _thread_work_items; } void set(uint worker_i, T value) { - assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); - assert(_data[worker_i] == WorkerDataArray::uninitialized(), err_msg("Overwriting data for worker %d in %s", worker_i, _title)); + assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length); + assert(_data[worker_i] == WorkerDataArray::uninitialized(), "Overwriting data for worker %d in %s", worker_i, _title); _data[worker_i] = value; _has_new_data = true; } @@ -142,14 +142,14 @@ } T get(uint worker_i) { - assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); - assert(_data[worker_i] != WorkerDataArray::uninitialized(), err_msg("No data added for worker %d", worker_i)); + assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length); + assert(_data[worker_i] != WorkerDataArray::uninitialized(), "No data added for worker %d", worker_i); return _data[worker_i]; } void add(uint worker_i, T value) { - assert(worker_i < _length, err_msg("Worker %d is greater than max: %d", worker_i, _length)); - assert(_data[worker_i] != WorkerDataArray::uninitialized(), err_msg("No data to add to for worker %d", worker_i)); + assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length); + assert(_data[worker_i] != WorkerDataArray::uninitialized(), "No data to add to for worker %d", worker_i); _data[worker_i] += value; _has_new_data = true; } @@ -235,7 +235,7 @@ assert(active_threads <= _length, "Wrong number of active threads"); for (uint i = 0; i < active_threads; i++) { assert(_data[i] != WorkerDataArray::uninitialized(), - err_msg("Invalid data for worker %u in '%s'", i, _title)); + "Invalid data for worker %u in '%s'", i, _title); } if (_thread_work_items != NULL) { _thread_work_items->verify(active_threads); @@ -479,7 +479,7 @@ print_count_values(buf, phase_id, thread_work_items); } - assert(thread_work_items->_print_sum, err_msg("%s does not have print sum true even though it is a count", thread_work_items->_title)); + assert(thread_work_items->_print_sum, "%s does not have print sum true even though it is a count", thread_work_items->_title); buf.append_and_print_cr(" Min: " SIZE_FORMAT ", Avg: %.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT ", Sum: " SIZE_FORMAT "]", _phase_times->min_thread_work_items(phase_id), _phase_times->average_thread_work_items(phase_id), _phase_times->max_thread_work_items(phase_id), diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -112,8 +112,7 @@ // 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(), "Should be at a safepoint"); - assert(worker_i < ParallelGCThreads, - err_msg("incorrect worker id: %u", worker_i)); + assert(worker_i < ParallelGCThreads, "incorrect worker id: %u", worker_i); into_cset_dcq->enqueue(card_ptr); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1InCSetState.hpp --- a/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -67,7 +67,7 @@ }; InCSetState(in_cset_state_t value = NotInCSet) : _value(value) { - assert(is_valid(), err_msg("Invalid state %d", _value)); + assert(is_valid(), "Invalid state %d", _value); } in_cset_state_t value() const { return _value; } @@ -104,7 +104,7 @@ public: void set_humongous(uintptr_t index) { assert(get_by_index(index).is_default(), - err_msg("State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value())); + "State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value()); set_by_index(index, InCSetState::Humongous); } @@ -114,13 +114,13 @@ void set_in_young(uintptr_t index) { assert(get_by_index(index).is_default(), - err_msg("State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value())); + "State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value()); set_by_index(index, InCSetState::Young); } void set_in_old(uintptr_t index) { assert(get_by_index(index).is_default(), - err_msg("State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value())); + "State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value()); set_by_index(index, InCSetState::Old); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1MMUTracker.cpp --- a/hotspot/src/share/vm/gc/g1/g1MMUTracker.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1MMUTracker.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -76,7 +76,7 @@ return gc_time; } -void G1MMUTrackerQueue::add_pause(double start, double end, const GCId& gcId) { +void G1MMUTrackerQueue::add_pause(double start, double end) { double duration = end - start; remove_expired_entries(end); @@ -106,7 +106,7 @@ // Current entry needs to be added before calculating the value double slice_time = calculate_gc_time(end); - G1MMUTracer::report_mmu(gcId, _time_slice, slice_time, _max_gc_time); + G1MMUTracer::report_mmu(_time_slice, slice_time, _max_gc_time); } // basically the _internal call does not remove expired entries diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1MMUTracker.hpp --- a/hotspot/src/share/vm/gc/g1/g1MMUTracker.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1MMUTracker.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -43,10 +43,10 @@ public: G1MMUTracker(double time_slice, double max_gc_time); - virtual void add_pause(double start, double end, const GCId& gcId) = 0; + virtual void add_pause(double start, double end) = 0; virtual double when_sec(double current_time, double pause_time) = 0; - double max_gc_time() { + double max_gc_time() const { return _max_gc_time; } @@ -127,7 +127,7 @@ public: G1MMUTrackerQueue(double time_slice, double max_gc_time); - virtual void add_pause(double start, double end, const GCId& gcId); + virtual void add_pause(double start, double end); virtual double when_sec(double current_time, double pause_time); }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp --- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -93,8 +93,10 @@ mark_sweep_phase2(); +#if defined(COMPILER2) || INCLUDE_JVMCI // Don't add any more derived pointers during phase3 - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); + DerivedPointerTable::set_active(false); +#endif mark_sweep_phase3(); @@ -121,7 +123,7 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - GCTraceTime tm("phase 1", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); + GCTraceTime tm("phase 1", G1Log::fine() && Verbose, true, gc_timer()); G1CollectedHeap* g1h = G1CollectedHeap::heap(); @@ -146,8 +148,7 @@ &GenMarkSweep::keep_alive, &GenMarkSweep::follow_stack_closure, NULL, - gc_timer(), - gc_tracer()->gc_id()); + gc_timer()); gc_tracer()->report_gc_reference_stats(stats); @@ -168,7 +169,9 @@ if (VerifyDuringGC) { HandleMark hm; // handle scope - COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif g1h->prepare_for_verify(); // Note: we can verify only the heap here. When an object is // marked, the previous value of the mark word (including @@ -200,7 +203,7 @@ // phase2, phase3 and phase4, but the ValidateMarkSweep live oops // tracking expects us to do so. See comment under phase4. - GCTraceTime tm("phase 2", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); + GCTraceTime tm("phase 2", G1Log::fine() && Verbose, true, gc_timer()); prepare_compaction(); } @@ -233,7 +236,7 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); // Adjust the pointers to reflect the new locations - GCTraceTime tm("phase 3", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); + GCTraceTime tm("phase 3", G1Log::fine() && Verbose, true, gc_timer()); // Need cleared claim bits for the roots processing ClassLoaderDataGraph::clear_claimed_marks(); @@ -294,7 +297,7 @@ // to use a higher index (saved from phase2) when verifying perm_gen. G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCTraceTime tm("phase 4", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); + GCTraceTime tm("phase 4", G1Log::fine() && Verbose, true, gc_timer()); G1SpaceCompactClosure blk; g1h->heap_region_iterate(&blk); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1OopClosures.cpp --- a/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -55,7 +55,7 @@ _worker_id = par_scan_state->worker_id(); assert(_worker_id < ParallelGCThreads, - err_msg("The given worker id %u must be less than the number of threads %u", _worker_id, ParallelGCThreads)); + "The given worker id %u must be less than the number of threads %u", _worker_id, ParallelGCThreads); } // Generate G1 specialized oop_oop_iterate functions. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp --- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -57,13 +57,13 @@ vmassert(page_size > 0, "Page size must be non-zero."); guarantee(is_ptr_aligned(rs.base(), page_size), - err_msg("Reserved space base " PTR_FORMAT " is not aligned to requested page size " SIZE_FORMAT, p2i(rs.base()), page_size)); + "Reserved space base " PTR_FORMAT " is not aligned to requested page size " SIZE_FORMAT, p2i(rs.base()), page_size); guarantee(is_size_aligned(used_size, os::vm_page_size()), - err_msg("Given used reserved space size needs to be OS page size aligned (%d bytes) but is " SIZE_FORMAT, os::vm_page_size(), used_size)); + "Given used reserved space size needs to be OS page size aligned (%d bytes) but is " SIZE_FORMAT, os::vm_page_size(), used_size); guarantee(used_size <= rs.size(), - err_msg("Used size of reserved space " SIZE_FORMAT " bytes is smaller than reservation at " SIZE_FORMAT " bytes", used_size, rs.size())); + "Used size of reserved space " SIZE_FORMAT " bytes is smaller than reservation at " SIZE_FORMAT " bytes", used_size, rs.size()); guarantee(is_size_aligned(rs.size(), page_size), - err_msg("Expected that the virtual space is size aligned, but " SIZE_FORMAT " is not aligned to page size " SIZE_FORMAT, rs.size(), page_size)); + "Expected that the virtual space is size aligned, but " SIZE_FORMAT " is not aligned to page size " SIZE_FORMAT, rs.size(), page_size); _low_boundary = rs.base(); _high_boundary = _low_boundary + used_size; @@ -137,23 +137,23 @@ bool G1PageBasedVirtualSpace::is_after_last_page(size_t index) const { guarantee(index <= _committed.size(), - err_msg("Given boundary page " SIZE_FORMAT " is beyond managed page count " SIZE_FORMAT, index, _committed.size())); + "Given boundary page " SIZE_FORMAT " is beyond managed page count " SIZE_FORMAT, index, _committed.size()); return index == _committed.size(); } void G1PageBasedVirtualSpace::commit_preferred_pages(size_t start, size_t num_pages) { vmassert(num_pages > 0, "No full pages to commit"); vmassert(start + num_pages <= _committed.size(), - err_msg("Tried to commit area from page " SIZE_FORMAT " to page " SIZE_FORMAT " " - "that is outside of managed space of " SIZE_FORMAT " pages", - start, start + num_pages, _committed.size())); + "Tried to commit area from page " SIZE_FORMAT " to page " SIZE_FORMAT " " + "that is outside of managed space of " SIZE_FORMAT " pages", + start, start + num_pages, _committed.size()); char* start_addr = page_start(start); size_t size = num_pages * _page_size; os::commit_memory_or_exit(start_addr, size, _page_size, _executable, err_msg("Failed to commit area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", - p2i(start_addr), p2i(start_addr + size), size)); + p2i(start_addr), p2i(start_addr + size), size)); } void G1PageBasedVirtualSpace::commit_tail() { @@ -162,14 +162,14 @@ char* const aligned_end_address = (char*)align_ptr_down(_high_boundary, _page_size); os::commit_memory_or_exit(aligned_end_address, _tail_size, os::vm_page_size(), _executable, err_msg("Failed to commit tail area from " PTR_FORMAT " to " PTR_FORMAT " of length " SIZE_FORMAT ".", - p2i(aligned_end_address), p2i(_high_boundary), _tail_size)); + p2i(aligned_end_address), p2i(_high_boundary), _tail_size)); } void G1PageBasedVirtualSpace::commit_internal(size_t start_page, size_t end_page) { guarantee(start_page < end_page, - err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + "Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page); guarantee(end_page <= _committed.size(), - err_msg("Given end page " SIZE_FORMAT " is beyond end of managed page amount of " SIZE_FORMAT, end_page, _committed.size())); + "Given end page " SIZE_FORMAT " is beyond end of managed page amount of " SIZE_FORMAT, end_page, _committed.size()); size_t pages = end_page - start_page; bool need_to_commit_tail = is_after_last_page(end_page) && is_last_page_partial(); @@ -195,7 +195,7 @@ void G1PageBasedVirtualSpace::pretouch_internal(size_t start_page, size_t end_page) { guarantee(start_page < end_page, - err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + "Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page); os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page)); } @@ -226,7 +226,7 @@ void G1PageBasedVirtualSpace::uncommit_internal(size_t start_page, size_t end_page) { guarantee(start_page < end_page, - err_msg("Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page)); + "Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page); char* start_addr = page_start(start_page); os::uncommit_memory(start_addr, pointer_delta(bounded_end_addr(end_page), start_addr, sizeof(char))); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -97,10 +97,10 @@ bool G1ParScanThreadState::verify_ref(narrowOop* ref) const { assert(ref != NULL, "invariant"); assert(UseCompressedOops, "sanity"); - assert(!has_partial_array_mask(ref), err_msg("ref=" PTR_FORMAT, p2i(ref))); + assert(!has_partial_array_mask(ref), "ref=" PTR_FORMAT, p2i(ref)); oop p = oopDesc::load_decode_heap_oop(ref); assert(_g1h->is_in_g1_reserved(p), - err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p))); + "ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p)); return true; } @@ -110,11 +110,11 @@ // Must be in the collection set--it's already been copied. oop p = clear_partial_array_mask(ref); assert(_g1h->obj_in_cs(p), - err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p))); + "ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p)); } else { oop p = oopDesc::load_decode_heap_oop(ref); assert(_g1h->is_in_g1_reserved(p), - err_msg("ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p))); + "ref=" PTR_FORMAT " p=" PTR_FORMAT, p2i(ref), p2i(p)); } return true; } @@ -147,8 +147,8 @@ size_t word_sz, AllocationContext_t const context, bool previous_plab_refill_failed) { - assert(state.is_in_cset_or_humongous(), err_msg("Unexpected state: " CSETSTATE_FORMAT, state.value())); - assert(dest->is_in_cset_or_humongous(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value())); + assert(state.is_in_cset_or_humongous(), "Unexpected state: " CSETSTATE_FORMAT, state.value()); + assert(dest->is_in_cset_or_humongous(), "Unexpected dest: " CSETSTATE_FORMAT, dest->value()); // Right now we only have two types of regions (young / old) so // let's keep the logic here simple. We can generalize it when necessary. @@ -177,7 +177,7 @@ return obj_ptr; } else { _old_gen_is_full = previous_plab_refill_failed; - assert(dest->is_old(), err_msg("Unexpected dest: " CSETSTATE_FORMAT, dest->value())); + assert(dest->is_old(), "Unexpected dest: " CSETSTATE_FORMAT, dest->value()); // no other space to try. return NULL; } @@ -359,8 +359,7 @@ } oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markOop m) { - assert(_g1h->obj_in_cs(old), - err_msg("Object " PTR_FORMAT " should be in the CSet", p2i(old))); + assert(_g1h->obj_in_cs(old), "Object " PTR_FORMAT " should be in the CSet", p2i(old)); oop forward_ptr = old->forward_to_atomic(old); if (forward_ptr == NULL) { @@ -383,9 +382,9 @@ // space for this object (old != forward_ptr) or they beat us in // self-forwarding it (old == forward_ptr). assert(old == forward_ptr || !_g1h->obj_in_cs(forward_ptr), - err_msg("Object " PTR_FORMAT " forwarded to: " PTR_FORMAT " " - "should not be in the CSet", - p2i(old), p2i(forward_ptr))); + "Object " PTR_FORMAT " forwarded to: " PTR_FORMAT " " + "should not be in the CSet", + p2i(old), p2i(forward_ptr)); return forward_ptr; } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -75,9 +75,9 @@ InCSetState dest(InCSetState original) const { assert(original.is_valid(), - err_msg("Original state invalid: " CSETSTATE_FORMAT, original.value())); + "Original state invalid: " CSETSTATE_FORMAT, original.value()); assert(_dest[original.value()].is_valid_gen(), - err_msg("Dest state is invalid: " CSETSTATE_FORMAT, _dest[original.value()].value())); + "Dest state is invalid: " CSETSTATE_FORMAT, _dest[original.value()].value()); return _dest[original.value()]; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -52,7 +52,7 @@ _g1h->set_humongous_is_live(obj); } else { assert(!in_cset_state.is_in_cset_or_humongous(), - err_msg("In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value())); + "In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value()); } assert(obj != NULL, "Must be"); @@ -82,7 +82,7 @@ // to-space object. int next_index = to_obj_array->length(); assert(0 <= next_index && next_index < length, - err_msg("invariant, next index: %d, length: %d", next_index, length)); + "invariant, next index: %d, length: %d", next_index, length); int start = next_index; int end = length; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp --- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -113,7 +113,7 @@ virtual void commit_regions(uint start_idx, size_t num_regions) { for (uint i = start_idx; i < start_idx + num_regions; i++) { - assert(!_commit_map.at(i), err_msg("Trying to commit storage at region %u that is already committed", i)); + assert(!_commit_map.at(i), "Trying to commit storage at region %u that is already committed", i); size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); bool zero_filled = false; @@ -128,7 +128,7 @@ virtual void uncommit_regions(uint start_idx, size_t num_regions) { for (uint i = start_idx; i < start_idx + num_regions; i++) { - assert(_commit_map.at(i), err_msg("Trying to uncommit storage at region %u that is not committed", i)); + assert(_commit_map.at(i), "Trying to uncommit storage at region %u that is not committed", i); size_t idx = region_idx_to_page_idx(i); uint old_refcount = _refcounts.get_by_index(idx); assert(old_refcount > 0, "must be"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1RemSet.cpp --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -413,11 +413,11 @@ bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i, bool check_for_refs_into_cset) { assert(_g1->is_in_exact(_ct_bs->addr_for(card_ptr)), - err_msg("Card at " PTR_FORMAT " index " SIZE_FORMAT " representing heap at " PTR_FORMAT " (%u) must be in committed heap", - p2i(card_ptr), - _ct_bs->index_for(_ct_bs->addr_for(card_ptr)), - p2i(_ct_bs->addr_for(card_ptr)), - _g1->addr_to_region(_ct_bs->addr_for(card_ptr)))); + "Card at " PTR_FORMAT " index " SIZE_FORMAT " representing heap at " PTR_FORMAT " (%u) must be in committed heap", + p2i(card_ptr), + _ct_bs->index_for(_ct_bs->addr_for(card_ptr)), + p2i(_ct_bs->addr_for(card_ptr)), + _g1->addr_to_region(_ct_bs->addr_for(card_ptr))); // If the card is no longer dirty, nothing to do. if (*card_ptr != CardTableModRefBS::dirty_card_val()) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp --- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -247,3 +247,52 @@ } } } + +void G1SATBCardTableModRefBS::write_ref_nmethod_post(oop* dst, nmethod* nm) { + oop obj = oopDesc::load_heap_oop(dst); + if (obj != NULL) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapRegion* hr = g1h->heap_region_containing(obj); + hr->add_strong_code_root(nm); + } +} + +class G1EnsureLastRefToRegion : public OopClosure { + G1CollectedHeap* _g1h; + HeapRegion* _hr; + oop* _dst; + + bool _value; +public: + G1EnsureLastRefToRegion(G1CollectedHeap* g1h, HeapRegion* hr, oop* dst) : + _g1h(g1h), _hr(hr), _dst(dst), _value(true) {} + + void do_oop(oop* p) { + if (_value && p != _dst) { + oop obj = oopDesc::load_heap_oop(p); + if (obj != NULL) { + HeapRegion* hr = _g1h->heap_region_containing(obj); + if (hr == _hr) { + // Another reference to the same region. + _value = false; + } + } + } + } + void do_oop(narrowOop* p) { ShouldNotReachHere(); } + bool value() const { return _value; } +}; + +void G1SATBCardTableModRefBS::write_ref_nmethod_pre(oop* dst, nmethod* nm) { + oop obj = oopDesc::load_heap_oop(dst); + if (obj != NULL) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapRegion* hr = g1h->heap_region_containing(obj); + G1EnsureLastRefToRegion ensure_last_ref(g1h, hr, dst); + nm->oops_do(&ensure_last_ref); + if (ensure_last_ref.value()) { + // Last reference to this region, remove the nmethod from the rset. + hr->remove_strong_code_root(nm); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp --- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -38,6 +38,7 @@ // snapshot-at-the-beginning marking. class G1SATBCardTableModRefBS: public CardTableModRefBS { + friend class VMStructs; protected: enum G1CardValues { g1_young_gen = CT_MR_BS_last_reserved << 1 @@ -122,6 +123,9 @@ jbyte val = _byte_map[card_index]; return (val & (clean_card_mask_val() | deferred_card_val())) == deferred_card_val(); } + virtual void write_ref_nmethod_pre(oop* dst, nmethod* nm); + virtual void write_ref_nmethod_post(oop* dst, nmethod* nm); + }; template<> diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/g1_globals.hpp --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,6 +26,7 @@ #define SHARE_VM_GC_G1_G1_GLOBALS_HPP #include "runtime/globals.hpp" +#include // for DBL_MAX // // Defines all globals flags used by the garbage-first compiler. // @@ -61,6 +62,7 @@ "update buffer processing info " \ "(0 means do not periodically generate this info); " \ "it also requires -XX:+G1SummarizeRSetStats") \ + range(0, max_intx) \ \ diagnostic(bool, G1TraceConcRefinement, false, \ "Trace G1 concurrent refinement") \ @@ -71,7 +73,7 @@ product(double, G1ConcMarkStepDurationMillis, 10.0, \ "Target duration of individual concurrent marking steps " \ "in milliseconds.") \ - range(1.0, (double)max_uintx) \ + range(1.0, DBL_MAX) \ \ product(intx, G1RefProcDrainInterval, 10, \ "The number of discovered reference objects to process before " \ @@ -89,9 +91,11 @@ \ product(size_t, G1SATBBufferSize, 1*K, \ "Number of entries in an SATB log buffer.") \ + range(1, max_uintx) \ \ develop(intx, G1SATBProcessCompletedThreshold, 20, \ "Number of completed buffers that triggers log processing.") \ + range(0, max_jint) \ \ product(uintx, G1SATBBufferEnqueueingThresholdPercent, 60, \ "Before enqueueing them, each mutator thread tries to do some " \ @@ -114,26 +118,31 @@ \ product(size_t, G1UpdateBufferSize, 256, \ "Size of an update buffer") \ + range(1, NOT_LP64(32*M) LP64_ONLY(1*G)) \ \ product(intx, G1ConcRefinementYellowZone, 0, \ "Number of enqueued update buffers that will " \ "trigger concurrent processing. Will be selected ergonomically " \ "by default.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementRedZone, 0, \ "Maximum number of enqueued update buffers before mutator " \ "threads start processing new ones instead of enqueueing them. " \ "Will be selected ergonomically by default. Zero will disable " \ "concurrent processing.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementGreenZone, 0, \ "The number of update buffers that are left in the queue by the " \ "concurrent processing threads. Will be selected ergonomically " \ "by default.") \ + range(0, max_intx) \ \ product(intx, G1ConcRefinementServiceIntervalMillis, 300, \ "The last concurrent refinement thread wakes up every " \ "specified number of milliseconds to do miscellaneous work.") \ + range(0, max_jint) \ \ product(intx, G1ConcRefinementThresholdStep, 0, \ "Each time the rset update queue increases by this amount " \ @@ -143,6 +152,7 @@ product(intx, G1RSetUpdatingPauseTimePercent, 10, \ "A target percentage of time that is allowed to be spend on " \ "process RS update buffers during the collection pause.") \ + range(0, 100) \ \ product(bool, G1UseAdaptiveConcRefinement, true, \ "Select green, yellow and red zones adaptively to meet the " \ @@ -158,18 +168,24 @@ \ develop(intx, G1RSetRegionEntriesBase, 256, \ "Max number of regions in a fine-grain table per MB.") \ + range(1, max_jint/wordSize) \ \ product(intx, G1RSetRegionEntries, 0, \ "Max number of regions for which we keep bitmaps." \ "Will be set ergonomically by default") \ + range(0, max_jint/wordSize) \ + constraint(G1RSetRegionEntriesConstraintFunc,AfterErgo) \ \ develop(intx, G1RSetSparseRegionEntriesBase, 4, \ "Max number of entries per region in a sparse table " \ "per MB.") \ + range(1, max_jint/wordSize) \ \ product(intx, G1RSetSparseRegionEntries, 0, \ "Max number of entries per region in a sparse table." \ "Will be set ergonomically by default.") \ + range(0, max_jint/wordSize) \ + constraint(G1RSetSparseRegionEntriesConstraintFunc,AfterErgo) \ \ develop(bool, G1RecordHRRSOops, false, \ "When true, record recent calls to rem set operations.") \ @@ -180,6 +196,7 @@ develop(intx, G1MaxVerifyFailures, -1, \ "The maximum number of verification failures to print. " \ "-1 means print all.") \ + range(-1, max_jint) \ \ develop(bool, G1ScrubRemSets, true, \ "When true, do RS scrubbing after cleanup.") \ @@ -193,11 +210,13 @@ develop(intx, G1YoungSurvRateNumRegionsSummary, 0, \ "the number of regions for which we'll print a surv rate " \ "summary.") \ + range(0, max_intx) \ + constraint(G1YoungSurvRateNumRegionsSummaryConstraintFunc,AfterErgo)\ \ product(uintx, G1ReservePercent, 10, \ "It determines the minimum reserve we should have in the heap " \ "to minimize the probability of promotion failure.") \ - range(0, 100) \ + range(0, 50) \ \ diagnostic(bool, G1PrintHeapRegions, false, \ "If set G1 will print information on which regions are being " \ @@ -215,10 +234,13 @@ \ product(size_t, G1HeapRegionSize, 0, \ "Size of the G1 regions.") \ + range(0, 32*M) \ + constraint(G1HeapRegionSizeConstraintFunc,AfterMemoryInit) \ \ product(uintx, G1ConcRefinementThreads, 0, \ "If non-0 is the number of parallel rem set update threads, " \ "otherwise the value is determined ergonomically.") \ + range(0, (max_jint-1)/wordSize) \ \ develop(bool, G1VerifyCTCleanup, false, \ "Verify card table cleanup.") \ @@ -226,6 +248,7 @@ product(size_t, G1RSetScanBlockSize, 64, \ "Size of a work unit of cards claimed by a worker thread" \ "during RSet scanning.") \ + range(1, max_uintx) \ \ develop(uintx, G1SecondaryFreeListAppendLength, 5, \ "The number of regions we will add to the secondary free list " \ @@ -262,6 +285,7 @@ experimental(uintx, G1NewSizePercent, 5, \ "Percentage (0-100) of the heap size to use as default " \ "minimum young gen size.") \ + range(0, 100) \ constraint(G1NewSizePercentConstraintFunc,AfterErgo) \ \ experimental(uintx, G1MixedGCLiveThresholdPercent, 85, \ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/heapRegion.cpp --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -165,7 +165,7 @@ assert(_end == orig_end(), "we should have already filtered out humongous regions"); assert(!in_collection_set(), - err_msg("Should not clear heap region %u in the collection set", hrm_index())); + "Should not clear heap region %u in the collection set", hrm_index()); set_allocation_context(AllocationContext::system()); set_young_index_in_cset(-1); @@ -292,9 +292,9 @@ record_timestamp(); assert(mr.end() == orig_end(), - err_msg("Given region end address " PTR_FORMAT " should match exactly " - "bottom plus one region size, i.e. " PTR_FORMAT, - p2i(mr.end()), p2i(orig_end()))); + "Given region end address " PTR_FORMAT " should match exactly " + "bottom plus one region size, i.e. " PTR_FORMAT, + p2i(mr.end()), p2i(orig_end())); } CompactibleSpace* HeapRegion::next_compaction_space() const { @@ -327,7 +327,7 @@ bool during_conc_mark, size_t marked_bytes) { assert(marked_bytes <= used(), - err_msg("marked: " SIZE_FORMAT " used: " SIZE_FORMAT, marked_bytes, used())); + "marked: " SIZE_FORMAT " used: " SIZE_FORMAT, marked_bytes, used()); _prev_top_at_mark_start = top(); _prev_marked_bytes = marked_bytes; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/heapRegion.hpp --- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -542,9 +542,9 @@ void set_containing_set(HeapRegionSetBase* containing_set) { assert((containing_set == NULL && _containing_set != NULL) || (containing_set != NULL && _containing_set == NULL), - err_msg("containing_set: " PTR_FORMAT " " - "_containing_set: " PTR_FORMAT, - p2i(containing_set), p2i(_containing_set))); + "containing_set: " PTR_FORMAT " " + "_containing_set: " PTR_FORMAT, + p2i(containing_set), p2i(_containing_set)); _containing_set = containing_set; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp --- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -132,10 +132,10 @@ } assert(ClassUnloadingWithConcurrentMark, - err_msg("All blocks should be objects if G1 Class Unloading isn't used. " - "HR: [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ") " - "addr: " PTR_FORMAT, - p2i(bottom()), p2i(top()), p2i(end()), p2i(addr))); + "All blocks should be objects if G1 Class Unloading isn't used. " + "HR: [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT ") " + "addr: " PTR_FORMAT, + p2i(bottom()), p2i(top()), p2i(end()), p2i(addr)); // Old regions' dead objects may have dead classes // We need to find the next live object in some other diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/heapRegionManager.cpp --- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -92,7 +92,7 @@ } void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) { - guarantee(num_regions >= 1, err_msg("Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start)); + guarantee(num_regions >= 1, "Need to specify at least one region to uncommit, tried to uncommit zero regions at %u", start); guarantee(_num_committed >= num_regions, "pre-condition"); // Print before uncommitting. @@ -132,7 +132,7 @@ _available_map.par_set_range(start, start + num_regions, BitMap::unknown_range); for (uint i = start; i < start + num_regions; i++) { - assert(is_available(i), err_msg("Just made region %u available but is apparently not.", i)); + assert(is_available(i), "Just made region %u available but is apparently not.", i); HeapRegion* hr = at(i); if (G1CollectedHeap::heap()->hr_printer()->is_active()) { G1CollectedHeap::heap()->hr_printer()->commit(hr->bottom(), hr->end()); @@ -213,8 +213,8 @@ HeapRegion* hr = _regions.get_by_index(i); // sanity check guarantee((!empty_only && !is_available(i)) || (is_available(i) && hr != NULL && hr->is_empty()), - err_msg("Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT - " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr))); + "Found region sequence starting at " UINT32_FORMAT ", length " SIZE_FORMAT + " that is not empty at " UINT32_FORMAT ". Hr is " PTR_FORMAT, found, num, i, p2i(hr)); } return found; } else { @@ -224,7 +224,7 @@ HeapRegion* HeapRegionManager::next_region_in_heap(const HeapRegion* r) const { guarantee(r != NULL, "Start region must be a valid region"); - guarantee(is_available(r->hrm_index()), err_msg("Trying to iterate starting from region %u which is not in the heap", r->hrm_index())); + guarantee(is_available(r->hrm_index()), "Trying to iterate starting from region %u which is not in the heap", r->hrm_index()); for (uint i = r->hrm_index() + 1; i < _allocated_heapregions_length; i++) { HeapRegion* hr = _regions.get_by_index(i); if (is_available(i)) { @@ -241,7 +241,7 @@ if (!is_available(i)) { continue; } - guarantee(at(i) != NULL, err_msg("Tried to access region %u that has a NULL HeapRegion*", i)); + guarantee(at(i) != NULL, "Tried to access region %u that has a NULL HeapRegion*", i); bool res = blk->doHeapRegion(at(i)); if (res) { blk->incomplete(); @@ -273,7 +273,7 @@ assert(!is_available(i), "just checking"); } assert(cur == max_length() || num_regions == 0 || is_available(cur), - err_msg("The region at the current position %u must be available or at the end of the heap.", cur)); + "The region at the current position %u must be available or at the end of the heap.", cur); #endif return num_regions; } @@ -374,8 +374,8 @@ assert(chr->is_continues_humongous(), "Must be humongous region"); assert(chr->humongous_start_region() == r, - err_msg("Must work on humongous continuation of the original start region " - PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr))); + "Must work on humongous continuation of the original start region " + PTR_FORMAT ", but is " PTR_FORMAT, p2i(r), p2i(chr)); assert(!hrclaimer->is_region_claimed(ch_index), "Must not have been claimed yet because claiming of humongous continuation first claims the start region"); @@ -440,9 +440,9 @@ void HeapRegionManager::shrink_at(uint index, size_t num_regions) { #ifdef ASSERT for (uint i = index; i < (index + num_regions); i++) { - assert(is_available(i), err_msg("Expected available region at index %u", i)); - assert(at(i)->is_empty(), err_msg("Expected empty region at index %u", i)); - assert(at(i)->is_free(), err_msg("Expected free region at index %u", i)); + assert(is_available(i), "Expected available region at index %u", i); + assert(at(i)->is_empty(), "Expected empty region at index %u", i); + assert(at(i)->is_free(), "Expected free region at index %u", i); } #endif uncommit_regions(index, num_regions); @@ -479,11 +479,11 @@ void HeapRegionManager::verify() { guarantee(length() <= _allocated_heapregions_length, - err_msg("invariant: _length: %u _allocated_length: %u", - length(), _allocated_heapregions_length)); + "invariant: _length: %u _allocated_length: %u", + length(), _allocated_heapregions_length); guarantee(_allocated_heapregions_length <= max_length(), - err_msg("invariant: _allocated_length: %u _max_length: %u", - _allocated_heapregions_length, max_length())); + "invariant: _allocated_length: %u _max_length: %u", + _allocated_heapregions_length, max_length()); bool prev_committed = true; uint num_committed = 0; @@ -495,12 +495,12 @@ } num_committed++; HeapRegion* hr = _regions.get_by_index(i); - guarantee(hr != NULL, err_msg("invariant: i: %u", i)); + guarantee(hr != NULL, "invariant: i: %u", i); guarantee(!prev_committed || hr->bottom() == prev_end, - err_msg("invariant i: %u " HR_FORMAT " prev_end: " PTR_FORMAT, - i, HR_FORMAT_PARAMS(hr), p2i(prev_end))); + "invariant i: %u " HR_FORMAT " prev_end: " PTR_FORMAT, + i, HR_FORMAT_PARAMS(hr), p2i(prev_end)); guarantee(hr->hrm_index() == i, - err_msg("invariant: i: %u hrm_index(): %u", i, hr->hrm_index())); + "invariant: i: %u hrm_index(): %u", i, hr->hrm_index()); // Asserts will fire if i is >= _length HeapWord* addr = hr->bottom(); guarantee(addr_to_region(addr) == hr, "sanity"); @@ -515,10 +515,10 @@ } } for (uint i = _allocated_heapregions_length; i < max_length(); i++) { - guarantee(_regions.get_by_index(i) == NULL, err_msg("invariant i: %u", i)); + guarantee(_regions.get_by_index(i) == NULL, "invariant i: %u", i); } - guarantee(num_committed == _num_committed, err_msg("Found %u committed regions, but should be %u", num_committed, _num_committed)); + guarantee(num_committed == _num_committed, "Found %u committed regions, but should be %u", num_committed, _num_committed); _free_list.verify(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/heapRegionManager.inline.hpp --- a/hotspot/src/share/vm/gc/g1/heapRegionManager.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,9 +31,9 @@ inline HeapRegion* HeapRegionManager::addr_to_region(HeapWord* addr) const { assert(addr < heap_end(), - err_msg("addr: " PTR_FORMAT " end: " PTR_FORMAT, p2i(addr), p2i(heap_end()))); + "addr: " PTR_FORMAT " end: " PTR_FORMAT, p2i(addr), p2i(heap_end())); assert(addr >= heap_bottom(), - err_msg("addr: " PTR_FORMAT " bottom: " PTR_FORMAT, p2i(addr), p2i(heap_bottom()))); + "addr: " PTR_FORMAT " bottom: " PTR_FORMAT, p2i(addr), p2i(heap_bottom())); HeapRegion* hr = _regions.get_by_address(addr); return hr; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp --- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -376,8 +376,8 @@ void FromCardCache::invalidate(uint start_idx, size_t new_num_regions) { guarantee((size_t)start_idx + new_num_regions <= max_uintx, - err_msg("Trying to invalidate beyond maximum region, from %u size " SIZE_FORMAT, - start_idx, new_num_regions)); + "Trying to invalidate beyond maximum region, from %u size " SIZE_FORMAT, + start_idx, new_num_regions); for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) { uint end_idx = (start_idx + (uint)new_num_regions); assert(end_idx <= _max_regions, "Must be within max."); @@ -1013,7 +1013,7 @@ card_index = _cur_region_card_offset + _cur_card_in_prt; guarantee(_cur_card_in_prt < HeapRegion::CardsPerRegion, - err_msg("Card index " SIZE_FORMAT " must be within the region", _cur_card_in_prt)); + "Card index " SIZE_FORMAT " must be within the region", _cur_card_in_prt); return true; } @@ -1182,8 +1182,8 @@ size_t min_prt_size = sizeof(void*) + dummy->bm()->size_in_words() * HeapWordSize; assert(dummy->mem_size() > min_prt_size, - err_msg("PerRegionTable memory usage is suspiciously small, only has " SIZE_FORMAT " bytes. " - "Should be at least " SIZE_FORMAT " bytes.", dummy->mem_size(), min_prt_size)); + "PerRegionTable memory usage is suspiciously small, only has " SIZE_FORMAT " bytes. " + "Should be at least " SIZE_FORMAT " bytes.", dummy->mem_size(), min_prt_size); free(dummy); guarantee(dummy->mem_size() == fl_mem_size(), "fl_mem_size() does not return the correct element size"); // try to reset the state diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/heapRegionSet.cpp --- a/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -37,14 +37,14 @@ #ifndef PRODUCT void HeapRegionSetBase::verify_region(HeapRegion* hr) { - assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrm_index())); - assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrm_index())); // currently we don't use these sets for young regions - assert(hr->is_humongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrm_index(), name())); - assert(hr->is_free() == regions_free(), err_msg("Wrong free state for region %u and set %s", hr->hrm_index(), name())); - assert(!hr->is_free() || hr->is_empty(), err_msg("Free region %u is not empty for set %s", hr->hrm_index(), name())); + assert(hr->containing_set() == this, "Inconsistent containing set for %u", hr->hrm_index()); + assert(!hr->is_young(), "Adding young region %u", hr->hrm_index()); // currently we don't use these sets for young regions + assert(hr->is_humongous() == regions_humongous(), "Wrong humongous state for region %u and set %s", hr->hrm_index(), name()); + assert(hr->is_free() == regions_free(), "Wrong free state for region %u and set %s", hr->hrm_index(), name()); + assert(!hr->is_free() || hr->is_empty(), "Free region %u is not empty for set %s", hr->hrm_index(), name()); assert(!hr->is_empty() || hr->is_free() || hr->is_archive(), - err_msg("Empty region %u is not free or archive for set %s", hr->hrm_index(), name())); - assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrm_index())); + "Empty region %u is not free or archive for set %s", hr->hrm_index(), name()); + assert(hr->rem_set()->verify_ready_for_par_iteration(), "Wrong iteration state %u", hr->hrm_index()); } #endif @@ -57,14 +57,14 @@ guarantee(( is_empty() && length() == 0 && total_capacity_bytes() == 0) || (!is_empty() && length() > 0 && total_capacity_bytes() > 0) , - hrs_ext_msg(this, "invariant")); + "%s", hrs_ext_msg(this, "invariant").buffer()); } void HeapRegionSetBase::verify_start() { // See comment in verify() about MT safety and verification. check_mt_safety(); assert(!_verify_in_progress, - hrs_ext_msg(this, "verification should not be in progress")); + "%s", hrs_ext_msg(this, "verification should not be in progress").buffer()); // Do the basic verification first before we do the checks over the regions. HeapRegionSetBase::verify(); @@ -76,7 +76,7 @@ // See comment in verify() about MT safety and verification. check_mt_safety(); assert(_verify_in_progress, - hrs_ext_msg(this, "verification should be in progress")); + "%s", hrs_ext_msg(this, "verification should be in progress").buffer()); _verify_in_progress = false; } @@ -151,7 +151,7 @@ #endif // ASSERT if (is_empty()) { - assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant")); + assert(length() == 0 && _tail == NULL, "%s", hrs_ext_msg(this, "invariant").buffer()); _head = from_list->_head; _tail = from_list->_tail; } else { @@ -198,8 +198,8 @@ void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) { check_mt_safety(); - assert(num_regions >= 1, hrs_ext_msg(this, "pre-condition")); - assert(!is_empty(), hrs_ext_msg(this, "pre-condition")); + assert(num_regions >= 1, "%s", hrs_ext_msg(this, "pre-condition").buffer()); + assert(!is_empty(), "%s", hrs_ext_msg(this, "pre-condition").buffer()); verify_optional(); DEBUG_ONLY(uint old_length = length();) @@ -212,22 +212,22 @@ HeapRegion* prev = curr->prev(); assert(count < num_regions, - hrs_err_msg("[%s] should not come across more regions " - "pending for removal than num_regions: %u", - name(), num_regions)); + "%s", hrs_err_msg("[%s] should not come across more regions " + "pending for removal than num_regions: %u", + name(), num_regions).buffer()); if (prev == NULL) { - assert(_head == curr, hrs_ext_msg(this, "invariant")); + assert(_head == curr, "%s", hrs_ext_msg(this, "invariant").buffer()); _head = next; } else { - assert(_head != curr, hrs_ext_msg(this, "invariant")); + assert(_head != curr, "%s", hrs_ext_msg(this, "invariant").buffer()); prev->set_next(next); } if (next == NULL) { - assert(_tail == curr, hrs_ext_msg(this, "invariant")); + assert(_tail == curr, "%s", hrs_ext_msg(this, "invariant").buffer()); _tail = prev; } else { - assert(_tail != curr, hrs_ext_msg(this, "invariant")); + assert(_tail != curr, "%s", hrs_ext_msg(this, "invariant").buffer()); next->set_prev(prev); } if (_last = curr) { @@ -243,12 +243,12 @@ } assert(count == num_regions, - hrs_err_msg("[%s] count: %u should be == num_regions: %u", - name(), count, num_regions)); + "%s", hrs_err_msg("[%s] count: %u should be == num_regions: %u", + name(), count, num_regions).buffer()); assert(length() + num_regions == old_length, - hrs_err_msg("[%s] new length should be consistent " - "new length: %u old length: %u num_regions: %u", - name(), length(), old_length, num_regions)); + "%s", hrs_err_msg("[%s] new length should be consistent " + "new length: %u old length: %u num_regions: %u", + name(), length(), old_length, num_regions).buffer()); verify_optional(); } @@ -305,8 +305,8 @@ count++; guarantee(count < _unrealistically_long_length, - hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: " PTR_FORMAT " prev0: " PTR_FORMAT " " "prev1: " PTR_FORMAT " length: %u", - name(), count, p2i(curr), p2i(prev0), p2i(prev1), length())); + "%s", hrs_err_msg("[%s] the calculated length: %u seems very long, is there maybe a cycle? curr: " PTR_FORMAT " prev0: " PTR_FORMAT " " "prev1: " PTR_FORMAT " length: %u", + name(), count, p2i(curr), p2i(prev0), p2i(prev1), length()).buffer()); if (curr->next() != NULL) { guarantee(curr->next()->prev() == curr, "Next or prev pointers messed up"); @@ -321,11 +321,11 @@ curr = curr->next(); } - guarantee(_tail == prev0, err_msg("Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index())); + guarantee(_tail == prev0, "Expected %s to end with %u but it ended with %u.", name(), _tail->hrm_index(), prev0->hrm_index()); guarantee(_tail == NULL || _tail->next() == NULL, "_tail should not have a next"); - guarantee(length() == count, err_msg("%s count mismatch. Expected %u, actual %u.", name(), length(), count)); - guarantee(total_capacity_bytes() == capacity, err_msg("%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, - name(), total_capacity_bytes(), capacity)); + guarantee(length() == count, "%s count mismatch. Expected %u, actual %u.", name(), length(), count); + guarantee(total_capacity_bytes() == capacity, "%s capacity mismatch. Expected " SIZE_FORMAT ", actual " SIZE_FORMAT, + name(), total_capacity_bytes(), capacity); } // Note on the check_mt_safety() methods below: diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp --- a/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,9 +29,9 @@ inline void HeapRegionSetBase::add(HeapRegion* hr) { check_mt_safety(); - assert(hr->containing_set() == NULL, hrs_ext_msg(this, "should not already have a containing set %u")); - assert(hr->next() == NULL, hrs_ext_msg(this, "should not already be linked")); - assert(hr->prev() == NULL, hrs_ext_msg(this, "should not already be linked")); + assert(hr->containing_set() == NULL, "%s", hrs_ext_msg(this, "should not already have a containing set %u").buffer()); + assert(hr->next() == NULL, "%s", hrs_ext_msg(this, "should not already be linked").buffer()); + assert(hr->prev() == NULL, "%s", hrs_ext_msg(this, "should not already be linked").buffer()); _count.increment(1u, hr->capacity()); hr->set_containing_set(this); @@ -41,18 +41,18 @@ inline void HeapRegionSetBase::remove(HeapRegion* hr) { check_mt_safety(); verify_region(hr); - assert(hr->next() == NULL, hrs_ext_msg(this, "should already be unlinked")); - assert(hr->prev() == NULL, hrs_ext_msg(this, "should already be unlinked")); + assert(hr->next() == NULL, "%s", hrs_ext_msg(this, "should already be unlinked").buffer()); + assert(hr->prev() == NULL, "%s", hrs_ext_msg(this, "should already be unlinked").buffer()); hr->set_containing_set(NULL); - assert(_count.length() > 0, hrs_ext_msg(this, "pre-condition")); + assert(_count.length() > 0, "%s", hrs_ext_msg(this, "pre-condition").buffer()); _count.decrement(1u, hr->capacity()); } inline void FreeRegionList::add_ordered(HeapRegion* hr) { assert((length() == 0 && _head == NULL && _tail == NULL && _last == NULL) || (length() > 0 && _head != NULL && _tail != NULL), - hrs_ext_msg(this, "invariant")); + "%s", hrs_ext_msg(this, "invariant").buffer()); // add() will verify the region and check mt safety. add(hr); @@ -129,7 +129,7 @@ return NULL; } assert(length() > 0 && _head != NULL && _tail != NULL, - hrs_ext_msg(this, "invariant")); + "%s", hrs_ext_msg(this, "invariant").buffer()); HeapRegion* hr; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/heapRegionType.hpp --- a/hotspot/src/share/vm/gc/g1/heapRegionType.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/heapRegionType.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -28,7 +28,7 @@ #include "memory/allocation.hpp" #define hrt_assert_is_valid(tag) \ - assert(is_valid((tag)), err_msg("invalid HR type: %u", (uint) (tag))) + assert(is_valid((tag)), "invalid HR type: %u", (uint) (tag)) class HeapRegionType VALUE_OBJ_CLASS_SPEC { private: @@ -97,8 +97,7 @@ hrt_assert_is_valid(tag); hrt_assert_is_valid(before); hrt_assert_is_valid(_tag); - assert(_tag == before, - err_msg("HR tag: %u, expected: %u new tag; %u", _tag, before, tag)); + assert(_tag == before, "HR tag: %u, expected: %u new tag; %u", _tag, before, tag); _tag = tag; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/satbQueue.cpp --- a/hotspot/src/share/vm/gc/g1/satbQueue.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/satbQueue.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -77,16 +77,16 @@ inline bool requires_marking(const void* entry, G1CollectedHeap* heap) { // Includes rejection of NULL pointers. assert(heap->is_in_reserved(entry), - err_msg("Non-heap pointer in SATB buffer: " PTR_FORMAT, p2i(entry))); + "Non-heap pointer in SATB buffer: " PTR_FORMAT, p2i(entry)); HeapRegion* region = heap->heap_region_containing_raw(entry); - assert(region != NULL, err_msg("No region for " PTR_FORMAT, p2i(entry))); + assert(region != NULL, "No region for " PTR_FORMAT, p2i(entry)); if (entry >= region->next_top_at_mark_start()) { return false; } assert(((oop)entry)->is_oop(true /* ignore mark word */), - err_msg("Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry))); + "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry)); return true; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp --- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,6 +26,7 @@ #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/shared/gcId.hpp" #include "gc/g1/g1Log.hpp" #include "gc/g1/vm_operations_g1.hpp" #include "gc/shared/gcTimer.hpp" @@ -66,8 +67,8 @@ _should_retry_gc(false), _old_marking_cycles_completed_before(0) { guarantee(target_pause_time_ms > 0.0, - err_msg("target_pause_time_ms = %1.6lf should be positive", - target_pause_time_ms)); + "target_pause_time_ms = %1.6lf should be positive", + target_pause_time_ms); _gc_cause = gc_cause; } @@ -227,7 +228,8 @@ void VM_CGC_Operation::doit() { TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCTraceTime t(_printGCMessage, G1Log::fine(), true, g1h->gc_timer_cm(), g1h->concurrent_mark()->concurrent_gc_id()); + GCIdMark gc_id_mark(_gc_id); + GCTraceTime t(_printGCMessage, G1Log::fine(), true, g1h->gc_timer_cm()); IsGCActiveMark x; _cl->do_void(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp --- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,6 +26,7 @@ #define SHARE_VM_GC_G1_VM_OPERATIONS_G1_HPP #include "gc/g1/g1AllocationContext.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/vmGCOperations.hpp" // VM_operations for the G1 collector. @@ -104,6 +105,7 @@ VoidClosure* _cl; const char* _printGCMessage; bool _needs_pll; + uint _gc_id; protected: // java.lang.ref.Reference support @@ -112,7 +114,7 @@ public: VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg, bool needs_pll) - : _cl(cl), _printGCMessage(printGCMsg), _needs_pll(needs_pll) { } + : _cl(cl), _printGCMessage(printGCMsg), _needs_pll(needs_pll), _gc_id(GCId::current()) { } virtual VMOp_Type type() const { return VMOp_CGC_Operation; } virtual void doit(); virtual bool doit_prologue(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp --- a/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -285,7 +285,7 @@ while (p < to) { Prefetch::write(p, interval); oop m = oop(p); - assert(m->is_oop_or_null(), err_msg("Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m))); + assert(m->is_oop_or_null(), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); pm->push_contents(m); p += m->size(); } @@ -293,7 +293,7 @@ } else { while (p < to) { oop m = oop(p); - assert(m->is_oop_or_null(), err_msg("Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m))); + assert(m->is_oop_or_null(), "Expected an oop or NULL for header field at " PTR_FORMAT, p2i(m)); pm->push_contents(m); p += m->size(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp --- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,6 +26,7 @@ #include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/gcTaskThread.hpp" #include "gc/shared/adaptiveSizePolicy.hpp" +#include "gc/shared/gcId.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "runtime/mutex.hpp" @@ -48,8 +49,8 @@ case ordinary_task: result = "ordinary task"; break; - case barrier_task: - result = "barrier task"; + case wait_for_barrier_task: + result = "wait for barrier task"; break; case noop_task: result = "noop task"; @@ -61,33 +62,24 @@ return result; }; -GCTask::GCTask() : - _kind(Kind::ordinary_task), - _affinity(GCTaskManager::sentinel_worker()){ - initialize(); +GCTask::GCTask() { + initialize(Kind::ordinary_task, GCId::current()); } -GCTask::GCTask(Kind::kind kind) : - _kind(kind), - _affinity(GCTaskManager::sentinel_worker()) { - initialize(); +GCTask::GCTask(Kind::kind kind) { + initialize(kind, GCId::current()); } -GCTask::GCTask(uint affinity) : - _kind(Kind::ordinary_task), - _affinity(affinity) { - initialize(); +GCTask::GCTask(Kind::kind kind, uint gc_id) { + initialize(kind, gc_id); } -GCTask::GCTask(Kind::kind kind, uint affinity) : - _kind(kind), - _affinity(affinity) { - initialize(); -} - -void GCTask::initialize() { +void GCTask::initialize(Kind::kind kind, uint gc_id) { + _kind = kind; + _affinity = GCTaskManager::sentinel_worker(); _older = NULL; _newer = NULL; + _gc_id = gc_id; } void GCTask::destruct() { @@ -378,16 +370,7 @@ GCTaskManager::GCTaskManager(uint workers) : _workers(workers), _active_workers(0), - _idle_workers(0), - _ndc(NULL) { - initialize(); -} - -GCTaskManager::GCTaskManager(uint workers, NotifyDoneClosure* ndc) : - _workers(workers), - _active_workers(0), - _idle_workers(0), - _ndc(ndc) { + _idle_workers(0) { initialize(); } @@ -404,7 +387,6 @@ GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap(); _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock()); _noop_task = NoopGCTask::create_on_c_heap(); - _idle_inactive_task = WaitForBarrierGCTask::create_on_c_heap(); _resource_flag = NEW_C_HEAP_ARRAY(bool, workers(), mtGC); { // Set up worker threads. @@ -437,7 +419,6 @@ } reset_delivered_tasks(); reset_completed_tasks(); - reset_noop_tasks(); reset_barriers(); reset_emptied_queue(); for (uint s = 0; s < workers(); s += 1) { @@ -450,8 +431,6 @@ assert(queue()->is_empty(), "still have queued work"); NoopGCTask::destroy(_noop_task); _noop_task = NULL; - WaitForBarrierGCTask::destroy(_idle_inactive_task); - _idle_inactive_task = NULL; if (_thread != NULL) { for (uint i = 0; i < workers(); i += 1) { GCTaskThread::destroy(thread(i)); @@ -483,9 +462,9 @@ Threads::number_of_non_daemon_threads()); assert(!all_workers_active() || active_workers() == ParallelGCThreads, - err_msg("all_workers_active() is incorrect: " - "active %d ParallelGCThreads %u", active_workers(), - ParallelGCThreads)); + "all_workers_active() is incorrect: " + "active %d ParallelGCThreads %u", active_workers(), + ParallelGCThreads); if (TraceDynamicGCThreads) { gclog_or_tty->print_cr("GCTaskManager::set_active_gang(): " "all_workers_active() %d workers %d " @@ -507,7 +486,7 @@ // the GCTaskManager's monitor so that the "more_inactive_workers" // count is correct. MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); - _idle_inactive_task->set_should_wait(true); + _wait_helper.set_should_wait(true); // active_workers are a number being requested. idle_workers // are the number currently idle. If all the workers are being // requested to be active but some are already idle, reduce @@ -550,7 +529,7 @@ { MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); - _idle_inactive_task->set_should_wait(false); + _wait_helper.set_should_wait(false); monitor()->notify_all(); // Release monitor } @@ -671,7 +650,6 @@ // Just hand back a Noop task, // in case someone wanted us to release resources, or whatever. result = noop_task(); - increment_noop_tasks(); } assert(result != NULL, "shouldn't have null task"); if (TraceGCTaskManager) { @@ -706,11 +684,6 @@ if (TraceGCTaskManager) { tty->print_cr(" GCTaskManager::note_completion(%u) done", which); } - // Notify client that we are done. - NotifyDoneClosure* ndc = notify_done_closure(); - if (ndc != NULL) { - ndc->notify(this); - } } if (TraceGCTaskManager) { tty->print_cr(" GCTaskManager::note_completion(%u) (%s)->notify_all", @@ -751,7 +724,7 @@ } void GCTaskManager::release_all_resources() { - // If you want this to be done atomically, do it in a BarrierGCTask. + // If you want this to be done atomically, do it in a WaitForBarrierGCTask. for (uint i = 0; i < workers(); i += 1) { set_resource_flag(i, true); } @@ -813,25 +786,22 @@ // NoopGCTask // -NoopGCTask* NoopGCTask::create() { - NoopGCTask* result = new NoopGCTask(false); - return result; -} - NoopGCTask* NoopGCTask::create_on_c_heap() { - NoopGCTask* result = new(ResourceObj::C_HEAP, mtGC) NoopGCTask(true); + NoopGCTask* result = new(ResourceObj::C_HEAP, mtGC) NoopGCTask(); return result; } void NoopGCTask::destroy(NoopGCTask* that) { if (that != NULL) { that->destruct(); - if (that->is_c_heap_obj()) { - FreeHeap(that); - } + FreeHeap(that); } } +// This task should never be performing GC work that require +// a valid GC id. +NoopGCTask::NoopGCTask() : GCTask(GCTask::Kind::noop_task, GCId::undefined()) { } + void NoopGCTask::destruct() { // This has to know it's superclass structure, just like the constructor. this->GCTask::destruct(); @@ -857,12 +827,12 @@ } void IdleGCTask::do_it(GCTaskManager* manager, uint which) { - WaitForBarrierGCTask* wait_for_task = manager->idle_inactive_task(); + WaitHelper* wait_helper = manager->wait_helper(); if (TraceGCTaskManager) { tty->print_cr("[" INTPTR_FORMAT "]" " IdleGCTask:::do_it()" " should_wait: %s", - p2i(this), wait_for_task->should_wait() ? "true" : "false"); + p2i(this), wait_helper->should_wait() ? "true" : "false"); } MutexLockerEx ml(manager->monitor(), Mutex::_no_safepoint_check_flag); if (TraceDynamicGCThreads) { @@ -871,7 +841,7 @@ // Increment has to be done when the idle tasks are created. // manager->increment_idle_workers(); manager->monitor()->notify_all(); - while (wait_for_task->should_wait()) { + while (wait_helper->should_wait()) { if (TraceGCTaskManager) { tty->print_cr("[" INTPTR_FORMAT "]" " IdleGCTask::do_it()" @@ -888,7 +858,7 @@ tty->print_cr("[" INTPTR_FORMAT "]" " IdleGCTask::do_it() returns" " should_wait: %s", - p2i(this), wait_for_task->should_wait() ? "true" : "false"); + p2i(this), wait_helper->should_wait() ? "true" : "false"); } // Release monitor(). } @@ -909,140 +879,52 @@ } // -// BarrierGCTask +// WaitForBarrierGCTask // - -void BarrierGCTask::do_it(GCTaskManager* manager, uint which) { - // Wait for this to be the only busy worker. - // ??? I thought of having a StackObj class - // whose constructor would grab the lock and come to the barrier, - // and whose destructor would release the lock, - // but that seems like too much mechanism for two lines of code. - MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); - do_it_internal(manager, which); - // Release manager->lock(). +WaitForBarrierGCTask* WaitForBarrierGCTask::create() { + WaitForBarrierGCTask* result = new WaitForBarrierGCTask(); + return result; } -void BarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) { +WaitForBarrierGCTask::WaitForBarrierGCTask() : GCTask(GCTask::Kind::wait_for_barrier_task) { } + +void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) { + if (that != NULL) { + if (TraceGCTaskManager) { + tty->print_cr("[" INTPTR_FORMAT "] WaitForBarrierGCTask::destroy()", p2i(that)); + } + that->destruct(); + } +} + +void WaitForBarrierGCTask::destruct() { + if (TraceGCTaskManager) { + tty->print_cr("[" INTPTR_FORMAT "] WaitForBarrierGCTask::destruct()", p2i(this)); + } + this->GCTask::destruct(); + // Clean up that should be in the destructor, + // except that ResourceMarks don't call destructors. + _wait_helper.release_monitor(); +} + +void WaitForBarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) { // Wait for this to be the only busy worker. assert(manager->monitor()->owned_by_self(), "don't own the lock"); assert(manager->is_blocked(), "manager isn't blocked"); while (manager->busy_workers() > 1) { if (TraceGCTaskManager) { - tty->print_cr("BarrierGCTask::do_it(%u) waiting on %u workers", + tty->print_cr("WaitForBarrierGCTask::do_it(%u) waiting on %u workers", which, manager->busy_workers()); } manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0); } } -void BarrierGCTask::destruct() { - this->GCTask::destruct(); - // Nothing else to do. -} - -// -// ReleasingBarrierGCTask -// - -void ReleasingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { - MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); - do_it_internal(manager, which); - manager->release_all_resources(); - // Release manager->lock(). -} - -void ReleasingBarrierGCTask::destruct() { - this->BarrierGCTask::destruct(); - // Nothing else to do. -} - -// -// NotifyingBarrierGCTask -// - -void NotifyingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { - MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); - do_it_internal(manager, which); - NotifyDoneClosure* ndc = notify_done_closure(); - if (ndc != NULL) { - ndc->notify(manager); - } - // Release manager->lock(). -} - -void NotifyingBarrierGCTask::destruct() { - this->BarrierGCTask::destruct(); - // Nothing else to do. -} - -// -// WaitForBarrierGCTask -// -WaitForBarrierGCTask* WaitForBarrierGCTask::create() { - WaitForBarrierGCTask* result = new WaitForBarrierGCTask(false); - return result; -} - -WaitForBarrierGCTask* WaitForBarrierGCTask::create_on_c_heap() { - WaitForBarrierGCTask* result = - new (ResourceObj::C_HEAP, mtGC) WaitForBarrierGCTask(true); - return result; -} - -WaitForBarrierGCTask::WaitForBarrierGCTask(bool on_c_heap) : - _is_c_heap_obj(on_c_heap) { - _monitor = MonitorSupply::reserve(); - set_should_wait(true); - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::WaitForBarrierGCTask()" - " monitor: " INTPTR_FORMAT, - p2i(this), p2i(monitor())); - } -} - -void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) { - if (that != NULL) { - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::destroy()" - " is_c_heap_obj: %s" - " monitor: " INTPTR_FORMAT, - p2i(that), - that->is_c_heap_obj() ? "true" : "false", - p2i(that->monitor())); - } - that->destruct(); - if (that->is_c_heap_obj()) { - FreeHeap(that); - } - } -} - -void WaitForBarrierGCTask::destruct() { - assert(monitor() != NULL, "monitor should not be NULL"); - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::destruct()" - " monitor: " INTPTR_FORMAT, - p2i(this), p2i(monitor())); - } - this->BarrierGCTask::destruct(); - // Clean up that should be in the destructor, - // except that ResourceMarks don't call destructors. - if (monitor() != NULL) { - MonitorSupply::release(monitor()); - } - _monitor = (Monitor*) 0xDEAD000F; -} - void WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) { if (TraceGCTaskManager) { tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::do_it() waiting for idle" - " monitor: " INTPTR_FORMAT, - p2i(this), p2i(monitor())); + " WaitForBarrierGCTask::do_it() waiting for idle", + p2i(this)); } { // First, wait for the barrier to arrive. @@ -1050,24 +932,30 @@ do_it_internal(manager, which); // Release manager->lock(). } - { - // Then notify the waiter. - MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); - set_should_wait(false); - // Waiter doesn't miss the notify in the wait_for method - // since it checks the flag after grabbing the monitor. - if (TraceGCTaskManager) { - tty->print_cr("[" INTPTR_FORMAT "]" - " WaitForBarrierGCTask::do_it()" - " [" INTPTR_FORMAT "] (%s)->notify_all()", - p2i(this), p2i(monitor()), monitor()->name()); - } - monitor()->notify_all(); - // Release monitor(). + // Then notify the waiter. + _wait_helper.notify(); +} + +WaitHelper::WaitHelper() : _should_wait(true), _monitor(MonitorSupply::reserve()) { + if (TraceGCTaskManager) { + tty->print_cr("[" INTPTR_FORMAT "]" + " WaitHelper::WaitHelper()" + " monitor: " INTPTR_FORMAT, + p2i(this), p2i(monitor())); } } -void WaitForBarrierGCTask::wait_for(bool reset) { +void WaitHelper::release_monitor() { + assert(_monitor != NULL, ""); + MonitorSupply::release(_monitor); + _monitor = NULL; +} + +WaitHelper::~WaitHelper() { + release_monitor(); +} + +void WaitHelper::wait_for(bool reset) { if (TraceGCTaskManager) { tty->print_cr("[" INTPTR_FORMAT "]" " WaitForBarrierGCTask::wait_for()" @@ -1100,6 +988,20 @@ } } +void WaitHelper::notify() { + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); + set_should_wait(false); + // Waiter doesn't miss the notify in the wait_for method + // since it checks the flag after grabbing the monitor. + if (TraceGCTaskManager) { + tty->print_cr("[" INTPTR_FORMAT "]" + " WaitForBarrierGCTask::do_it()" + " [" INTPTR_FORMAT "] (%s)->notify_all()", + p2i(this), p2i(monitor()), monitor()->name()); + } + monitor()->notify_all(); +} + Mutex* MonitorSupply::_lock = NULL; GrowableArray* MonitorSupply::_freelist = NULL; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp --- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -38,12 +38,8 @@ class GCTaskQueue; class SynchronizedGCTaskQueue; class GCTaskManager; -class NotifyDoneClosure; // Some useful subclasses of GCTask. You can also make up your own. class NoopGCTask; -class BarrierGCTask; -class ReleasingBarrierGCTask; -class NotifyingBarrierGCTask; class WaitForBarrierGCTask; class IdleGCTask; // A free list of Monitor*'s. @@ -64,7 +60,7 @@ enum kind { unknown_task, ordinary_task, - barrier_task, + wait_for_barrier_task, noop_task, idle_task }; @@ -72,13 +68,16 @@ }; private: // Instance state. - const Kind::kind _kind; // For runtime type checking. - const uint _affinity; // Which worker should run task. + Kind::kind _kind; // For runtime type checking. + uint _affinity; // Which worker should run task. GCTask* _newer; // Tasks are on doubly-linked ... GCTask* _older; // ... lists. + uint _gc_id; // GC Id to use for the thread that executes this task public: virtual char* name() { return (char *)"task"; } + uint gc_id() { return _gc_id; } + // Abstract do_it method virtual void do_it(GCTaskManager* manager, uint which) = 0; // Accessors @@ -105,7 +104,7 @@ return kind()==Kind::ordinary_task; } bool is_barrier_task() const { - return kind()==Kind::barrier_task; + return kind()==Kind::wait_for_barrier_task; } bool is_noop_task() const { return kind()==Kind::noop_task; @@ -120,17 +119,14 @@ GCTask(); // A GCTask of a particular kind, usually barrier or noop. GCTask(Kind::kind kind); - // An ordinary GCTask with an affinity. - GCTask(uint affinity); - // A GCTask of a particular kind, with and affinity. - GCTask(Kind::kind kind, uint affinity); + GCTask(Kind::kind kind, uint gc_id); // We want a virtual destructor because virtual methods, // but since ResourceObj's don't have their destructors // called, we don't have one at all. Instead we have // this method, which gets called by subclasses to clean up. virtual void destruct(); // Methods. - void initialize(); + void initialize(Kind::kind kind, uint gc_id); }; // A doubly-linked list of GCTasks. @@ -276,21 +272,26 @@ ~SynchronizedGCTaskQueue(); }; -// This is an abstract base class for getting notifications -// when a GCTaskManager is done. -class NotifyDoneClosure : public CHeapObj { -public: - // The notification callback method. - virtual void notify(GCTaskManager* manager) = 0; -protected: - // Constructor. - NotifyDoneClosure() { - // Nothing to do. +class WaitHelper VALUE_OBJ_CLASS_SPEC { + private: + Monitor* _monitor; + volatile bool _should_wait; + public: + WaitHelper(); + ~WaitHelper(); + void wait_for(bool reset); + void notify(); + void set_should_wait(bool value) { + _should_wait = value; } - // Virtual destructor because virtual methods. - virtual ~NotifyDoneClosure() { - // Nothing to do. + + Monitor* monitor() const { + return _monitor; } + bool should_wait() const { + return _should_wait; + } + void release_monitor(); }; // Dynamic number of GC threads @@ -365,7 +366,6 @@ friend class IdleGCTask; private: // Instance state. - NotifyDoneClosure* _ndc; // Notify on completion. const uint _workers; // Number of workers. Monitor* _monitor; // Notification of changes. SynchronizedGCTaskQueue* _queue; // Queue of tasks. @@ -379,17 +379,13 @@ uint _barriers; // Count of barrier tasks. uint _emptied_queue; // Times we emptied the queue. NoopGCTask* _noop_task; // The NoopGCTask instance. - uint _noop_tasks; // Count of noop tasks. - WaitForBarrierGCTask* _idle_inactive_task;// Task for inactive workers + WaitHelper _wait_helper; // Used by inactive worker volatile uint _idle_workers; // Number of idled workers public: // Factory create and destroy methods. static GCTaskManager* create(uint workers) { return new GCTaskManager(workers); } - static GCTaskManager* create(uint workers, NotifyDoneClosure* ndc) { - return new GCTaskManager(workers, ndc); - } static void destroy(GCTaskManager* that) { if (that != NULL) { delete that; @@ -409,8 +405,8 @@ Monitor * lock() const { return _monitor; } - WaitForBarrierGCTask* idle_inactive_task() { - return _idle_inactive_task; + WaitHelper* wait_helper() { + return &_wait_helper; } // Methods. // Add the argument task to be run. @@ -452,8 +448,6 @@ // Constructors. Clients use factory, but there might be subclasses. // Create a GCTaskManager with the appropriate number of workers. GCTaskManager(uint workers); - // Create a GCTaskManager that calls back when there's no more work. - GCTaskManager(uint workers, NotifyDoneClosure* ndc); // Make virtual if necessary. ~GCTaskManager(); // Accessors. @@ -469,9 +463,6 @@ // Sets the number of threads that will be used in a collection void set_active_gang(); - NotifyDoneClosure* notify_done_closure() const { - return _ndc; - } SynchronizedGCTaskQueue* queue() const { return _queue; } @@ -540,17 +531,6 @@ void reset_emptied_queue() { _emptied_queue = 0; } - // Count of the number of noop tasks we've handed out, - // e.g., to handle resource release requests. - uint noop_tasks() const { - return _noop_tasks; - } - void increment_noop_tasks() { - _noop_tasks += 1; - } - void reset_noop_tasks() { - _noop_tasks = 0; - } void increment_idle_workers() { _idle_workers++; } @@ -575,11 +555,8 @@ // A noop task that does nothing, // except take us around the GCTaskThread loop. class NoopGCTask : public GCTask { -private: - const bool _is_c_heap_obj; // Is this a CHeapObj? public: // Factory create and destroy methods. - static NoopGCTask* create(); static NoopGCTask* create_on_c_heap(); static void destroy(NoopGCTask* that); @@ -590,147 +567,39 @@ } protected: // Constructor. - NoopGCTask(bool on_c_heap) : - GCTask(GCTask::Kind::noop_task), - _is_c_heap_obj(on_c_heap) { - // Nothing to do. - } - // Destructor-like method. - void destruct(); - // Accessors. - bool is_c_heap_obj() const { - return _is_c_heap_obj; - } -}; - -// A BarrierGCTask blocks other tasks from starting, -// and waits until it is the only task running. -class BarrierGCTask : public GCTask { -public: - // Factory create and destroy methods. - static BarrierGCTask* create() { - return new BarrierGCTask(); - } - static void destroy(BarrierGCTask* that) { - if (that != NULL) { - that->destruct(); - delete that; - } - } - // Methods from GCTask. - void do_it(GCTaskManager* manager, uint which); -protected: - // Constructor. Clients use factory, but there might be subclasses. - BarrierGCTask() : - GCTask(GCTask::Kind::barrier_task) { - // Nothing to do. - } - // Destructor-like method. - void destruct(); - - virtual char* name() { return (char *)"barrier task"; } - // Methods. - // Wait for this to be the only task running. - void do_it_internal(GCTaskManager* manager, uint which); -}; - -// A ReleasingBarrierGCTask is a BarrierGCTask -// that tells all the tasks to release their resource areas. -class ReleasingBarrierGCTask : public BarrierGCTask { -public: - // Factory create and destroy methods. - static ReleasingBarrierGCTask* create() { - return new ReleasingBarrierGCTask(); - } - static void destroy(ReleasingBarrierGCTask* that) { - if (that != NULL) { - that->destruct(); - delete that; - } - } - // Methods from GCTask. - void do_it(GCTaskManager* manager, uint which); -protected: - // Constructor. Clients use factory, but there might be subclasses. - ReleasingBarrierGCTask() : - BarrierGCTask() { - // Nothing to do. - } + NoopGCTask(); // Destructor-like method. void destruct(); }; -// A NotifyingBarrierGCTask is a BarrierGCTask -// that calls a notification method when it is the only task running. -class NotifyingBarrierGCTask : public BarrierGCTask { -private: - // Instance state. - NotifyDoneClosure* _ndc; // The callback object. -public: - // Factory create and destroy methods. - static NotifyingBarrierGCTask* create(NotifyDoneClosure* ndc) { - return new NotifyingBarrierGCTask(ndc); - } - static void destroy(NotifyingBarrierGCTask* that) { - if (that != NULL) { - that->destruct(); - delete that; - } - } - // Methods from GCTask. - void do_it(GCTaskManager* manager, uint which); -protected: - // Constructor. Clients use factory, but there might be subclasses. - NotifyingBarrierGCTask(NotifyDoneClosure* ndc) : - BarrierGCTask(), - _ndc(ndc) { - assert(notify_done_closure() != NULL, "can't notify on NULL"); - } - // Destructor-like method. - void destruct(); - // Accessor. - NotifyDoneClosure* notify_done_closure() const { return _ndc; } -}; - -// A WaitForBarrierGCTask is a BarrierGCTask +// A WaitForBarrierGCTask is a GCTask // with a method you can call to wait until // the BarrierGCTask is done. -// This may cover many of the uses of NotifyingBarrierGCTasks. -class WaitForBarrierGCTask : public BarrierGCTask { +class WaitForBarrierGCTask : public GCTask { friend class GCTaskManager; friend class IdleGCTask; private: // Instance state. - Monitor* _monitor; // Guard and notify changes. - volatile bool _should_wait; // true=>wait, false=>proceed. - const bool _is_c_heap_obj; // Was allocated on the heap. + WaitHelper _wait_helper; + WaitForBarrierGCTask(); public: virtual char* name() { return (char *) "waitfor-barrier-task"; } // Factory create and destroy methods. static WaitForBarrierGCTask* create(); - static WaitForBarrierGCTask* create_on_c_heap(); static void destroy(WaitForBarrierGCTask* that); // Methods. void do_it(GCTaskManager* manager, uint which); - void wait_for(bool reset); - void set_should_wait(bool value) { - _should_wait = value; - } protected: - // Constructor. Clients use factory, but there might be subclasses. - WaitForBarrierGCTask(bool on_c_heap); // Destructor-like method. void destruct(); - // Accessors. - Monitor* monitor() const { - return _monitor; - } - bool should_wait() const { - return _should_wait; - } - bool is_c_heap_obj() { - return _is_c_heap_obj; + + // Methods. + // Wait for this to be the only task running. + void do_it_internal(GCTaskManager* manager, uint which); + + void wait_for(bool reset) { + _wait_helper.wait_for(reset); } }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp --- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "gc/parallel/gcTaskManager.hpp" #include "gc/parallel/gcTaskThread.hpp" +#include "gc/shared/gcId.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" @@ -124,6 +125,7 @@ for (; /* break */; ) { // This will block until there is a task to be gotten. GCTask* task = manager()->get_task(which()); + GCIdMark gc_id_mark(task->gc_id()); // Record if this is an idle task for later use. bool is_idle_task = task->is_idle_task(); // In case the update is costly diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/mutableNUMASpace.cpp --- a/hotspot/src/share/vm/gc/parallel/mutableNUMASpace.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/mutableNUMASpace.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -85,8 +85,8 @@ while (words_left_to_fill > 0) { size_t words_to_fill = MIN2(words_left_to_fill, CollectedHeap::filler_array_max_size()); assert(words_to_fill >= CollectedHeap::min_fill_size(), - err_msg("Remaining size (" SIZE_FORMAT ") is too small to fill (based on " SIZE_FORMAT " and " SIZE_FORMAT ")", - words_to_fill, words_left_to_fill, CollectedHeap::filler_array_max_size())); + "Remaining size (" SIZE_FORMAT ") is too small to fill (based on " SIZE_FORMAT " and " SIZE_FORMAT ")", + words_to_fill, words_left_to_fill, CollectedHeap::filler_array_max_size()); CollectedHeap::fill_with_object((HeapWord*)cur_top, words_to_fill); if (!os::numa_has_static_binding()) { size_t touched_words = words_to_fill; @@ -971,7 +971,7 @@ break; } if (e != scan_end) { - assert(e < scan_end, err_msg("e: " PTR_FORMAT " scan_end: " PTR_FORMAT, p2i(e), p2i(scan_end))); + assert(e < scan_end, "e: " PTR_FORMAT " scan_end: " PTR_FORMAT, p2i(e), p2i(scan_end)); if ((page_expected.size != page_size || page_expected.lgrp_id != lgrp_id()) && page_expected.size != 0) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/objectStartArray.cpp --- a/hotspot/src/share/vm/gc/parallel/objectStartArray.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/objectStartArray.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -127,8 +127,8 @@ bool ObjectStartArray::object_starts_in_range(HeapWord* start_addr, HeapWord* end_addr) const { assert(start_addr <= end_addr, - err_msg("Range is wrong. start_addr (" PTR_FORMAT ") is after end_addr (" PTR_FORMAT ")", - p2i(start_addr), p2i(end_addr))); + "Range is wrong. start_addr (" PTR_FORMAT ") is after end_addr (" PTR_FORMAT ")", + p2i(start_addr), p2i(end_addr)); if (start_addr > end_addr) { return false; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/objectStartArray.hpp --- a/hotspot/src/share/vm/gc/parallel/objectStartArray.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/objectStartArray.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -121,8 +121,8 @@ #define assert_covered_region_contains(addr) \ assert(_covered_region.contains(addr), \ - err_msg(#addr " (" PTR_FORMAT ") is not in covered region [" PTR_FORMAT ", " PTR_FORMAT "]", \ - p2i(addr), p2i(_covered_region.start()), p2i(_covered_region.end()))) + #addr " (" PTR_FORMAT ") is not in covered region [" PTR_FORMAT ", " PTR_FORMAT "]", \ + p2i(addr), p2i(_covered_region.start()), p2i(_covered_region.end())) void allocate_block(HeapWord* p) { assert_covered_region_contains(p); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/parMarkBitMap.hpp --- a/hotspot/src/share/vm/gc/parallel/parMarkBitMap.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/parMarkBitMap.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -390,9 +390,9 @@ inline void ParMarkBitMap::verify_addr(HeapWord* addr) const { // Allow one past the last valid address; useful for loop bounds. assert(addr >= region_start(), - err_msg("addr too small, addr: " PTR_FORMAT " region start: " PTR_FORMAT, p2i(addr), p2i(region_start()))); + "addr too small, addr: " PTR_FORMAT " region start: " PTR_FORMAT, p2i(addr), p2i(region_start())); assert(addr <= region_end(), - err_msg("addr too big, addr: " PTR_FORMAT " region end: " PTR_FORMAT, p2i(addr), p2i(region_end()))); + "addr too big, addr: " PTR_FORMAT " region end: " PTR_FORMAT, p2i(addr), p2i(region_end())); } #endif // #ifdef ASSERT diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.inline.hpp --- a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -48,7 +48,7 @@ // Assumes the the old gen address range is lower than that of the young gen. bool result = ((HeapWord*)p) >= young_gen()->reserved().start(); assert(result == young_gen()->is_in_reserved(p), - err_msg("incorrect test - result=%d, p=" PTR_FORMAT, result, p2i((void*)p))); + "incorrect test - result=%d, p=" PTR_FORMAT, result, p2i((void*)p)); return result; } #endif // SHARE_VM_GC_PARALLEL_PARALLELSCAVENGEHEAP_INLINE_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/pcTasks.cpp --- a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -53,7 +53,7 @@ ResourceMark rm; NOT_PRODUCT(GCTraceTime tm("ThreadRootsMarkingTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -82,7 +82,7 @@ assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("MarkFromRootsTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm); @@ -153,7 +153,7 @@ assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("RefProcTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm); @@ -209,7 +209,7 @@ assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("StealMarkingTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -241,7 +241,7 @@ assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("StealRegionCompactionTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -254,9 +254,9 @@ if (use_all_workers) { which_stack_index = which; assert(manager->active_workers() == ParallelGCThreads, - err_msg("all_workers_active has been incorrectly set: " - " active %d ParallelGCThreads %u", manager->active_workers(), - ParallelGCThreads)); + "all_workers_active has been incorrectly set: " + " active %d ParallelGCThreads %u", manager->active_workers(), + ParallelGCThreads); } else { which_stack_index = ParCompactionManager::pop_recycled_stack_index(); } @@ -308,7 +308,7 @@ void UpdateDensePrefixTask::do_it(GCTaskManager* manager, uint which) { NOT_PRODUCT(GCTraceTime tm("UpdateDensePrefixTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -323,7 +323,7 @@ assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); NOT_PRODUCT(GCTraceTime tm("DrainStacksCompactionTask", - PrintGCDetails && TraceParallelOldGCTasks, true, NULL, PSParallelCompact::gc_tracer()->gc_id())); + PrintGCDetails && TraceParallelOldGCTasks, true, NULL)); ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); @@ -333,9 +333,9 @@ if (use_all_workers) { which_stack_index = which; assert(manager->active_workers() == ParallelGCThreads, - err_msg("all_workers_active has been incorrectly set: " - " active %d ParallelGCThreads %u", manager->active_workers(), - ParallelGCThreads)); + "all_workers_active has been incorrectly set: " + " active %d ParallelGCThreads %u", manager->active_workers(), + ParallelGCThreads); } else { which_stack_index = stack_index(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp --- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,6 +36,7 @@ #include "gc/serial/markSweep.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" @@ -113,6 +114,7 @@ ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); GCCause::Cause gc_cause = heap->gc_cause(); + GCIdMark gc_id_mark; _gc_timer->register_gc_start(); _gc_tracer->report_gc_start(gc_cause, _gc_timer->gc_start()); @@ -165,7 +167,7 @@ HandleMark hm; TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer->gc_id()); + GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); @@ -189,7 +191,9 @@ allocate_stacks(); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif ref_processor()->enable_discovery(); ref_processor()->setup_policy(clear_all_softrefs); @@ -198,9 +202,11 @@ mark_sweep_phase2(); +#if defined(COMPILER2) || INCLUDE_JVMCI // Don't add any more derived pointers during phase3 - COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); + assert(DerivedPointerTable::is_active(), "Sanity"); + DerivedPointerTable::set_active(false); +#endif mark_sweep_phase3(); @@ -245,7 +251,9 @@ CodeCache::gc_epilogue(); JvmtiExport::gc_epilogue(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif ref_processor()->enqueue_discovered_references(NULL); @@ -508,7 +516,7 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - GCTraceTime tm("phase 1", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 1", PrintGCDetails && Verbose, true, _gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); @@ -541,7 +549,7 @@ ref_processor()->setup_policy(clear_all_softrefs); const ReferenceProcessorStats& stats = ref_processor()->process_discovered_references( - is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL, _gc_timer, _gc_tracer->gc_id()); + is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL, _gc_timer); gc_tracer()->report_gc_reference_stats(stats); } @@ -567,7 +575,7 @@ void PSMarkSweep::mark_sweep_phase2() { - GCTraceTime tm("phase 2", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 2", PrintGCDetails && Verbose, true, _gc_timer); // Now all live objects are marked, compute the new object addresses. @@ -594,7 +602,7 @@ void PSMarkSweep::mark_sweep_phase3() { // Adjust the pointers to reflect the new locations - GCTraceTime tm("phase 3", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 3", PrintGCDetails && Verbose, true, _gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSYoungGen* young_gen = heap->young_gen(); @@ -634,7 +642,7 @@ void PSMarkSweep::mark_sweep_phase4() { EventMark m("4 compact heap"); - GCTraceTime tm("phase 4", PrintGCDetails && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 4", PrintGCDetails && Verbose, true, _gc_timer); // All pointers are now adjusted, move objects accordingly diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/psOldGen.hpp --- a/hotspot/src/share/vm/gc/parallel/psOldGen.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/psOldGen.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -65,15 +65,15 @@ // Explictly capture current covered_region in a local MemRegion covered_region = this->start_array()->covered_region(); assert(covered_region.contains(new_memregion), - err_msg("new region is not in covered_region [ " PTR_FORMAT ", " PTR_FORMAT " ], " - "new region [ " PTR_FORMAT ", " PTR_FORMAT " ], " - "object space [ " PTR_FORMAT ", " PTR_FORMAT " ]", - p2i(covered_region.start()), - p2i(covered_region.end()), - p2i(new_memregion.start()), - p2i(new_memregion.end()), - p2i(this->object_space()->used_region().start()), - p2i(this->object_space()->used_region().end()))); + "new region is not in covered_region [ " PTR_FORMAT ", " PTR_FORMAT " ], " + "new region [ " PTR_FORMAT ", " PTR_FORMAT " ], " + "object space [ " PTR_FORMAT ", " PTR_FORMAT " ]", + p2i(covered_region.start()), + p2i(covered_region.end()), + p2i(new_memregion.start()), + p2i(new_memregion.end()), + p2i(this->object_space()->used_region().start()), + p2i(this->object_space()->used_region().end())); } #endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp --- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -40,6 +40,7 @@ #include "gc/parallel/psYoungGen.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" @@ -960,7 +961,7 @@ // at each young gen gc. Do the update unconditionally (even though a // promotion failure does not swap spaces) because an unknown number of young // collections will have swapped the spaces an unknown number of times. - GCTraceTime tm("pre compact", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("pre compact", print_phases(), true, &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _space_info[from_space_id].set_space(heap->young_gen()->from_space()); _space_info[to_space_id].set_space(heap->young_gen()->to_space()); @@ -1003,7 +1004,7 @@ void PSParallelCompact::post_compact() { - GCTraceTime tm("post compact", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("post compact", print_phases(), true, &_gc_timer); for (unsigned int id = old_space_id; id < last_space_id; ++id) { // Clear the marking bitmap, summary data and split info. @@ -1045,7 +1046,9 @@ CodeCache::gc_epilogue(); JvmtiExport::gc_epilogue(); - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif ref_processor()->enqueue_discovered_references(NULL); @@ -1824,7 +1827,7 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm, bool maximum_compaction) { - GCTraceTime tm("summary phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("summary phase", print_phases(), true, &_gc_timer); // trace("2"); #ifdef ASSERT @@ -1984,6 +1987,7 @@ ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); + GCIdMark gc_id_mark; _gc_timer.register_gc_start(); _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start()); @@ -2031,7 +2035,7 @@ gc_task_manager()->task_idle_workers(); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer.gc_id()); + GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(true /* Full GC */,gc_cause); @@ -2042,7 +2046,9 @@ CodeCache::gc_prologue(); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif ref_processor()->enable_discovery(); ref_processor()->setup_policy(maximum_heap_compaction); @@ -2056,8 +2062,10 @@ && GCCause::is_user_requested_gc(gc_cause); summary_phase(vmthread_cm, maximum_heap_compaction || max_on_system_gc); - COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_active(), "Sanity"); + DerivedPointerTable::set_active(false); +#endif // adjust_roots() updates Universe::_intArrayKlassObj which is // needed by the compaction for filling holes in the dense prefix. @@ -2331,7 +2339,7 @@ bool maximum_heap_compaction, ParallelOldTracer *gc_tracer) { // Recursively traverse all live objects and mark them - GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); uint parallel_gc_threads = heap->gc_task_manager()->workers(); @@ -2346,7 +2354,7 @@ ClassLoaderDataGraph::clear_claimed_marks(); { - GCTraceTime tm_m("par mark", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_m("par mark", print_phases(), true, &_gc_timer); ParallelScavengeHeap::ParStrongRootsScope psrs; @@ -2375,24 +2383,24 @@ // Process reference objects found during marking { - GCTraceTime tm_r("reference processing", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_r("reference processing", print_phases(), true, &_gc_timer); ReferenceProcessorStats stats; if (ref_processor()->processing_is_mt()) { RefProcTaskExecutor task_executor; stats = ref_processor()->process_discovered_references( is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, - &task_executor, &_gc_timer, _gc_tracer.gc_id()); + &task_executor, &_gc_timer); } else { stats = ref_processor()->process_discovered_references( is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL, - &_gc_timer, _gc_tracer.gc_id()); + &_gc_timer); } gc_tracer->report_gc_reference_stats(stats); } - GCTraceTime tm_c("class unloading", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_c("class unloading", print_phases(), true, &_gc_timer); // This is the point where the entire marking should have completed. assert(cm->marking_stacks_empty(), "Marking should have completed"); @@ -2423,7 +2431,7 @@ void PSParallelCompact::adjust_roots() { // Adjust the pointers to reflect the new locations - GCTraceTime tm("adjust roots", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("adjust roots", print_phases(), true, &_gc_timer); // Need new claim bits when tracing through and adjusting pointers. ClassLoaderDataGraph::clear_claimed_marks(); @@ -2459,7 +2467,7 @@ void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q, uint parallel_gc_threads) { - GCTraceTime tm("drain task setup", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("drain task setup", print_phases(), true, &_gc_timer); // Find the threads that are active unsigned int which = 0; @@ -2533,7 +2541,7 @@ void PSParallelCompact::enqueue_dense_prefix_tasks(GCTaskQueue* q, uint parallel_gc_threads) { - GCTraceTime tm("dense prefix task setup", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("dense prefix task setup", print_phases(), true, &_gc_timer); ParallelCompactData& sd = PSParallelCompact::summary_data(); @@ -2615,7 +2623,7 @@ GCTaskQueue* q, ParallelTaskTerminator* terminator_ptr, uint parallel_gc_threads) { - GCTraceTime tm("steal task setup", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("steal task setup", print_phases(), true, &_gc_timer); // Once a thread has drained it's stack, it should try to steal regions from // other threads. @@ -2663,7 +2671,7 @@ void PSParallelCompact::compact() { // trace("5"); - GCTraceTime tm("compaction phase", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("compaction phase", print_phases(), true, &_gc_timer); ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); PSOldGen* old_gen = heap->old_gen(); @@ -2679,7 +2687,7 @@ enqueue_region_stealing_tasks(q, &terminator, active_gc_threads); { - GCTraceTime tm_pc("par compact", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_pc("par compact", print_phases(), true, &_gc_timer); gc_task_manager()->execute_and_wait(q); @@ -2693,7 +2701,7 @@ { // Update the deferred objects, if any. Any compaction manager can be used. - GCTraceTime tm_du("deferred updates", print_phases(), true, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm_du("deferred updates", print_phases(), true, &_gc_timer); ParCompactionManager* cm = ParCompactionManager::manager_array(0); for (unsigned int id = old_space_id; id < last_space_id; ++id) { update_deferred_objects(cm, SpaceId(id)); @@ -2851,7 +2859,7 @@ start_array->allocate_block(addr); } cm->update_contents(oop(addr)); - assert(oop(addr)->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(oop(addr)))); + assert(oop(addr)->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(addr))); } } } @@ -3400,7 +3408,7 @@ oop moved_oop = (oop) destination(); compaction_manager()->update_contents(moved_oop); - assert(moved_oop->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(moved_oop))); + assert(moved_oop->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(moved_oop)); update_state(words); assert(destination() == (HeapWord*)moved_oop + moved_oop->size(), "sanity"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/parallel/psScavenge.cpp --- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,6 +36,7 @@ #include "gc/shared/collectorPolicy.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcHeapSummary.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" @@ -278,6 +279,7 @@ return false; } + GCIdMark gc_id_mark; _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start()); bool promotion_failure_occurred = false; @@ -322,7 +324,7 @@ HandleMark hm; TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - GCTraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer.gc_id()); + GCTraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters()); TraceMemoryManagerStats tms(false /* not full GC */,gc_cause); @@ -351,7 +353,9 @@ } save_to_space_top_before_gc(); - COMPILER2_PRESENT(DerivedPointerTable::clear()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::clear(); +#endif reference_processor()->enable_discovery(); reference_processor()->setup_policy(false); @@ -387,7 +391,7 @@ // We'll use the promotion manager again later. PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager(); { - GCTraceTime tm("Scavenge", false, false, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("Scavenge", false, false, &_gc_timer); ParallelScavengeHeap::ParStrongRootsScope psrs; GCTaskQueue* q = GCTaskQueue::create(); @@ -429,7 +433,7 @@ // Process reference objects discovered during scavenge { - GCTraceTime tm("References", false, false, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("References", false, false, &_gc_timer); reference_processor()->setup_policy(false); // not always_clear reference_processor()->set_active_mt_degree(active_workers); @@ -440,10 +444,10 @@ PSRefProcTaskExecutor task_executor; stats = reference_processor()->process_discovered_references( &_is_alive_closure, &keep_alive, &evac_followers, &task_executor, - &_gc_timer, _gc_tracer.gc_id()); + &_gc_timer); } else { stats = reference_processor()->process_discovered_references( - &_is_alive_closure, &keep_alive, &evac_followers, NULL, &_gc_timer, _gc_tracer.gc_id()); + &_is_alive_closure, &keep_alive, &evac_followers, NULL, &_gc_timer); } _gc_tracer.report_gc_reference_stats(stats); @@ -458,7 +462,7 @@ } { - GCTraceTime tm("StringTable", false, false, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("StringTable", false, false, &_gc_timer); // Unlink any dead interned Strings and process the remaining live ones. PSScavengeRootsClosure root_closure(promotion_manager); StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure); @@ -473,6 +477,8 @@ } } + _gc_tracer.report_tenuring_threshold(tenuring_threshold()); + // Let the size policy know we're done. Note that we count promotion // failure cleanup time as part of the collection (otherwise, we're // implicitly saying it's mutator time). @@ -623,12 +629,14 @@ assert(young_gen->to_space()->is_empty(), "to space should be empty now"); } - COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); +#if defined(COMPILER2) || INCLUDE_JVMCI + DerivedPointerTable::update_pointers(); +#endif NOT_PRODUCT(reference_processor()->verify_no_references_recorded()); { - GCTraceTime tm("Prune Scavenge Root Methods", false, false, &_gc_timer, _gc_tracer.gc_id()); + GCTraceTime tm("Prune Scavenge Root Methods", false, false, &_gc_timer); CodeCache::prune_scavenge_root_nmethods(); } @@ -672,7 +680,6 @@ heap->print_heap_after_gc(); heap->trace_heap_after_gc(&_gc_tracer); - _gc_tracer.report_tenuring_threshold(tenuring_threshold()); if (ZapUnusedHeapArea) { young_gen->eden_space()->check_mangled_unused_area_complete(); @@ -819,7 +826,7 @@ if (AlwaysTenure || NeverTenure) { assert(MaxTenuringThreshold == 0 || MaxTenuringThreshold == markOopDesc::max_age + 1, - err_msg("MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is %d", (int) MaxTenuringThreshold)); + "MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is %d", (int) MaxTenuringThreshold); _tenuring_threshold = MaxTenuringThreshold; } else { // We want to smooth out our startup times for the AdaptiveSizePolicy diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/serial/defNewGeneration.cpp --- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -583,7 +583,7 @@ init_assuming_no_promotion_failure(); - GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL, gc_tracer.gc_id()); + GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); // Capture heap used before collection (for printing). size_t gch_prev_used = gch->used(); @@ -646,8 +646,9 @@ rp->setup_policy(clear_all_soft_refs); const ReferenceProcessorStats& stats = rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers, - NULL, _gc_timer, gc_tracer.gc_id()); + NULL, _gc_timer); gc_tracer.report_gc_reference_stats(stats); + gc_tracer.report_tenuring_threshold(tenuring_threshold()); if (!_promotion_failed) { // Swap the survivor spaces. @@ -712,7 +713,6 @@ update_time_of_last_gc(now); gch->trace_heap_after_gc(&gc_tracer); - gc_tracer.report_tenuring_threshold(tenuring_threshold()); _gc_timer->register_gc_end(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/serial/genMarkSweep.cpp --- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -70,7 +70,7 @@ set_ref_processor(rp); rp->setup_policy(clear_all_softrefs); - GCTraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL, _gc_tracer->gc_id()); + GCTraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL); gch->trace_heap_before_gc(_gc_tracer); @@ -96,8 +96,10 @@ mark_sweep_phase2(); // Don't add any more derived pointers during phase3 - COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity")); - COMPILER2_PRESENT(DerivedPointerTable::set_active(false)); +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_active(), "Sanity"); + DerivedPointerTable::set_active(false); +#endif mark_sweep_phase3(); @@ -186,7 +188,7 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them - GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer); GenCollectedHeap* gch = GenCollectedHeap::heap(); @@ -217,7 +219,7 @@ ref_processor()->setup_policy(clear_all_softrefs); const ReferenceProcessorStats& stats = ref_processor()->process_discovered_references( - &is_alive, &keep_alive, &follow_stack_closure, NULL, _gc_timer, _gc_tracer->gc_id()); + &is_alive, &keep_alive, &follow_stack_closure, NULL, _gc_timer); gc_tracer()->report_gc_reference_stats(stats); } @@ -259,7 +261,7 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCTraceTime tm("phase 2", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 2", PrintGC && Verbose, true, _gc_timer); gch->prepare_for_compaction(); } @@ -275,7 +277,7 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); // Adjust the pointers to reflect the new locations - GCTraceTime tm("phase 3", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 3", PrintGC && Verbose, true, _gc_timer); // Need new claim bits for the pointer adjustment tracing. ClassLoaderDataGraph::clear_claimed_marks(); @@ -327,7 +329,7 @@ // to use a higher index (saved from phase2) when verifying perm_gen. GenCollectedHeap* gch = GenCollectedHeap::heap(); - GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id()); + GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer); GenCompactClosure blk; gch->generation_iterate(&blk, true); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp --- a/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -129,8 +129,8 @@ CardGeneration::compute_new_size(); assert(used() == used_after_gc && used_after_gc <= capacity(), - err_msg("used: " SIZE_FORMAT " used_after_gc: " SIZE_FORMAT - " capacity: " SIZE_FORMAT, used(), used_after_gc, capacity())); + "used: " SIZE_FORMAT " used_after_gc: " SIZE_FORMAT + " capacity: " SIZE_FORMAT, used(), used_after_gc, capacity()); } void TenuredGeneration::update_gc_stats(Generation* current_generation, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/ageTable.cpp --- a/hotspot/src/share/vm/gc/shared/ageTable.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/ageTable.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -78,7 +78,7 @@ if (AlwaysTenure || NeverTenure) { assert(MaxTenuringThreshold == 0 || MaxTenuringThreshold == markOopDesc::max_age + 1, - err_msg("MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is " UINTX_FORMAT, MaxTenuringThreshold)); + "MaxTenuringThreshold should be 0 or markOopDesc::max_age + 1, but is " UINTX_FORMAT, MaxTenuringThreshold); result = MaxTenuringThreshold; } else { size_t total = 0; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/barrierSet.hpp --- a/hotspot/src/share/vm/gc/shared/barrierSet.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/barrierSet.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -188,6 +188,9 @@ static void static_write_ref_array_pre(HeapWord* start, size_t count); static void static_write_ref_array_post(HeapWord* start, size_t count); + virtual void write_ref_nmethod_pre(oop* dst, nmethod* nm) {} + virtual void write_ref_nmethod_post(oop* dst, nmethod* nm) {} + protected: virtual void write_ref_array_work(MemRegion mr) = 0; public: diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp --- a/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/blockOffsetTable.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -543,11 +543,11 @@ size_t n_cards_back = entry_to_cards_back(offset); q -= (N_words * n_cards_back); assert(q >= _sp->bottom(), - err_msg("q = " PTR_FORMAT " crossed below bottom = " PTR_FORMAT, - p2i(q), p2i(_sp->bottom()))); + "q = " PTR_FORMAT " crossed below bottom = " PTR_FORMAT, + p2i(q), p2i(_sp->bottom())); assert(q < _sp->end(), - err_msg("q = " PTR_FORMAT " crossed above end = " PTR_FORMAT, - p2i(q), p2i(_sp->end()))); + "q = " PTR_FORMAT " crossed above end = " PTR_FORMAT, + p2i(q), p2i(_sp->end())); index -= n_cards_back; offset = _array->offset_array(index); } @@ -555,11 +555,11 @@ index--; q -= offset; assert(q >= _sp->bottom(), - err_msg("q = " PTR_FORMAT " crossed below bottom = " PTR_FORMAT, - p2i(q), p2i(_sp->bottom()))); + "q = " PTR_FORMAT " crossed below bottom = " PTR_FORMAT, + p2i(q), p2i(_sp->bottom())); assert(q < _sp->end(), - err_msg("q = " PTR_FORMAT " crossed above end = " PTR_FORMAT, - p2i(q), p2i(_sp->end()))); + "q = " PTR_FORMAT " crossed above end = " PTR_FORMAT, + p2i(q), p2i(_sp->end())); HeapWord* n = q; while (n <= addr) { @@ -567,17 +567,17 @@ q = n; n += _sp->block_size(n); assert(n > q, - err_msg("Looping at n = " PTR_FORMAT " with last = " PTR_FORMAT "," - " while querying blk_start(" PTR_FORMAT ")" - " on _sp = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(n), p2i(last), p2i(addr), p2i(_sp->bottom()), p2i(_sp->end()))); + "Looping at n = " PTR_FORMAT " with last = " PTR_FORMAT "," + " while querying blk_start(" PTR_FORMAT ")" + " on _sp = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(n), p2i(last), p2i(addr), p2i(_sp->bottom()), p2i(_sp->end())); } assert(q <= addr, - err_msg("wrong order for current (" INTPTR_FORMAT ")" " <= arg (" INTPTR_FORMAT ")", - p2i(q), p2i(addr))); + "wrong order for current (" INTPTR_FORMAT ")" " <= arg (" INTPTR_FORMAT ")", + p2i(q), p2i(addr)); assert(addr <= n, - err_msg("wrong order for arg (" INTPTR_FORMAT ") <= next (" INTPTR_FORMAT ")", - p2i(addr), p2i(n))); + "wrong order for arg (" INTPTR_FORMAT ") <= next (" INTPTR_FORMAT ")", + p2i(addr), p2i(n)); return q; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp --- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -126,9 +126,9 @@ // Mapping from address to card marking array entry jbyte* byte_for(const void* p) const { assert(_whole_heap.contains(p), - err_msg("Attempt to access p = " PTR_FORMAT " out of bounds of " - " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end()))); + "Attempt to access p = " PTR_FORMAT " out of bounds of " + " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end())); jbyte* result = &byte_map_base[uintptr_t(p) >> card_shift]; assert(result >= _byte_map && result < _byte_map + _byte_map_size, "out of bounds accessor for card marking array"); @@ -294,18 +294,18 @@ size_t delta = pointer_delta(p, byte_map_base, sizeof(jbyte)); HeapWord* result = (HeapWord*) (delta << card_shift); assert(_whole_heap.contains(result), - err_msg("Returning result = " PTR_FORMAT " out of bounds of " - " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(result), p2i(_whole_heap.start()), p2i(_whole_heap.end()))); + "Returning result = " PTR_FORMAT " out of bounds of " + " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(result), p2i(_whole_heap.start()), p2i(_whole_heap.end())); return result; } // Mapping from address to card marking array index. size_t index_for(void* p) { assert(_whole_heap.contains(p), - err_msg("Attempt to access p = " PTR_FORMAT " out of bounds of " - " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end()))); + "Attempt to access p = " PTR_FORMAT " out of bounds of " + " card marking array's _whole_heap = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(p), p2i(_whole_heap.start()), p2i(_whole_heap.end())); return byte_for(p) - _byte_map; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/cardTableRS.cpp --- a/hotspot/src/share/vm/gc/shared/cardTableRS.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -278,10 +278,10 @@ // CMS+ParNew until related bug is fixed. MemRegion ur = sp->used_region(); assert(ur.contains(urasm) || (UseConcMarkSweepGC), - err_msg("Did you forget to call save_marks()? " - "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in " - "[" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()))); + "Did you forget to call save_marks()? " + "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in " + "[" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end())); // In the case of CMS+ParNew, issue a warning if (!ur.contains(urasm)) { assert(UseConcMarkSweepGC, "Tautology: see assert above"); @@ -342,25 +342,25 @@ template void do_oop_work(T* p) { HeapWord* jp = (HeapWord*)p; assert(jp >= _begin && jp < _end, - err_msg("Error: jp " PTR_FORMAT " should be within " - "[_begin, _end) = [" PTR_FORMAT "," PTR_FORMAT ")", - p2i(jp), p2i(_begin), p2i(_end))); + "Error: jp " PTR_FORMAT " should be within " + "[_begin, _end) = [" PTR_FORMAT "," PTR_FORMAT ")", + p2i(jp), p2i(_begin), p2i(_end)); oop obj = oopDesc::load_decode_heap_oop(p); guarantee(obj == NULL || (HeapWord*)obj >= _boundary, - err_msg("pointer " PTR_FORMAT " at " PTR_FORMAT " on " - "clean card crosses boundary" PTR_FORMAT, - p2i((HeapWord*)obj), p2i(jp), p2i(_boundary))); + "pointer " PTR_FORMAT " at " PTR_FORMAT " on " + "clean card crosses boundary" PTR_FORMAT, + p2i(obj), p2i(jp), p2i(_boundary)); } public: VerifyCleanCardClosure(HeapWord* b, HeapWord* begin, HeapWord* end) : _boundary(b), _begin(begin), _end(end) { assert(b <= begin, - err_msg("Error: boundary " PTR_FORMAT " should be at or below begin " PTR_FORMAT, - p2i(b), p2i(begin))); + "Error: boundary " PTR_FORMAT " should be at or below begin " PTR_FORMAT, + p2i(b), p2i(begin)); assert(begin <= end, - err_msg("Error: begin " PTR_FORMAT " should be strictly below end " PTR_FORMAT, - p2i(begin), p2i(end))); + "Error: begin " PTR_FORMAT " should be strictly below end " PTR_FORMAT, + p2i(begin), p2i(end)); } virtual void do_oop(oop* p) { VerifyCleanCardClosure::do_oop_work(p); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/collectedHeap.cpp --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -231,7 +231,7 @@ void CollectedHeap::pre_initialize() { // Used for ReduceInitialCardMarks (when COMPILER2 is used); // otherwise remains unused. -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI _defer_initial_card_mark = ReduceInitialCardMarks && can_elide_tlab_store_barriers() && (DeferInitialCardMark || card_mark_must_follow_store()); #else @@ -459,7 +459,7 @@ const size_t payload_size = words - filler_array_hdr_size(); const size_t len = payload_size * HeapWordSize / sizeof(jint); - assert((int)len >= 0, err_msg("size too large " SIZE_FORMAT " becomes %d", words, (int)len)); + assert((int)len >= 0, "size too large " SIZE_FORMAT " becomes %d", words, (int)len); // Set the length first for concurrent GC. ((arrayOop)start)->set_length((int)len); @@ -539,7 +539,7 @@ " to threads list is doomed to failure!"); for (JavaThread *thread = Threads::first(); thread; thread = thread->next()) { if (use_tlab) thread->tlab().make_parsable(retire_tlabs); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // The deferred store barriers must all have been flushed to the // card-table (or other remembered set structure) before GC starts // processing the card-table (or other remembered set). @@ -573,13 +573,15 @@ void CollectedHeap::pre_full_gc_dump(GCTimer* timer) { if (HeapDumpBeforeFullGC) { - GCTraceTime tt("Heap Dump (before full gc): ", PrintGCDetails, false, timer, GCId::create()); + GCIdMarkAndRestore gc_id_mark; + GCTraceTime tt("Heap Dump (before full gc): ", PrintGCDetails, false, timer); // We are doing a full collection and a heap dump before // full collection has been requested. HeapDumper::dump_heap(); } if (PrintClassHistogramBeforeFullGC) { - GCTraceTime tt("Class Histogram (before full gc): ", PrintGCDetails, true, timer, GCId::create()); + GCIdMarkAndRestore gc_id_mark; + GCTraceTime tt("Class Histogram (before full gc): ", PrintGCDetails, true, timer); VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */); inspector.doit(); } @@ -587,11 +589,13 @@ void CollectedHeap::post_full_gc_dump(GCTimer* timer) { if (HeapDumpAfterFullGC) { - GCTraceTime tt("Heap Dump (after full gc): ", PrintGCDetails, false, timer, GCId::create()); + GCIdMarkAndRestore gc_id_mark; + GCTraceTime tt("Heap Dump (after full gc): ", PrintGCDetails, false, timer); HeapDumper::dump_heap(); } if (PrintClassHistogramAfterFullGC) { - GCTraceTime tt("Class Histogram (after full gc): ", PrintGCDetails, true, timer, GCId::create()); + GCIdMarkAndRestore gc_id_mark; + GCTraceTime tt("Class Histogram (after full gc): ", PrintGCDetails, true, timer); VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */); inspector.doit(); } @@ -622,12 +626,12 @@ assert(heap_start >= ((uintptr_t)NULL + epsilon), "sanity"); void* before_heap = (void*)(heap_start - epsilon); assert(!heap->is_in(before_heap), - err_msg("before_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(before_heap))); + "before_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(before_heap)); // Test that a pointer to after the heap end is reported as outside the heap. assert(heap_end <= ((uintptr_t)-1 - epsilon), "sanity"); void* after_heap = (void*)(heap_end + epsilon); assert(!heap->is_in(after_heap), - err_msg("after_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(after_heap))); + "after_heap: " PTR_FORMAT " is unexpectedly in the heap", p2i(after_heap)); } #endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/collectedHeap.hpp --- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -90,7 +90,8 @@ GCHeapLog* _gc_heap_log; - // Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 is being used + // Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 + // or INCLUDE_JVMCI is being used bool _defer_initial_card_mark; MemRegion _reserved; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp --- a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -244,9 +244,9 @@ } assert(is_ptr_aligned(addr, HeapWordSize), - err_msg("Address " PTR_FORMAT " is not properly aligned.", p2i(addr))); + "Address " PTR_FORMAT " is not properly aligned.", p2i(addr)); assert(is_size_aligned(alignment_in_bytes, HeapWordSize), - err_msg("Alignment size %u is incorrect.", alignment_in_bytes)); + "Alignment size %u is incorrect.", alignment_in_bytes); HeapWord* new_addr = (HeapWord*) align_pointer_up(addr, alignment_in_bytes); size_t padding = pointer_delta(new_addr, addr); @@ -258,13 +258,13 @@ if (padding < CollectedHeap::min_fill_size()) { padding += alignment_in_bytes / HeapWordSize; assert(padding >= CollectedHeap::min_fill_size(), - err_msg("alignment_in_bytes %u is expect to be larger " - "than the minimum object size", alignment_in_bytes)); + "alignment_in_bytes %u is expect to be larger " + "than the minimum object size", alignment_in_bytes); new_addr = addr + padding; } - assert(new_addr > addr, err_msg("Unexpected arithmetic overflow " - PTR_FORMAT " not greater than " PTR_FORMAT, p2i(new_addr), p2i(addr))); + assert(new_addr > addr, "Unexpected arithmetic overflow " + PTR_FORMAT " not greater than " PTR_FORMAT, p2i(new_addr), p2i(addr)); if(new_addr < end) { CollectedHeap::fill_with_object(addr, padding); return new_addr; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/collectorPolicy.cpp --- a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -78,11 +78,11 @@ assert(_space_alignment != 0, "Space alignment not set up properly"); assert(_heap_alignment != 0, "Heap alignment not set up properly"); assert(_heap_alignment >= _space_alignment, - err_msg("heap_alignment: " SIZE_FORMAT " less than space_alignment: " SIZE_FORMAT, - _heap_alignment, _space_alignment)); + "heap_alignment: " SIZE_FORMAT " less than space_alignment: " SIZE_FORMAT, + _heap_alignment, _space_alignment); assert(_heap_alignment % _space_alignment == 0, - err_msg("heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, - _heap_alignment, _space_alignment)); + "heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, + _heap_alignment, _space_alignment); if (FLAG_IS_CMDLINE(MaxHeapSize)) { if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) { @@ -275,14 +275,14 @@ assert(_gen_alignment != 0, "Generation alignment not set up properly"); assert(_heap_alignment >= _gen_alignment, - err_msg("heap_alignment: " SIZE_FORMAT " less than gen_alignment: " SIZE_FORMAT, - _heap_alignment, _gen_alignment)); + "heap_alignment: " SIZE_FORMAT " less than gen_alignment: " SIZE_FORMAT, + _heap_alignment, _gen_alignment); assert(_gen_alignment % _space_alignment == 0, - err_msg("gen_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, - _gen_alignment, _space_alignment)); + "gen_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT, + _gen_alignment, _space_alignment); assert(_heap_alignment % _gen_alignment == 0, - err_msg("heap_alignment: " SIZE_FORMAT " not aligned by gen_alignment: " SIZE_FORMAT, - _heap_alignment, _gen_alignment)); + "heap_alignment: " SIZE_FORMAT " not aligned by gen_alignment: " SIZE_FORMAT, + _heap_alignment, _gen_alignment); // All generational heaps have a youngest gen; handle those flags here @@ -1012,14 +1012,14 @@ MarkSweepPolicy msp; msp.initialize_all(); - assert(msp.min_young_size() <= expected, err_msg("%zu > %zu", msp.min_young_size(), expected)); + assert(msp.min_young_size() <= expected, "%zu > %zu", msp.min_young_size(), expected); } static void verify_young_initial(size_t expected) { MarkSweepPolicy msp; msp.initialize_all(); - assert(msp.initial_young_size() == expected, err_msg("%zu != %zu", msp.initial_young_size(), expected)); + assert(msp.initial_young_size() == expected, "%zu != %zu", msp.initial_young_size(), expected); } static void verify_scaled_young_initial(size_t initial_heap_size) { @@ -1033,23 +1033,23 @@ } size_t expected = msp.scale_by_NewRatio_aligned(initial_heap_size); - assert(msp.initial_young_size() == expected, err_msg("%zu != %zu", msp.initial_young_size(), expected)); + assert(msp.initial_young_size() == expected, "%zu != %zu", msp.initial_young_size(), expected); assert(FLAG_IS_ERGO(NewSize) && NewSize == expected, - err_msg("NewSize should have been set ergonomically to %zu, but was %zu", expected, NewSize)); + "NewSize should have been set ergonomically to %zu, but was %zu", expected, NewSize); } static void verify_old_min(size_t expected) { MarkSweepPolicy msp; msp.initialize_all(); - assert(msp.min_old_size() <= expected, err_msg("%zu > %zu", msp.min_old_size(), expected)); + assert(msp.min_old_size() <= expected, "%zu > %zu", msp.min_old_size(), expected); } static void verify_old_initial(size_t expected) { MarkSweepPolicy msp; msp.initialize_all(); - assert(msp.initial_old_size() == expected, err_msg("%zu != %zu", msp.initial_old_size(), expected)); + assert(msp.initial_old_size() == expected, "%zu != %zu", msp.initial_old_size(), expected); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp --- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -33,10 +33,6 @@ #include "runtime/javaCalls.hpp" #include "runtime/os.hpp" -// CopyrightVersion 1.2 - -int ConcurrentGCThread::_CGC_flag = CGC_nil; - ConcurrentGCThread::ConcurrentGCThread() : _should_terminate(false), _has_terminated(false) { }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp --- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -35,19 +35,6 @@ bool _should_terminate; bool _has_terminated; - enum CGC_flag_type { - CGC_nil = 0x0, - CGC_dont_suspend = 0x1, - CGC_CGC_safepoint = 0x2, - CGC_VM_safepoint = 0x4 - }; - - static int _CGC_flag; - - static bool CGC_flag_is_set(int b) { return (_CGC_flag & b) != 0; } - static int set_CGC_flag(int b) { return _CGC_flag |= b; } - static int reset_CGC_flag(int b) { return _CGC_flag &= ~b; } - // Create and start the thread (setting it's priority high.) void create_and_start(); @@ -63,13 +50,10 @@ void terminate(); public: - // Constructor - ConcurrentGCThread(); - ~ConcurrentGCThread() {} // Exists to call NamedThread destructor. // Tester - bool is_ConcurrentGC_thread() const { return true; } + bool is_ConcurrentGC_thread() const { return true; } }; // The SurrogateLockerThread is used by concurrent GC threads for diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/gcCause.hpp --- a/hotspot/src/share/vm/gc/shared/gcCause.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/gcCause.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -95,9 +95,9 @@ // Causes for collection of the tenured gernation inline static bool is_tenured_allocation_failure_gc(GCCause::Cause cause) { assert(cause != GCCause::_old_generation_too_full_to_scavenge && - cause != GCCause::_old_generation_expanded_on_last_scavenge, - err_msg("This GCCause may be correct but is not expected yet: %s", - to_string(cause))); + cause != GCCause::_old_generation_expanded_on_last_scavenge, + "This GCCause may be correct but is not expected yet: %s", + to_string(cause)); // _tenured_generation_full or _cms_generation_full for full tenured generations // _adaptive_size_policy for a full collection after a young GC // _allocation_failure is the generic cause a collection which could result @@ -141,14 +141,14 @@ _position = jio_snprintf(_buffer, _length, "%s ", prefix); } assert(_position >= 0 && _position <= _length, - err_msg("Need to increase the buffer size in GCCauseString? %d", _position)); + "Need to increase the buffer size in GCCauseString? %d", _position); } GCCauseString& append(const char* str) { int res = jio_snprintf(_buffer + _position, _length - _position, "%s", str); _position += res; assert(res >= 0 && _position <= _length, - err_msg("Need to increase the buffer size in GCCauseString? %d", res)); + "Need to increase the buffer size in GCCauseString? %d", res); return *this; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/gcId.cpp --- a/hotspot/src/share/vm/gc/shared/gcId.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/gcId.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -25,18 +25,50 @@ #include "precompiled.hpp" #include "gc/shared/gcId.hpp" #include "runtime/safepoint.hpp" +#include "runtime/thread.inline.hpp" uint GCId::_next_id = 0; -const GCId GCId::create() { - return GCId(_next_id++); +NamedThread* currentNamedthread() { + assert(Thread::current()->is_Named_thread(), "This thread must be NamedThread"); + return (NamedThread*)Thread::current(); +} + +const uint GCId::create() { + return _next_id++; } -const GCId GCId::peek() { - return GCId(_next_id); + +const uint GCId::current() { + assert(currentNamedthread()->gc_id() != undefined(), "Using undefined GC id."); + return current_raw(); +} + +const uint GCId::current_raw() { + return currentNamedthread()->gc_id(); +} + +GCIdMark::GCIdMark() : _gc_id(GCId::create()) { + currentNamedthread()->set_gc_id(_gc_id); } -const GCId GCId::undefined() { - return GCId(UNDEFINED); + +GCIdMark::GCIdMark(uint gc_id) : _gc_id(gc_id) { + currentNamedthread()->set_gc_id(_gc_id); +} + +GCIdMark::~GCIdMark() { + currentNamedthread()->set_gc_id(GCId::undefined()); } -bool GCId::is_undefined() const { - return _id == UNDEFINED; + +GCIdMarkAndRestore::GCIdMarkAndRestore() : _gc_id(GCId::create()) { + _previous_gc_id = GCId::current(); // will assert that the GC Id is not undefined + currentNamedthread()->set_gc_id(_gc_id); } + +GCIdMarkAndRestore::GCIdMarkAndRestore(uint gc_id) : _gc_id(gc_id) { + _previous_gc_id = GCId::current(); // will assert that the GC Id is not undefinied + currentNamedthread()->set_gc_id(_gc_id); +} + +GCIdMarkAndRestore::~GCIdMarkAndRestore() { + currentNamedthread()->set_gc_id(_previous_gc_id); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/gcId.hpp --- a/hotspot/src/share/vm/gc/shared/gcId.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/gcId.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -27,25 +27,36 @@ #include "memory/allocation.hpp" -class GCId VALUE_OBJ_CLASS_SPEC { - private: - uint _id; - GCId(uint id) : _id(id) {} - GCId() { } // Unused - +class GCId : public AllStatic { + friend class GCIdMark; + friend class GCIdMarkAndRestore; static uint _next_id; static const uint UNDEFINED = (uint)-1; + static const uint create(); public: - uint id() const { - assert(_id != UNDEFINED, "Using undefined GC ID"); - return _id; - } - bool is_undefined() const; + // Returns the currently active GC id. Asserts that there is an active GC id. + static const uint current(); + // Same as current() but can return undefined() if no GC id is currently active + static const uint current_raw(); + static const uint undefined() { return UNDEFINED; } +}; - static const GCId create(); - static const GCId peek(); - static const GCId undefined(); +class GCIdMark : public StackObj { + uint _gc_id; + public: + GCIdMark(); + GCIdMark(uint gc_id); + ~GCIdMark(); +}; + +class GCIdMarkAndRestore : public StackObj { + uint _gc_id; + uint _previous_gc_id; + public: + GCIdMarkAndRestore(); + GCIdMarkAndRestore(uint gc_id); + ~GCIdMarkAndRestore(); }; #endif // SHARE_VM_GC_SHARED_GCID_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/gcTrace.cpp --- a/hotspot/src/share/vm/gc/shared/gcTrace.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/gcTrace.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -40,31 +40,16 @@ #include "gc/g1/evacuationInfo.hpp" #endif -#define assert_unset_gc_id() assert(_shared_gc_info.gc_id().is_undefined(), "GC already started?") -#define assert_set_gc_id() assert(!_shared_gc_info.gc_id().is_undefined(), "GC not started?") - void GCTracer::report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp) { - assert_unset_gc_id(); - - GCId gc_id = GCId::create(); - _shared_gc_info.set_gc_id(gc_id); _shared_gc_info.set_cause(cause); _shared_gc_info.set_start_timestamp(timestamp); } void GCTracer::report_gc_start(GCCause::Cause cause, const Ticks& timestamp) { - assert_unset_gc_id(); - report_gc_start_impl(cause, timestamp); } -bool GCTracer::has_reported_gc_start() const { - return !_shared_gc_info.gc_id().is_undefined(); -} - void GCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - _shared_gc_info.set_sum_of_pauses(time_partitions->sum_of_pauses()); _shared_gc_info.set_longest_pause(time_partitions->longest_pause()); _shared_gc_info.set_end_timestamp(timestamp); @@ -74,16 +59,10 @@ } void GCTracer::report_gc_end(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - report_gc_end_impl(timestamp, time_partitions); - - _shared_gc_info.set_gc_id(GCId::undefined()); } void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) const { - assert_set_gc_id(); - send_reference_stats_event(REF_SOFT, rps.soft_count()); send_reference_stats_event(REF_WEAK, rps.weak_count()); send_reference_stats_event(REF_FINAL, rps.final_count()); @@ -92,14 +71,12 @@ #if INCLUDE_SERVICES class ObjectCountEventSenderClosure : public KlassInfoClosure { - const GCId _gc_id; const double _size_threshold_percentage; const size_t _total_size_in_words; const Ticks _timestamp; public: - ObjectCountEventSenderClosure(GCId gc_id, size_t total_size_in_words, const Ticks& timestamp) : - _gc_id(gc_id), + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : _size_threshold_percentage(ObjectCountCutOffPercent / 100), _total_size_in_words(total_size_in_words), _timestamp(timestamp) @@ -107,7 +84,7 @@ virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { - ObjectCountEventSender::send(entry, _gc_id, _timestamp); + ObjectCountEventSender::send(entry, _timestamp); } } @@ -119,7 +96,6 @@ }; void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) { - assert_set_gc_id(); assert(is_alive_cl != NULL, "Must supply function to check liveness"); if (ObjectCountEventSender::should_send_event()) { @@ -129,7 +105,7 @@ if (!cit.allocation_failed()) { HeapInspection hi(false, false, false, NULL); hi.populate_table(&cit, is_alive_cl); - ObjectCountEventSenderClosure event_sender(_shared_gc_info.gc_id(), cit.size_of_instances_in_words(), Ticks::now()); + ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now()); cit.iterate(&event_sender); } } @@ -137,14 +113,10 @@ #endif // INCLUDE_SERVICES void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const { - assert_set_gc_id(); - send_gc_heap_summary_event(when, heap_summary); } void GCTracer::report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& summary) const { - assert_set_gc_id(); - send_meta_space_summary_event(when, summary); send_metaspace_chunk_free_list_summary(when, Metaspace::NonClassType, summary.metaspace_chunk_free_list_summary()); @@ -154,7 +126,6 @@ } void YoungGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); assert(_tenuring_threshold != UNSET_TENURING_THRESHOLD, "Tenuring threshold has not been reported"); GCTracer::report_gc_end_impl(timestamp, time_partitions); @@ -164,8 +135,6 @@ } void YoungGCTracer::report_promotion_failed(const PromotionFailedInfo& pf_info) const { - assert_set_gc_id(); - send_promotion_failed_event(pf_info); } @@ -189,78 +158,56 @@ void YoungGCTracer::report_promotion_in_new_plab_event(Klass* klass, size_t obj_size, uint age, bool tenured, size_t plab_size) const { - assert_set_gc_id(); send_promotion_in_new_plab_event(klass, obj_size, age, tenured, plab_size); } void YoungGCTracer::report_promotion_outside_plab_event(Klass* klass, size_t obj_size, uint age, bool tenured) const { - assert_set_gc_id(); send_promotion_outside_plab_event(klass, obj_size, age, tenured); } void OldGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - GCTracer::report_gc_end_impl(timestamp, time_partitions); send_old_gc_event(); } void ParallelOldTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - OldGCTracer::report_gc_end_impl(timestamp, time_partitions); send_parallel_old_event(); } void ParallelOldTracer::report_dense_prefix(void* dense_prefix) { - assert_set_gc_id(); - _parallel_old_gc_info.report_dense_prefix(dense_prefix); } void OldGCTracer::report_concurrent_mode_failure() { - assert_set_gc_id(); - send_concurrent_mode_failure_event(); } #if INCLUDE_ALL_GCS -void G1MMUTracer::report_mmu(const GCId& gcId, double timeSlice, double gcTime, double maxTime) { - assert(!gcId.is_undefined(), "Undefined GC id"); - - send_g1_mmu_event(gcId, timeSlice, gcTime, maxTime); +void G1MMUTracer::report_mmu(double timeSlice, double gcTime, double maxTime) { + send_g1_mmu_event(timeSlice, gcTime, maxTime); } void G1NewTracer::report_yc_type(G1YCType type) { - assert_set_gc_id(); - _g1_young_gc_info.set_type(type); } void G1NewTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) { - assert_set_gc_id(); - YoungGCTracer::report_gc_end_impl(timestamp, time_partitions); send_g1_young_gc_event(); } void G1NewTracer::report_evacuation_info(EvacuationInfo* info) { - assert_set_gc_id(); - send_evacuation_info_event(info); } void G1NewTracer::report_evacuation_failed(EvacuationFailedInfo& ef_info) { - assert_set_gc_id(); - send_evacuation_failed_event(ef_info); ef_info.reset(); } void G1NewTracer::report_evacuation_statistics(const G1EvacSummary& young_summary, const G1EvacSummary& old_summary) const { - assert_set_gc_id(); - send_young_evacuation_statistics(young_summary); send_old_evacuation_statistics(old_summary); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/gcTrace.hpp --- a/hotspot/src/share/vm/gc/shared/gcTrace.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/gcTrace.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -52,7 +52,6 @@ class SharedGCInfo VALUE_OBJ_CLASS_SPEC { private: - GCId _gc_id; GCName _name; GCCause::Cause _cause; Ticks _start_timestamp; @@ -62,7 +61,6 @@ public: SharedGCInfo(GCName name) : - _gc_id(GCId::undefined()), _name(name), _cause(GCCause::_last_gc_cause), _start_timestamp(), @@ -71,9 +69,6 @@ _longest_pause() { } - void set_gc_id(GCId gc_id) { _gc_id = gc_id; } - const GCId& gc_id() const { return _gc_id; } - void set_start_timestamp(const Ticks& timestamp) { _start_timestamp = timestamp; } const Ticks start_timestamp() const { return _start_timestamp; } @@ -128,8 +123,6 @@ void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; void report_object_count_after_gc(BoolObjectClosure* object_filter) NOT_SERVICES_RETURN; - bool has_reported_gc_start() const; - const GCId& gc_id() { return _shared_gc_info.gc_id(); } protected: GCTracer(GCName name) : _shared_gc_info(name) {} @@ -242,10 +235,10 @@ #if INCLUDE_ALL_GCS class G1MMUTracer : public AllStatic { - static void send_g1_mmu_event(const GCId& gcId, double timeSlice, double gcTime, double maxTime); + static void send_g1_mmu_event(double timeSlice, double gcTime, double maxTime); public: - static void report_mmu(const GCId& gcId, double timeSlice, double gcTime, double maxTime); + static void report_mmu(double timeSlice, double gcTime, double maxTime); }; class G1NewTracer : public YoungGCTracer { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/gcTraceSend.cpp --- a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -44,7 +44,7 @@ void GCTracer::send_garbage_collection_event() const { EventGCGarbageCollection event(UNTIMED); if (event.should_commit()) { - event.set_gcId(_shared_gc_info.gc_id().id()); + event.set_gcId(GCId::current()); event.set_name(_shared_gc_info.name()); event.set_cause((u2) _shared_gc_info.cause()); event.set_sumOfPauses(_shared_gc_info.sum_of_pauses()); @@ -58,7 +58,7 @@ void GCTracer::send_reference_stats_event(ReferenceType type, size_t count) const { EventGCReferenceStatistics e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_type((u1)type); e.set_count(count); e.commit(); @@ -69,7 +69,7 @@ const MetaspaceChunkFreeListSummary& summary) const { EventMetaspaceChunkFreeListSummary e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_when(when); e.set_metadataType(mdtype); @@ -92,7 +92,7 @@ void ParallelOldTracer::send_parallel_old_event() const { EventGCParallelOld e(UNTIMED); if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_densePrefix((TraceAddress)_parallel_old_gc_info.dense_prefix()); e.set_starttime(_shared_gc_info.start_timestamp()); e.set_endtime(_shared_gc_info.end_timestamp()); @@ -103,7 +103,7 @@ void YoungGCTracer::send_young_gc_event() const { EventGCYoungGarbageCollection e(UNTIMED); if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_tenuringThreshold(_tenuring_threshold); e.set_starttime(_shared_gc_info.start_timestamp()); e.set_endtime(_shared_gc_info.end_timestamp()); @@ -125,7 +125,7 @@ EventPromoteObjectInNewPLAB event; if (event.should_commit()) { - event.set_gcId(_shared_gc_info.gc_id().id()); + event.set_gcId(GCId::current()); event.set_class(klass); event.set_objectSize(obj_size); event.set_tenured(tenured); @@ -140,7 +140,7 @@ EventPromoteObjectOutsidePLAB event; if (event.should_commit()) { - event.set_gcId(_shared_gc_info.gc_id().id()); + event.set_gcId(GCId::current()); event.set_class(klass); event.set_objectSize(obj_size); event.set_tenured(tenured); @@ -152,7 +152,7 @@ void OldGCTracer::send_old_gc_event() const { EventGCOldGarbageCollection e(UNTIMED); if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_starttime(_shared_gc_info.start_timestamp()); e.set_endtime(_shared_gc_info.end_timestamp()); e.commit(); @@ -171,7 +171,7 @@ void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_info) const { EventPromotionFailed e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_data(to_trace_struct(pf_info)); e.set_thread(pf_info.thread()->thread_id()); e.commit(); @@ -182,7 +182,7 @@ void OldGCTracer::send_concurrent_mode_failure_event() { EventConcurrentModeFailure e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.commit(); } } @@ -191,7 +191,7 @@ void G1NewTracer::send_g1_young_gc_event() { EventGCG1GarbageCollection e(UNTIMED); if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_type(_g1_young_gc_info.type()); e.set_starttime(_shared_gc_info.start_timestamp()); e.set_endtime(_shared_gc_info.end_timestamp()); @@ -199,10 +199,10 @@ } } -void G1MMUTracer::send_g1_mmu_event(const GCId& gcId, double timeSlice, double gcTime, double maxTime) { +void G1MMUTracer::send_g1_mmu_event(double timeSlice, double gcTime, double maxTime) { EventGCG1MMU e; if (e.should_commit()) { - e.set_gcId(gcId.id()); + e.set_gcId(GCId::current()); e.set_timeSlice(timeSlice); e.set_gcTime(gcTime); e.set_maxGcTime(maxTime); @@ -213,7 +213,7 @@ void G1NewTracer::send_evacuation_info_event(EvacuationInfo* info) { EventEvacuationInfo e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_cSetRegions(info->collectionset_regions()); e.set_cSetUsedBefore(info->collectionset_used_before()); e.set_cSetUsedAfter(info->collectionset_used_after()); @@ -229,7 +229,7 @@ void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const { EventEvacuationFailed e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_data(to_trace_struct(ef_info)); e.commit(); } @@ -253,7 +253,7 @@ void G1NewTracer::send_young_evacuation_statistics(const G1EvacSummary& summary) const { EventGCG1EvacuationYoungStatistics surv_evt; if (surv_evt.should_commit()) { - surv_evt.set_stats(create_g1_evacstats(_shared_gc_info.gc_id().id(), summary)); + surv_evt.set_stats(create_g1_evacstats(GCId::current(), summary)); surv_evt.commit(); } } @@ -261,7 +261,7 @@ void G1NewTracer::send_old_evacuation_statistics(const G1EvacSummary& summary) const { EventGCG1EvacuationOldStatistics old_evt; if (old_evt.should_commit()) { - old_evt.set_stats(create_g1_evacstats(_shared_gc_info.gc_id().id(), summary)); + old_evt.set_stats(create_g1_evacstats(GCId::current(), summary)); old_evt.commit(); } } @@ -287,17 +287,16 @@ } class GCHeapSummaryEventSender : public GCHeapSummaryVisitor { - GCId _gc_id; GCWhen::Type _when; public: - GCHeapSummaryEventSender(GCId gc_id, GCWhen::Type when) : _gc_id(gc_id), _when(when) {} + GCHeapSummaryEventSender(GCWhen::Type when) : _when(when) {} void visit(const GCHeapSummary* heap_summary) const { const VirtualSpaceSummary& heap_space = heap_summary->heap(); EventGCHeapSummary e; if (e.should_commit()) { - e.set_gcId(_gc_id.id()); + e.set_gcId(GCId::current()); e.set_when((u1)_when); e.set_heapSpace(to_trace_struct(heap_space)); e.set_heapUsed(heap_summary->used()); @@ -310,7 +309,7 @@ EventG1HeapSummary e; if (e.should_commit()) { - e.set_gcId(_gc_id.id()); + e.set_gcId(GCId::current()); e.set_when((u1)_when); e.set_edenUsedSize(g1_heap_summary->edenUsed()); e.set_edenTotalSize(g1_heap_summary->edenCapacity()); @@ -331,7 +330,7 @@ EventPSHeapSummary e; if (e.should_commit()) { - e.set_gcId(_gc_id.id()); + e.set_gcId(GCId::current()); e.set_when((u1)_when); e.set_oldSpace(to_trace_struct(ps_heap_summary->old())); @@ -346,7 +345,7 @@ }; void GCTracer::send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary& heap_summary) const { - GCHeapSummaryEventSender visitor(_shared_gc_info.gc_id(), when); + GCHeapSummaryEventSender visitor(when); heap_summary.accept(&visitor); } @@ -363,7 +362,7 @@ void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const { EventMetaspaceSummary e; if (e.should_commit()) { - e.set_gcId(_shared_gc_info.gc_id().id()); + e.set_gcId(GCId::current()); e.set_when((u1) when); e.set_gcThreshold(meta_space_summary.capacity_until_GC()); e.set_metaspace(to_trace_struct(meta_space_summary.meta_space())); @@ -374,15 +373,12 @@ } class PhaseSender : public PhaseVisitor { - GCId _gc_id; public: - PhaseSender(GCId gc_id) : _gc_id(gc_id) {} - template void send_phase(PausePhase* pause) { T event(UNTIMED); if (event.should_commit()) { - event.set_gcId(_gc_id.id()); + event.set_gcId(GCId::current()); event.set_name(pause->name()); event.set_starttime(pause->start()); event.set_endtime(pause->end()); @@ -406,7 +402,7 @@ }; void GCTracer::send_phase_events(TimePartitions* time_partitions) const { - PhaseSender phase_reporter(_shared_gc_info.gc_id()); + PhaseSender phase_reporter; TimePartitionPhasesIterator iter(time_partitions); while (iter.has_next()) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/gcTraceTime.cpp --- a/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -35,7 +35,7 @@ #include "utilities/ticks.inline.hpp" -GCTraceTime::GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id) : +GCTraceTimeImpl::GCTraceTimeImpl(const char* title, bool doit, bool print_cr, GCTimer* timer) : _title(title), _doit(doit), _print_cr(print_cr), _timer(timer), _start_counter() { if (_doit || _timer != NULL) { _start_counter.stamp(); @@ -49,17 +49,13 @@ } if (_doit) { - gclog_or_tty->date_stamp(PrintGCDateStamps); - gclog_or_tty->stamp(PrintGCTimeStamps); - if (PrintGCID) { - gclog_or_tty->print("#%u: ", gc_id.id()); - } + gclog_or_tty->gclog_stamp(); gclog_or_tty->print("[%s", title); gclog_or_tty->flush(); } } -GCTraceTime::~GCTraceTime() { +GCTraceTimeImpl::~GCTraceTimeImpl() { Ticks stop_counter; if (_doit || _timer != NULL) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/gcTraceTime.hpp --- a/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/gcTraceTime.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,12 +26,13 @@ #define SHARE_VM_GC_SHARED_GCTRACETIME_HPP #include "gc/shared/gcTrace.hpp" +#include "memory/allocation.hpp" #include "prims/jni_md.h" #include "utilities/ticks.hpp" class GCTimer; -class GCTraceTime { +class GCTraceTimeImpl VALUE_OBJ_CLASS_SPEC { const char* _title; bool _doit; bool _print_cr; @@ -39,8 +40,16 @@ Ticks _start_counter; public: - GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id); - ~GCTraceTime(); + GCTraceTimeImpl(const char* title, bool doit, bool print_cr, GCTimer* timer); + ~GCTraceTimeImpl(); +}; + +class GCTraceTime : public StackObj { + GCTraceTimeImpl _gc_trace_time_impl; + + public: + GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer) : + _gc_trace_time_impl(title, doit, print_cr, timer) {}; }; #endif // SHARE_VM_GC_SHARED_GCTRACETIME_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,6 +30,7 @@ #include "code/icBuffer.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/collectorCounters.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.hpp" @@ -162,8 +163,8 @@ "the maximum representable size"); } assert(total_reserved % alignment == 0, - err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment=" - SIZE_FORMAT, total_reserved, alignment)); + "Gen size; total_reserved=" SIZE_FORMAT ", alignment=" + SIZE_FORMAT, total_reserved, alignment); *heap_rs = Universe::reserve_heap(total_reserved, alignment); return heap_rs->base(); @@ -315,9 +316,7 @@ bool restore_marks_for_biased_locking) { // Timer for individual generations. Last argument is false: no CR // FIXME: We should try to start the timing earlier to cover more of the GC pause - // The PrintGCDetails logging starts before we have incremented the GC id. We will do that later - // so we can assume here that the next GC id is what we want. - GCTraceTime t1(gen->short_name(), PrintGCDetails, false, NULL, GCId::peek()); + GCTraceTime t1(gen->short_name(), PrintGCDetails, false, NULL); TraceCollectorStats tcs(gen->counters()); TraceMemoryManagerStats tmms(gen->kind(),gc_cause()); @@ -434,6 +433,8 @@ return; // GC is disabled (e.g. JNI GetXXXCritical operation) } + GCIdMark gc_id_mark; + const bool do_clear_all_soft_refs = clear_all_soft_refs || collector_policy()->should_clear_all_soft_refs(); @@ -449,9 +450,7 @@ bool complete = full && (max_generation == OldGen); const char* gc_cause_prefix = complete ? "Full GC" : "GC"; TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); - // The PrintGCDetails logging starts before we have incremented the GC id. We will do that later - // so we can assume here that the next GC id is what we want. - GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL, GCId::peek()); + GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL); gc_prologue(complete); increment_total_collections(complete); @@ -489,6 +488,7 @@ bool must_restore_marks_for_biased_locking = false; if (max_generation == OldGen && _old_gen->should_collect(full, size, is_tlab)) { + GCIdMarkAndRestore gc_id_mark; if (!complete) { // The full_collections increment was missed above. increment_total_full_collections(); @@ -891,7 +891,7 @@ bool GenCollectedHeap::is_in_young(oop p) { bool result = ((HeapWord*)p) < _old_gen->reserved().start(); assert(result == _young_gen->is_in_reserved(p), - err_msg("incorrect test - result=%d, p=" INTPTR_FORMAT, result, p2i((void*)p))); + "incorrect test - result=%d, p=" INTPTR_FORMAT, result, p2i((void*)p)); return result; } @@ -1224,11 +1224,11 @@ }; void GenCollectedHeap::gc_epilogue(bool full) { -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI assert(DerivedPointerTable::is_empty(), "derived pointer present"); size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr())); guarantee(actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps"); -#endif /* COMPILER2 */ +#endif /* COMPILER2 || INCLUDE_JVMCI */ resize_all_tlabs(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/objectCountEventSender.cpp --- a/hotspot/src/share/vm/gc/shared/objectCountEventSender.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/objectCountEventSender.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -33,13 +33,13 @@ #include "utilities/ticks.hpp" #if INCLUDE_SERVICES -void ObjectCountEventSender::send(const KlassInfoEntry* entry, GCId gc_id, const Ticks& timestamp) { +void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) { #if INCLUDE_TRACE assert(Tracing::is_event_enabled(EventObjectCountAfterGC::eventId), "Only call this method if the event is enabled"); EventObjectCountAfterGC event(UNTIMED); - event.set_gcId(gc_id.id()); + event.set_gcId(GCId::current()); event.set_class(entry->klass()); event.set_count(entry->count()); event.set_totalSize(entry->words() * BytesPerWord); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/objectCountEventSender.hpp --- a/hotspot/src/share/vm/gc/shared/objectCountEventSender.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/objectCountEventSender.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,7 +36,7 @@ class ObjectCountEventSender : public AllStatic { public: - static void send(const KlassInfoEntry* entry, GCId gc_id, const Ticks& timestamp); + static void send(const KlassInfoEntry* entry, const Ticks& timestamp); static bool should_send_event(); }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/plab.cpp --- a/hotspot/src/share/vm/gc/shared/plab.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/plab.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -45,8 +45,8 @@ // ArrayOopDesc::header_size depends on command line initialization. AlignmentReserve = oopDesc::header_size() > MinObjAlignment ? align_object_size(arrayOopDesc::header_size(T_INT)) : 0; assert(min_size() > AlignmentReserve, - err_msg("Minimum PLAB size " SIZE_FORMAT " must be larger than alignment reserve " SIZE_FORMAT " " - "to be able to contain objects", min_size(), AlignmentReserve)); + "Minimum PLAB size " SIZE_FORMAT " must be larger than alignment reserve " SIZE_FORMAT " " + "to be able to contain objects", min_size(), AlignmentReserve); } // If the minimum object size is greater than MinObjAlignment, we can @@ -125,12 +125,12 @@ if (_allocated == 0) { assert(_unused == 0, - err_msg("Inconsistency in PLAB stats: " - "_allocated: " SIZE_FORMAT ", " - "_wasted: " SIZE_FORMAT ", " - "_unused: " SIZE_FORMAT ", " - "_undo_wasted: " SIZE_FORMAT, - _allocated, _wasted, _unused, _undo_wasted)); + "Inconsistency in PLAB stats: " + "_allocated: " SIZE_FORMAT ", " + "_wasted: " SIZE_FORMAT ", " + "_unused: " SIZE_FORMAT ", " + "_undo_wasted: " SIZE_FORMAT, + _allocated, _wasted, _unused, _undo_wasted); _allocated = 1; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/referenceProcessor.cpp --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,6 +31,7 @@ #include "gc/shared/gcTraceTime.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" +#include "memory/allocation.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.hpp" @@ -54,8 +55,11 @@ java_lang_ref_SoftReference::set_clock(_soft_ref_timestamp_clock); _always_clear_soft_ref_policy = new AlwaysClearPolicy(); - _default_soft_ref_policy = new COMPILER2_PRESENT(LRUMaxHeapPolicy()) - NOT_COMPILER2(LRUCurrentHeapPolicy()); +#if defined(COMPILER2) || INCLUDE_JVMCI + _default_soft_ref_policy = new LRUMaxHeapPolicy(); +#else + _default_soft_ref_policy = new LRUCurrentHeapPolicy(); +#endif if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) { vm_exit_during_initialization("Could not allocate reference policy object"); } @@ -182,13 +186,27 @@ return total; } +static void log_ref_count(size_t count, bool doit) { + if (doit) { + gclog_or_tty->print(", " SIZE_FORMAT " refs", count); + } +} + +class GCRefTraceTime : public StackObj { + GCTraceTimeImpl _gc_trace_time; + public: + GCRefTraceTime(const char* title, bool doit, GCTimer* timer, size_t count) : + _gc_trace_time(title, doit, false, timer) { + log_ref_count(count, doit); + } +}; + ReferenceProcessorStats ReferenceProcessor::process_discovered_references( BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor, - GCTimer* gc_timer, - GCId gc_id) { + GCTimer* gc_timer) { assert(!enqueuing_is_done(), "If here enqueuing should not be complete"); // Stop treating discovered references specially. @@ -206,48 +224,48 @@ bool trace_time = PrintGCDetails && PrintReferenceGC; + // Include cleaners in phantom statistics. We expect Cleaner + // references to be temporary, and don't want to deal with + // possible incompatibilities arising from making it more visible. + ReferenceProcessorStats stats( + total_count(_discoveredSoftRefs), + total_count(_discoveredWeakRefs), + total_count(_discoveredFinalRefs), + total_count(_discoveredPhantomRefs) + total_count(_discoveredCleanerRefs)); + // Soft references - size_t soft_count = 0; { - GCTraceTime tt("SoftReference", trace_time, false, gc_timer, gc_id); - soft_count = - process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, - is_alive, keep_alive, complete_gc, task_executor); + GCRefTraceTime tt("SoftReference", trace_time, gc_timer, stats.soft_count()); + process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, + is_alive, keep_alive, complete_gc, task_executor); } update_soft_ref_master_clock(); // Weak references - size_t weak_count = 0; { - GCTraceTime tt("WeakReference", trace_time, false, gc_timer, gc_id); - weak_count = - process_discovered_reflist(_discoveredWeakRefs, NULL, true, - is_alive, keep_alive, complete_gc, task_executor); + GCRefTraceTime tt("WeakReference", trace_time, gc_timer, stats.weak_count()); + process_discovered_reflist(_discoveredWeakRefs, NULL, true, + is_alive, keep_alive, complete_gc, task_executor); } // Final references - size_t final_count = 0; { - GCTraceTime tt("FinalReference", trace_time, false, gc_timer, gc_id); - final_count = - process_discovered_reflist(_discoveredFinalRefs, NULL, false, - is_alive, keep_alive, complete_gc, task_executor); + GCRefTraceTime tt("FinalReference", trace_time, gc_timer, stats.final_count()); + process_discovered_reflist(_discoveredFinalRefs, NULL, false, + is_alive, keep_alive, complete_gc, task_executor); } // Phantom references - size_t phantom_count = 0; { - GCTraceTime tt("PhantomReference", trace_time, false, gc_timer, gc_id); - phantom_count = - process_discovered_reflist(_discoveredPhantomRefs, NULL, false, - is_alive, keep_alive, complete_gc, task_executor); + GCRefTraceTime tt("PhantomReference", trace_time, gc_timer, stats.phantom_count()); + process_discovered_reflist(_discoveredPhantomRefs, NULL, false, + is_alive, keep_alive, complete_gc, task_executor); - // Process cleaners, but include them in phantom statistics. We expect + // Process cleaners, but include them in phantom timing. We expect // Cleaner references to be temporary, and don't want to deal with // possible incompatibilities arising from making it more visible. - phantom_count += - process_discovered_reflist(_discoveredCleanerRefs, NULL, true, + process_discovered_reflist(_discoveredCleanerRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); } @@ -257,14 +275,15 @@ // thus use JNI weak references to circumvent the phantom references and // resurrect a "post-mortem" object. { - GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer, gc_id); + GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer); + NOT_PRODUCT(log_ref_count(count_jni_refs(), trace_time);) if (task_executor != NULL) { task_executor->set_single_threaded_mode(); } process_phaseJNI(is_alive, keep_alive, complete_gc); } - return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count); + return stats; } #ifndef PRODUCT @@ -294,12 +313,6 @@ void ReferenceProcessor::process_phaseJNI(BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc) { -#ifndef PRODUCT - if (PrintGCDetails && PrintReferenceGC) { - unsigned int count = count_jni_refs(); - gclog_or_tty->print(", %u refs", count); - } -#endif JNIHandles::weak_oops_do(is_alive, keep_alive); complete_gc->do_void(); } @@ -437,7 +450,7 @@ _discovered_addr = java_lang_ref_Reference::discovered_addr(_ref); oop discovered = java_lang_ref_Reference::discovered(_ref); assert(_discovered_addr && discovered->is_oop_or_null(), - err_msg("Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered))); + "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered)); _next = discovered; _referent_addr = java_lang_ref_Reference::referent_addr(_ref); _referent = java_lang_ref_Reference::referent(_ref); @@ -446,9 +459,9 @@ assert(allow_null_referent ? _referent->is_oop_or_null() : _referent->is_oop(), - err_msg("Expected an oop%s for referent field at " PTR_FORMAT, - (allow_null_referent ? " or NULL" : ""), - p2i(_referent))); + "Expected an oop%s for referent field at " PTR_FORMAT, + (allow_null_referent ? " or NULL" : ""), + p2i(_referent)); } void DiscoveredListIterator::remove() { @@ -578,7 +591,7 @@ oop next = java_lang_ref_Reference::next(iter.obj()); if ((iter.referent() == NULL || iter.is_referent_alive() || next != NULL)) { - assert(next->is_oop_or_null(), err_msg("Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next))); + assert(next->is_oop_or_null(), "Expected an oop or NULL for next field at " PTR_FORMAT, p2i(next)); // Remove Reference object from list iter.remove(); // Trace the cohorts @@ -826,8 +839,7 @@ balance_queues(_discoveredCleanerRefs); } -size_t -ReferenceProcessor::process_discovered_reflist( +void ReferenceProcessor::process_discovered_reflist( DiscoveredList refs_lists[], ReferencePolicy* policy, bool clear_referent, @@ -850,12 +862,6 @@ balance_queues(refs_lists); } - size_t total_list_count = total_count(refs_lists); - - if (PrintReferenceGC && PrintGCDetails) { - gclog_or_tty->print(", " SIZE_FORMAT " refs", total_list_count); - } - // Phase 1 (soft refs only): // . Traverse the list and remove any SoftReferences whose // referents are not alive, but that should be kept alive for @@ -898,8 +904,6 @@ is_alive, keep_alive, complete_gc); } } - - return total_list_count; } inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) { @@ -993,9 +997,9 @@ bool da = discovery_is_atomic(); oop referent = java_lang_ref_Reference::referent(obj); assert(da ? referent->is_oop() : referent->is_oop_or_null(), - err_msg("Bad referent " INTPTR_FORMAT " found in Reference " - INTPTR_FORMAT " during %satomic discovery ", - p2i(referent), p2i(obj), da ? "" : "non-")); + "Bad referent " INTPTR_FORMAT " found in Reference " + INTPTR_FORMAT " during %satomic discovery ", + p2i(referent), p2i(obj), da ? "" : "non-"); } #endif @@ -1070,7 +1074,7 @@ HeapWord* const discovered_addr = java_lang_ref_Reference::discovered_addr(obj); const oop discovered = java_lang_ref_Reference::discovered(obj); - assert(discovered->is_oop_or_null(), err_msg("Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered))); + assert(discovered->is_oop_or_null(), "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered)); if (discovered != NULL) { // The reference has already been discovered... if (TraceReferenceGC) { @@ -1150,13 +1154,12 @@ OopClosure* keep_alive, VoidClosure* complete_gc, YieldClosure* yield, - GCTimer* gc_timer, - GCId gc_id) { + GCTimer* gc_timer) { // Soft references { GCTraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer, gc_id); + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1169,7 +1172,7 @@ // Weak references { GCTraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer, gc_id); + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1182,7 +1185,7 @@ // Final references { GCTraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer, gc_id); + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; @@ -1195,7 +1198,7 @@ // Phantom references { GCTraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, - false, gc_timer, gc_id); + false, gc_timer); for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/referenceProcessor.hpp --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -263,13 +263,13 @@ } // Process references with a certain reachability level. - size_t process_discovered_reflist(DiscoveredList refs_lists[], - ReferencePolicy* policy, - bool clear_referent, - BoolObjectClosure* is_alive, - OopClosure* keep_alive, - VoidClosure* complete_gc, - AbstractRefProcTaskExecutor* task_executor); + void process_discovered_reflist(DiscoveredList refs_lists[], + ReferencePolicy* policy, + bool clear_referent, + BoolObjectClosure* is_alive, + OopClosure* keep_alive, + VoidClosure* complete_gc, + AbstractRefProcTaskExecutor* task_executor); void process_phaseJNI(BoolObjectClosure* is_alive, OopClosure* keep_alive, @@ -331,8 +331,7 @@ OopClosure* keep_alive, VoidClosure* complete_gc, YieldClosure* yield, - GCTimer* gc_timer, - GCId gc_id); + GCTimer* gc_timer); // Returns the name of the discovered reference list // occupying the i / _num_q slot. @@ -441,8 +440,7 @@ OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor, - GCTimer *gc_timer, - GCId gc_id); + GCTimer *gc_timer); // Enqueue references at end of GC (called by the garbage collector) bool enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor = NULL); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/space.cpp --- a/hotspot/src/share/vm/gc/shared/space.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/space.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -592,8 +592,8 @@ // Very general, slow implementation. HeapWord* ContiguousSpace::block_start_const(const void* p) const { assert(MemRegion(bottom(), end()).contains(p), - err_msg("p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(bottom()), p2i(end()))); + "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(bottom()), p2i(end())); if (p >= top()) { return top(); } else { @@ -603,24 +603,23 @@ last = cur; cur += oop(cur)->size(); } - assert(oop(last)->is_oop(), - err_msg(PTR_FORMAT " should be an object start", p2i(last))); + assert(oop(last)->is_oop(), PTR_FORMAT " should be an object start", p2i(last)); return last; } } size_t ContiguousSpace::block_size(const HeapWord* p) const { assert(MemRegion(bottom(), end()).contains(p), - err_msg("p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")", - p2i(p), p2i(bottom()), p2i(end()))); + "p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(bottom()), p2i(end())); HeapWord* current_top = top(); assert(p <= current_top, - err_msg("p > current top - p: " PTR_FORMAT ", current top: " PTR_FORMAT, - p2i(p), p2i(current_top))); + "p > current top - p: " PTR_FORMAT ", current top: " PTR_FORMAT, + p2i(p), p2i(current_top)); assert(p == current_top || oop(p)->is_oop(), - err_msg("p (" PTR_FORMAT ") is not a block start - " - "current_top: " PTR_FORMAT ", is_oop: %s", - p2i(p), p2i(current_top), BOOL_TO_STR(oop(p)->is_oop()))); + "p (" PTR_FORMAT ") is not a block start - " + "current_top: " PTR_FORMAT ", is_oop: %s", + p2i(p), p2i(current_top), BOOL_TO_STR(oop(p)->is_oop())); if (p < current_top) { return oop(p)->size(); } else { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/taskqueue.cpp --- a/hotspot/src/share/vm/gc/shared/taskqueue.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/taskqueue.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -92,20 +92,20 @@ 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))); + "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))); + "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))); + "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))); + "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))); + "overflow_max_len=" SIZE_FORMAT " overflow=" SIZE_FORMAT, + get(overflow_max_len), get(overflow)); } #endif // ASSERT #endif // TASKQUEUE_STATS diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/workgroup.cpp --- a/hotspot/src/share/vm/gc/shared/workgroup.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/workgroup.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" @@ -140,7 +141,7 @@ _end_semaphore->wait(); // No workers are allowed to read the state variables after the coordinator has been signaled. - assert(_not_finished == 0, err_msg("%d not finished workers?", _not_finished)); + assert(_not_finished == 0, "%d not finished workers?", _not_finished); _task = NULL; _started = 0; @@ -328,6 +329,7 @@ void GangWorker::run_task(WorkData data) { print_task_started(data); + GCIdMark gc_id_mark(data._task->gc_id()); data._task->work(data._worker_id); print_task_done(data); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/gc/shared/workgroup.hpp --- a/hotspot/src/share/vm/gc/shared/workgroup.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "runtime/globals.hpp" #include "runtime/thread.hpp" +#include "gc/shared/gcId.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -54,9 +55,13 @@ // You subclass this to supply your own work() method class AbstractGangTask VALUE_OBJ_CLASS_SPEC { const char* _name; + const uint _gc_id; public: - AbstractGangTask(const char* name) : _name(name) {} + AbstractGangTask(const char* name) : + _name(name), + _gc_id(GCId::current_raw()) + {} // The abstract work method. // The argument tells you which member of the gang you are. @@ -64,6 +69,7 @@ // Debugging accessor for the name. const char* name() const { return _name; } + const uint gc_id() const { return _gc_id; } }; struct WorkData { @@ -132,7 +138,7 @@ virtual uint active_workers() const { assert(_active_workers <= _total_workers, - err_msg("_active_workers: %u > _total_workers: %u", _active_workers, _total_workers)); + "_active_workers: %u > _total_workers: %u", _active_workers, _total_workers); assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers, "Unless dynamic should use total workers"); return _active_workers; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/abstractInterpreter.hpp --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -90,6 +90,8 @@ java_util_zip_CRC32_update, // implementation of java.util.zip.CRC32.update() java_util_zip_CRC32_updateBytes, // implementation of java.util.zip.CRC32.updateBytes() java_util_zip_CRC32_updateByteBuffer, // implementation of java.util.zip.CRC32.updateByteBuffer() + java_util_zip_CRC32C_updateBytes, // implementation of java.util.zip.CRC32C.updateBytes(crc, b[], off, end) + java_util_zip_CRC32C_updateDirectByteBuffer, // implementation of java.util.zip.CRC32C.updateDirectByteBuffer(crc, address, off, end) java_lang_Float_intBitsToFloat, // implementation of java.lang.Float.intBitsToFloat() java_lang_Float_floatToRawIntBits, // implementation of java.lang.Float.floatToRawIntBits() java_lang_Double_longBitsToDouble, // implementation of java.lang.Double.longBitsToDouble() diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -2734,8 +2734,8 @@ } DEFAULT: - fatal(err_msg("Unimplemented opcode %d = %s", opcode, - Bytecodes::name((Bytecodes::Code)opcode))); + fatal("Unimplemented opcode %d = %s", opcode, + Bytecodes::name((Bytecodes::Code)opcode)); goto finish; } /* switch(opc) */ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -35,7 +35,7 @@ #ifdef ASSERT #define VERIFY_OOP(o_) \ if (VerifyOops) { \ - assert((oop(o_))->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(oop(o_)))); \ + assert((oop(o_))->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(o_))); \ StubRoutines::_verify_oop_count++; \ } #else diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/bytecodes.cpp --- a/hotspot/src/share/vm/interpreter/bytecodes.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -542,8 +542,7 @@ Code code = cast(i); Code java = java_code(code); if (can_trap(code) && !can_trap(java)) - fatal(err_msg("%s can trap => %s can trap, too", name(code), - name(java))); + fatal("%s can trap => %s can trap, too", name(code), name(java)); } } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/bytecodes.hpp --- a/hotspot/src/share/vm/interpreter/bytecodes.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/bytecodes.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -353,8 +353,8 @@ public: // Conversion - static void check (Code code) { assert(is_defined(code), err_msg("illegal code: %d", (int)code)); } - static void wide_check (Code code) { assert(wide_is_defined(code), err_msg("illegal code: %d", (int)code)); } + static void check (Code code) { assert(is_defined(code), "illegal code: %d", (int)code); } + static void wide_check (Code code) { assert(wide_is_defined(code), "illegal code: %d", (int)code); } static Code cast (int code) { return (Code)code; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/interpreter.cpp --- a/hotspot/src/share/vm/interpreter/interpreter.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -104,7 +104,10 @@ (*_masm)->flush(); // Commit Codelet. - AbstractInterpreter::code()->commit((*_masm)->code()->pure_insts_size(), (*_masm)->code()->strings()); + int committed_code_size = (*_masm)->code()->pure_insts_size(); + if (committed_code_size) { + AbstractInterpreter::code()->commit(committed_code_size, (*_masm)->code()->strings()); + } // Make sure nobody can use _masm outside a CodeletMark lifespan. *_masm = NULL; } @@ -234,6 +237,13 @@ case vmIntrinsics::_updateByteBufferCRC32 : return java_util_zip_CRC32_updateByteBuffer; } } + if (UseCRC32CIntrinsics) { + // Use optimized stub code for CRC32C methods. + switch (m->intrinsic_id()) { + case vmIntrinsics::_updateBytesCRC32C : return java_util_zip_CRC32C_updateBytes; + case vmIntrinsics::_updateDirectByteBufferCRC32C : return java_util_zip_CRC32C_updateDirectByteBuffer; + } + } switch(m->intrinsic_id()) { case vmIntrinsics::_intBitsToFloat: return java_lang_Float_intBitsToFloat; @@ -349,6 +359,8 @@ case java_util_zip_CRC32_update : tty->print("java_util_zip_CRC32_update"); break; case java_util_zip_CRC32_updateBytes : tty->print("java_util_zip_CRC32_updateBytes"); break; case java_util_zip_CRC32_updateByteBuffer : tty->print("java_util_zip_CRC32_updateByteBuffer"); break; + case java_util_zip_CRC32C_updateBytes : tty->print("java_util_zip_CRC32C_updateBytes"); break; + case java_util_zip_CRC32C_updateDirectByteBuffer: tty->print("java_util_zip_CRC32C_updateDirectByteByffer"); break; default: if (kind >= method_handle_invoke_FIRST && kind <= method_handle_invoke_LAST) { @@ -447,11 +459,11 @@ address AbstractInterpreter::deopt_reexecute_entry(Method* method, address bcp) { assert(method->contains(bcp), "just checkin'"); Bytecodes::Code code = Bytecodes::java_code_at(method, bcp); -#ifdef COMPILER1 +#if defined(COMPILER1) || INCLUDE_JVMCI if(code == Bytecodes::_athrow ) { return Interpreter::rethrow_exception_entry(); } -#endif /* COMPILER1 */ +#endif /* COMPILER1 || INCLUDE_JVMCI */ return Interpreter::deopt_entry(vtos, 0); } @@ -537,17 +549,18 @@ address InterpreterGenerator::generate_method_entry( AbstractInterpreter::MethodKind kind) { // determine code generation flags + bool native = false; bool synchronized = false; address entry_point = NULL; switch (kind) { - case Interpreter::zerolocals : break; - case Interpreter::zerolocals_synchronized: synchronized = true; break; - case Interpreter::native : entry_point = generate_native_entry(false); break; - case Interpreter::native_synchronized : entry_point = generate_native_entry(true); break; - case Interpreter::empty : entry_point = generate_empty_entry(); break; + case Interpreter::zerolocals : break; + case Interpreter::zerolocals_synchronized: synchronized = true; break; + case Interpreter::native : native = true; break; + case Interpreter::native_synchronized : native = true; synchronized = true; break; + case Interpreter::empty : entry_point = generate_empty_entry(); break; case Interpreter::accessor : entry_point = generate_accessor_entry(); break; - case Interpreter::abstract : entry_point = generate_abstract_entry(); break; + case Interpreter::abstract : entry_point = generate_abstract_entry(); break; case Interpreter::java_lang_math_sin : // fall thru case Interpreter::java_lang_math_cos : // fall thru @@ -562,33 +575,37 @@ : entry_point = generate_Reference_get_entry(); break; #ifndef CC_INTERP case Interpreter::java_util_zip_CRC32_update - : entry_point = generate_CRC32_update_entry(); break; + : native = true; entry_point = generate_CRC32_update_entry(); break; case Interpreter::java_util_zip_CRC32_updateBytes : // fall thru case Interpreter::java_util_zip_CRC32_updateByteBuffer - : entry_point = generate_CRC32_updateBytes_entry(kind); break; + : native = true; entry_point = generate_CRC32_updateBytes_entry(kind); break; + case Interpreter::java_util_zip_CRC32C_updateBytes + : // fall thru + case Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer + : entry_point = generate_CRC32C_updateBytes_entry(kind); break; #if defined(TARGET_ARCH_x86) && !defined(_LP64) // On x86_32 platforms, a special entry is generated for the following four methods. // On other platforms the normal entry is used to enter these methods. case Interpreter::java_lang_Float_intBitsToFloat - : entry_point = generate_Float_intBitsToFloat_entry(); break; + : native = true; entry_point = generate_Float_intBitsToFloat_entry(); break; case Interpreter::java_lang_Float_floatToRawIntBits - : entry_point = generate_Float_floatToRawIntBits_entry(); break; + : native = true; entry_point = generate_Float_floatToRawIntBits_entry(); break; case Interpreter::java_lang_Double_longBitsToDouble - : entry_point = generate_Double_longBitsToDouble_entry(); break; + : native = true; entry_point = generate_Double_longBitsToDouble_entry(); break; case Interpreter::java_lang_Double_doubleToRawLongBits - : entry_point = generate_Double_doubleToRawLongBits_entry(); break; + : native = true; entry_point = generate_Double_doubleToRawLongBits_entry(); break; #else case Interpreter::java_lang_Float_intBitsToFloat: case Interpreter::java_lang_Float_floatToRawIntBits: case Interpreter::java_lang_Double_longBitsToDouble: case Interpreter::java_lang_Double_doubleToRawLongBits: - entry_point = generate_native_entry(false); + native = true; break; #endif // defined(TARGET_ARCH_x86) && !defined(_LP64) #endif // CC_INTERP default: - fatal(err_msg("unexpected method kind: %d", kind)); + fatal("unexpected method kind: %d", kind); break; } @@ -596,5 +613,18 @@ return entry_point; } - return generate_normal_entry(synchronized); + // We expect the normal and native entry points to be generated first so we can reuse them. + if (native) { + entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::native_synchronized : Interpreter::native); + if (entry_point == NULL) { + entry_point = generate_native_entry(synchronized); + } + } else { + entry_point = Interpreter::entry_for_kind(synchronized ? Interpreter::zerolocals_synchronized : Interpreter::zerolocals); + if (entry_point == NULL) { + entry_point = generate_normal_entry(synchronized); + } + } + + return entry_point; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/interpreterRuntime.cpp --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -66,8 +66,6 @@ #include "opto/runtime.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - class UnlockFlagSaver { private: JavaThread* _thread; @@ -444,14 +442,14 @@ if (message != NULL) { tty->print_cr("Exception <%s: %s> (" INTPTR_FORMAT ")", h_exception->print_value_string(), message->as_C_string(), - (address)h_exception()); + p2i(h_exception())); } else { tty->print_cr("Exception <%s> (" INTPTR_FORMAT ")", h_exception->print_value_string(), - (address)h_exception()); + p2i(h_exception())); } tty->print_cr(" thrown in interpreter method <%s>", h_method->print_value_string()); - tty->print_cr(" at bci %d for thread " INTPTR_FORMAT, current_bci, thread); + tty->print_cr(" at bci %d for thread " INTPTR_FORMAT, current_bci, p2i(thread)); } // Don't go paging in something which won't be used. // else if (extable->length() == 0) { @@ -481,6 +479,17 @@ } } while (should_repeat == true); +#if INCLUDE_JVMCI + if (UseJVMCICompiler && h_method->method_data() != NULL) { + ResourceMark rm(thread); + ProfileData* pdata = h_method->method_data()->allocate_bci_to_data(current_bci, NULL); + if (pdata != NULL && pdata->is_BitData()) { + BitData* bit_data = (BitData*) pdata; + bit_data->set_exception_seen(); + } + } +#endif + // notify JVMTI of an exception throw; JVMTI will detect if this is a first // time throw or a stack unwinding throw and accordingly notify the debugger if (JvmtiExport::can_post_on_exceptions()) { @@ -858,7 +867,7 @@ resolve_invokedynamic(thread); break; default: - fatal(err_msg("unexpected bytecode: %s", Bytecodes::name(bytecode))); + fatal("unexpected bytecode: %s", Bytecodes::name(bytecode)); break; } } @@ -885,7 +894,7 @@ #ifndef PRODUCT if (TraceOnStackReplacement) { if (nm != NULL) { - tty->print("OSR entry @ pc: " INTPTR_FORMAT ": ", nm->osr_entry()); + tty->print("OSR entry @ pc: " INTPTR_FORMAT ": ", p2i(nm->osr_entry())); nm->print(); } } @@ -1305,7 +1314,7 @@ tty->cr(); tty->print_cr("argument handler #%d at " PTR_FORMAT " for fingerprint " UINT64_FORMAT, _handlers->length(), - handler, + p2i(handler), fingerprint); } _fingerprints->append(fingerprint); @@ -1316,8 +1325,8 @@ tty->print_cr("duplicate argument handler #%d for fingerprint " UINT64_FORMAT "(old: " PTR_FORMAT ", new : " PTR_FORMAT ")", _handlers->length(), fingerprint, - _handlers->at(handler_index), - handler); + p2i(_handlers->at(handler_index)), + p2i(handler)); } } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -124,7 +124,7 @@ // 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()) { + if (!THREAD->can_call_java()) { // don't force compilation, resolve was on behalf of compiler return; } @@ -179,11 +179,11 @@ KlassHandle object_klass = SystemDictionary::Object_klass(); Method * object_resolved_method = object_klass()->vtable()->method_at(index); assert(object_resolved_method->name() == resolved_method->name(), - err_msg("Object and interface method names should match at vtable index %d, %s != %s", - index, object_resolved_method->name()->as_C_string(), resolved_method->name()->as_C_string())); + "Object and interface method names should match at vtable index %d, %s != %s", + index, object_resolved_method->name()->as_C_string(), resolved_method->name()->as_C_string()); assert(object_resolved_method->signature() == resolved_method->signature(), - err_msg("Object and interface method signatures should match at vtable index %d, %s != %s", - index, object_resolved_method->signature()->as_C_string(), resolved_method->signature()->as_C_string())); + "Object and interface method signatures should match at vtable index %d, %s != %s", + index, object_resolved_method->signature()->as_C_string(), resolved_method->signature()->as_C_string()); #endif // ASSERT kind = CallInfo::vtable_call; @@ -192,7 +192,7 @@ kind = CallInfo::itable_call; index = resolved_method->itable_index(); } - assert(index == Method::nonvirtual_vtable_index || index >= 0, err_msg("bad index %d", index)); + assert(index == Method::nonvirtual_vtable_index || index >= 0, "bad index %d", index); _call_kind = kind; _call_index = index; _resolved_appendix = Handle(); @@ -215,7 +215,7 @@ assert(call_kind() != CallInfo::unknown_kind, "CallInfo must be set"); break; default: - fatal(err_msg_res("Unexpected call kind %d", call_kind())); + fatal("Unexpected call kind %d", call_kind()); } } #endif //ASSERT @@ -450,7 +450,7 @@ } return result; } else if (iid == vmIntrinsics::_invokeGeneric - && !THREAD->is_Compiler_thread() + && THREAD->can_call_java() && appendix_result_or_null != NULL) { // This is a method with type-checking semantics. // We will ask Java code to spin an adapter method for it. @@ -499,7 +499,7 @@ result->print(); } assert(actual_size_of_params == expected_size_of_params, - err_msg("%d != %d", actual_size_of_params, expected_size_of_params)); + "%d != %d", actual_size_of_params, expected_size_of_params); #endif //ASSERT assert(appendix_result_or_null != NULL, ""); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/linkResolver.hpp --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -174,9 +174,11 @@ static methodHandle lookup_polymorphic_method(const LinkInfo& link_info, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS); + JVMCI_ONLY(public:) // Needed for CompilerToVM.resolveMethod() // Not Linktime so doesn't take LinkInfo static methodHandle lookup_instance_method_in_klasses ( KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); + JVMCI_ONLY(private:) // Similar loader constraint checking functions that throw // LinkageError with descriptive message. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/oopMapCache.cpp --- a/hotspot/src/share/vm/interpreter/oopMapCache.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/oopMapCache.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,8 +31,6 @@ #include "runtime/handles.inline.hpp" #include "runtime/signature.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - class OopMapCacheEntry: private InterpreterOopMap { friend class InterpreterOopMap; friend class OopMapForCacheEntry; @@ -213,31 +211,6 @@ } } - -#ifdef ENABLE_ZAP_DEAD_LOCALS - -void InterpreterOopMap::iterate_all(OffsetClosure* oop_closure, OffsetClosure* value_closure, OffsetClosure* dead_closure) { - int n = number_of_entries(); - int word_index = 0; - uintptr_t value = 0; - uintptr_t mask = 0; - // iterate over entries - for (int i = 0; i < n; i++, mask <<= bits_per_entry) { - // get current word - if (mask == 0) { - value = bit_mask()[word_index++]; - mask = 1; - } - // test for dead values & oops, and for live values - if ((value & (mask << dead_bit_number)) != 0) dead_closure->offset_do(i); // call this for all dead values or oops - else if ((value & (mask << oop_bit_number)) != 0) oop_closure->offset_do(i); // call this for all live oops - else value_closure->offset_do(i); // call this for all live values - } -} - -#endif - - void InterpreterOopMap::print() const { int n = number_of_entries(); tty->print("oop map for "); @@ -297,12 +270,6 @@ bool v2 = vars[i].is_reference() ? true : false; assert(v1 == v2, "locals oop mask generation error"); if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0); -#ifdef ENABLE_ZAP_DEAD_LOCALS - bool v3 = is_dead(i) ? true : false; - bool v4 = !vars[i].is_live() ? true : false; - assert(v3 == v4, "locals live mask generation error"); - assert(!(v1 && v3), "dead value marked as oop"); -#endif } if (TraceOopMapGeneration && Verbose) { tty->cr(); tty->print("Stack (%d): ", stack_top); } @@ -311,12 +278,6 @@ bool v2 = stack[j].is_reference() ? true : false; assert(v1 == v2, "stack oop mask generation error"); if (TraceOopMapGeneration && Verbose) tty->print("%d", v1 ? 1 : 0); -#ifdef ENABLE_ZAP_DEAD_LOCALS - bool v3 = is_dead(max_locals + j) ? true : false; - bool v4 = !stack[j].is_live() ? true : false; - assert(v3 == v4, "stack live mask generation error"); - assert(!(v1 && v3), "dead value marked as oop"); -#endif } if (TraceOopMapGeneration && Verbose) tty->cr(); return true; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/oopMapCache.hpp --- a/hotspot/src/share/vm/interpreter/oopMapCache.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/oopMapCache.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -141,9 +141,6 @@ int expression_stack_size() const { return _expression_stack_size; } -#ifdef ENABLE_ZAP_DEAD_LOCALS - void iterate_all(OffsetClosure* oop_closure, OffsetClosure* value_closure, OffsetClosure* dead_closure); -#endif }; class OopMapCache : public CHeapObj { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/templateInterpreter.cpp --- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -412,17 +412,6 @@ method_entry(java_lang_math_pow ) method_entry(java_lang_ref_reference_get) - if (UseCRC32Intrinsics) { - method_entry(java_util_zip_CRC32_update) - method_entry(java_util_zip_CRC32_updateBytes) - method_entry(java_util_zip_CRC32_updateByteBuffer) - } - - method_entry(java_lang_Float_intBitsToFloat); - method_entry(java_lang_Float_floatToRawIntBits); - method_entry(java_lang_Double_longBitsToDouble); - method_entry(java_lang_Double_doubleToRawLongBits); - initialize_method_handle_entries(); // all native method kinds (must be one contiguous block) @@ -431,6 +420,22 @@ method_entry(native_synchronized) Interpreter::_native_entry_end = Interpreter::code()->code_end(); + if (UseCRC32Intrinsics) { + method_entry(java_util_zip_CRC32_update) + method_entry(java_util_zip_CRC32_updateBytes) + method_entry(java_util_zip_CRC32_updateByteBuffer) + } + + if (UseCRC32CIntrinsics) { + method_entry(java_util_zip_CRC32C_updateBytes) + method_entry(java_util_zip_CRC32C_updateDirectByteBuffer) + } + + method_entry(java_lang_Float_intBitsToFloat); + method_entry(java_lang_Float_floatToRawIntBits); + method_entry(java_lang_Double_longBitsToDouble); + method_entry(java_lang_Double_doubleToRawLongBits); + #undef method_entry // Bytecodes @@ -602,7 +607,7 @@ case Bytecodes::_invokedynamic: return Interpreter::invokedynamic_return_entry_table(); default: - fatal(err_msg("invalid bytecode: %s", Bytecodes::name(code))); + fatal("invalid bytecode: %s", Bytecodes::name(code)); return NULL; } } @@ -624,7 +629,7 @@ case Bytecodes::_invokedynamic: return _invokedynamic_return_entry[index]; default: - assert(!Bytecodes::is_invoke(code), err_msg("invoke instructions should be handled separately: %s", Bytecodes::name(code))); + assert(!Bytecodes::is_invoke(code), "invoke instructions should be handled separately: %s", Bytecodes::name(code)); return _return_entry[length].entry(state); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp --- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -59,6 +59,8 @@ address generate_safept_entry_for(TosState state, address runtime_entry); void generate_throw_exception(); + void lock_method(); + // Instruction generation void generate_and_dispatch (Template* t, TosState tos_out = ilgl); void set_vtos_entry_points (Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" +#include "runtime/arguments.hpp" +#include "runtime/globals.hpp" +#include "utilities/defaultStream.hpp" + +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose) { + if (!EnableJVMCI) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); + } + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose) { + if (!EnableJVMCI) { + if (verbose == true) { + jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); + } + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP +#define SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP + +#include "runtime/globals.hpp" +#include "utilities/globalDefinitions.hpp" + +/* + * Here we have JVMCI arguments constraints functions, which are called automatically + * whenever flag's value changes. If the constraint fails the function should return + * an appropriate error value. + */ + +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose); +Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose); + +#endif /* SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP */ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1029 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "code/compiledIC.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "asm/register.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/vmreg.hpp" + +#ifdef TARGET_ARCH_x86 +# include "vmreg_x86.inline.hpp" +#endif +#ifdef TARGET_ARCH_sparc +# include "vmreg_sparc.inline.hpp" +#endif +#ifdef TARGET_ARCH_zero +# include "vmreg_zero.inline.hpp" +#endif +#ifdef TARGET_ARCH_arm +# include "vmreg_arm.inline.hpp" +#endif +#ifdef TARGET_ARCH_ppc +# include "vmreg_ppc.inline.hpp" +#endif + + +// frequently used constants +// Allocate them with new so they are never destroyed (otherwise, a +// forced exit could destroy these objects while they are still in +// use). +ConstantOopWriteValue* CodeInstaller::_oop_null_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantOopWriteValue(NULL); +ConstantIntValue* CodeInstaller::_int_m1_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(-1); +ConstantIntValue* CodeInstaller::_int_0_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(0); +ConstantIntValue* CodeInstaller::_int_1_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(1); +ConstantIntValue* CodeInstaller::_int_2_scope_value = new (ResourceObj::C_HEAP, mtCompiler) ConstantIntValue(2); +LocationValue* CodeInstaller::_illegal_value = new (ResourceObj::C_HEAP, mtCompiler) LocationValue(Location()); + +Method* getMethodFromHotSpotMethod(oop hotspot_method) { + assert(hotspot_method != NULL && hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass()), "sanity"); + return CompilerToVM::asMethod(hotspot_method); +} + +VMReg getVMRegFromLocation(oop location, int total_frame_size) { + oop reg = code_Location::reg(location); + jint offset = code_Location::offset(location); + + if (reg != NULL) { + // register + jint number = code_Register::number(reg); + VMReg vmReg = CodeInstaller::get_hotspot_reg(number); + assert(offset % 4 == 0, "must be aligned"); + return vmReg->next(offset / 4); + } else { + // stack slot + assert(offset % 4 == 0, "must be aligned"); + return VMRegImpl::stack2reg(offset / 4); + } +} + +// creates a HotSpot oop map out of the byte arrays provided by DebugInfo +OopMap* CodeInstaller::create_oop_map(oop debug_info) { + oop reference_map = DebugInfo::referenceMap(debug_info); + if (HotSpotReferenceMap::maxRegisterSize(reference_map) > 16) { + _has_wide_vector = true; + } + OopMap* map = new OopMap(_total_frame_size, _parameter_count); + objArrayOop objects = HotSpotReferenceMap::objects(reference_map); + objArrayOop derivedBase = HotSpotReferenceMap::derivedBase(reference_map); + typeArrayOop sizeInBytes = HotSpotReferenceMap::sizeInBytes(reference_map); + for (int i = 0; i < objects->length(); i++) { + oop location = objects->obj_at(i); + oop baseLocation = derivedBase->obj_at(i); + int bytes = sizeInBytes->int_at(i); + + VMReg vmReg = getVMRegFromLocation(location, _total_frame_size); + if (baseLocation != NULL) { + // derived oop + assert(bytes == 8, "derived oop can't be compressed"); + VMReg baseReg = getVMRegFromLocation(baseLocation, _total_frame_size); + map->set_derived_oop(vmReg, baseReg); + } else if (bytes == 8) { + // wide oop + map->set_oop(vmReg); + } else { + // narrow oop + assert(bytes == 4, "wrong size"); + map->set_narrowoop(vmReg); + } + } + + oop callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info); + if (callee_save_info != NULL) { + objArrayOop registers = RegisterSaveLayout::registers(callee_save_info); + typeArrayOop slots = RegisterSaveLayout::slots(callee_save_info); + for (jint i = 0; i < slots->length(); i++) { + oop jvmci_reg = registers->obj_at(i); + jint jvmci_reg_number = code_Register::number(jvmci_reg); + VMReg hotspot_reg = CodeInstaller::get_hotspot_reg(jvmci_reg_number); + // HotSpot stack slots are 4 bytes + jint jvmci_slot = slots->int_at(i); + jint hotspot_slot = jvmci_slot * VMRegImpl::slots_per_word; + VMReg hotspot_slot_as_reg = VMRegImpl::stack2reg(hotspot_slot); + map->set_callee_saved(hotspot_slot_as_reg, hotspot_reg); +#ifdef _LP64 + // (copied from generate_oop_map() in c1_Runtime1_x86.cpp) + VMReg hotspot_slot_hi_as_reg = VMRegImpl::stack2reg(hotspot_slot + 1); + map->set_callee_saved(hotspot_slot_hi_as_reg, hotspot_reg->next()); +#endif + } + } + return map; +} + +static void record_metadata_reference(oop obj, jlong prim, jboolean compressed, OopRecorder* oop_recorder) { + if (obj->is_a(HotSpotResolvedObjectTypeImpl::klass())) { + Klass* klass = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(obj)); + if (compressed) { + assert(Klass::decode_klass((narrowKlass) prim) == klass, "%s @ " INTPTR_FORMAT " != " PTR64_FORMAT, klass->name()->as_C_string(), p2i(klass), prim); + } else { + assert((Klass*) prim == klass, "%s @ " INTPTR_FORMAT " != " PTR64_FORMAT, klass->name()->as_C_string(), p2i(klass), prim); + } + int index = oop_recorder->find_index(klass); + TRACE_jvmci_3("metadata[%d of %d] = %s", index, oop_recorder->metadata_count(), klass->name()->as_C_string()); + } else if (obj->is_a(HotSpotResolvedJavaMethodImpl::klass())) { + Method* method = (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(obj); + assert(!compressed, "unexpected compressed method pointer %s @ " INTPTR_FORMAT " = " PTR64_FORMAT, method->name()->as_C_string(), p2i(method), prim); + int index = oop_recorder->find_index(method); + TRACE_jvmci_3("metadata[%d of %d] = %s", index, oop_recorder->metadata_count(), method->name()->as_C_string()); + } else { + assert(java_lang_String::is_instance(obj), + "unexpected metadata reference (%s) for constant " JLONG_FORMAT " (" PTR64_FORMAT ")", obj->klass()->name()->as_C_string(), prim, prim); + } +} + +// Records any Metadata values embedded in a Constant (e.g., the value returned by HotSpotResolvedObjectTypeImpl.klass()). +static void record_metadata_in_constant(oop constant, OopRecorder* oop_recorder) { + if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + oop obj = HotSpotMetaspaceConstantImpl::metaspaceObject(constant); + jlong prim = HotSpotMetaspaceConstantImpl::primitive(constant); + assert(obj != NULL, "must have an object"); + assert(prim != 0, "must have a primitive value"); + + record_metadata_reference(obj, prim, false, oop_recorder); + } +} + +static void record_metadata_in_patch(Handle& constant, OopRecorder* oop_recorder) { + record_metadata_reference(HotSpotMetaspaceConstantImpl::metaspaceObject(constant), HotSpotMetaspaceConstantImpl::primitive(constant), HotSpotMetaspaceConstantImpl::compressed(constant), oop_recorder); +} + +Location::Type CodeInstaller::get_oop_type(oop value) { + oop lirKind = Value::lirKind(value); + oop platformKind = LIRKind::platformKind(lirKind); + assert(LIRKind::referenceMask(lirKind) == 1, "unexpected referenceMask"); + + if (platformKind == word_kind()) { + return Location::oop; + } else { + return Location::narrowoop; + } +} + +ScopeValue* CodeInstaller::get_scope_value(oop value, BasicType type, GrowableArray* objects, ScopeValue* &second) { + second = NULL; + if (value == Value::ILLEGAL()) { + assert(type == T_ILLEGAL, "expected legal value"); + return _illegal_value; + } else if (value->is_a(RegisterValue::klass())) { + oop reg = RegisterValue::reg(value); + jint number = code_Register::number(reg); + VMReg hotspotRegister = get_hotspot_reg(number); + if (is_general_purpose_reg(hotspotRegister)) { + Location::Type locationType; + if (type == T_OBJECT) { + locationType = get_oop_type(value); + } else if (type == T_LONG) { + locationType = Location::lng; + } else { + assert(type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN, "unexpected type in cpu register"); + locationType = Location::int_in_long; + } + ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, hotspotRegister)); + if (type == T_LONG) { + second = value; + } + return value; + } else { + assert(type == T_FLOAT || type == T_DOUBLE, "only float and double expected in xmm register"); + Location::Type locationType; + if (type == T_FLOAT) { + // this seems weird, but the same value is used in c1_LinearScan + locationType = Location::normal; + } else { + locationType = Location::dbl; + } + ScopeValue* value = new LocationValue(Location::new_reg_loc(locationType, hotspotRegister)); + if (type == T_DOUBLE) { + second = value; + } + return value; + } + } else if (value->is_a(StackSlot::klass())) { + jint offset = StackSlot::offset(value); + if (StackSlot::addFrameSize(value)) { + offset += _total_frame_size; + } + + Location::Type locationType; + if (type == T_OBJECT) { + locationType = get_oop_type(value); + } else if (type == T_LONG) { + locationType = Location::lng; + } else if (type == T_DOUBLE) { + locationType = Location::dbl; + } else { + assert(type == T_INT || type == T_FLOAT || type == T_SHORT || type == T_CHAR || type == T_BYTE || type == T_BOOLEAN, "unexpected type in stack slot"); + locationType = Location::normal; + } + ScopeValue* value = new LocationValue(Location::new_stk_loc(locationType, offset)); + if (type == T_DOUBLE || type == T_LONG) { + second = value; + } + return value; + } else if (value->is_a(JavaConstant::klass())) { + record_metadata_in_constant(value, _oop_recorder); + if (value->is_a(PrimitiveConstant::klass())) { + if (value->is_a(RawConstant::klass())) { + jlong prim = PrimitiveConstant::primitive(value); + return new ConstantLongValue(prim); + } else { + assert(type == JVMCIRuntime::kindToBasicType(JavaKind::typeChar(PrimitiveConstant::kind(value))), "primitive constant type doesn't match"); + if (type == T_INT || type == T_FLOAT) { + jint prim = (jint)PrimitiveConstant::primitive(value); + switch (prim) { + case -1: return _int_m1_scope_value; + case 0: return _int_0_scope_value; + case 1: return _int_1_scope_value; + case 2: return _int_2_scope_value; + default: return new ConstantIntValue(prim); + } + } else { + assert(type == T_LONG || type == T_DOUBLE, "unexpected primitive constant type"); + jlong prim = PrimitiveConstant::primitive(value); + second = _int_1_scope_value; + return new ConstantLongValue(prim); + } + } + } else { + assert(type == T_OBJECT, "unexpected object constant"); + if (value->is_a(NullConstant::klass()) || value->is_a(HotSpotCompressedNullConstant::klass())) { + return _oop_null_scope_value; + } else { + assert(value->is_a(HotSpotObjectConstantImpl::klass()), "unexpected constant type"); + oop obj = HotSpotObjectConstantImpl::object(value); + assert(obj != NULL, "null value must be in NullConstant"); + return new ConstantOopWriteValue(JNIHandles::make_local(obj)); + } + } + } else if (value->is_a(VirtualObject::klass())) { + assert(type == T_OBJECT, "unexpected virtual object"); + int id = VirtualObject::id(value); + ScopeValue* object = objects->at(id); + assert(object != NULL, "missing value"); + return object; + } else { + value->klass()->print(); + value->print(); + } + ShouldNotReachHere(); + return NULL; +} + +void CodeInstaller::record_object_value(ObjectValue* sv, oop value, GrowableArray* objects) { + oop type = VirtualObject::type(value); + int id = VirtualObject::id(value); + oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); + Klass* klass = java_lang_Class::as_Klass(javaMirror); + bool isLongArray = klass == Universe::longArrayKlassObj(); + + objArrayOop values = VirtualObject::values(value); + objArrayOop slotKinds = VirtualObject::slotKinds(value); + for (jint i = 0; i < values->length(); i++) { + ScopeValue* cur_second = NULL; + oop object = values->obj_at(i); + oop kind = slotKinds->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); + ScopeValue* value = get_scope_value(object, type, objects, cur_second); + + if (isLongArray && cur_second == NULL) { + // we're trying to put ints into a long array... this isn't really valid, but it's used for some optimizations. + // add an int 0 constant + cur_second = _int_0_scope_value; + } + + if (cur_second != NULL) { + sv->field_values()->append(cur_second); + } + assert(value != NULL, "missing value"); + sv->field_values()->append(value); + } +} + +MonitorValue* CodeInstaller::get_monitor_value(oop value, GrowableArray* objects) { + guarantee(value->is_a(StackLockValue::klass()), "Monitors must be of type StackLockValue"); + + ScopeValue* second = NULL; + ScopeValue* owner_value = get_scope_value(StackLockValue::owner(value), T_OBJECT, objects, second); + assert(second == NULL, "monitor cannot occupy two stack slots"); + + ScopeValue* lock_data_value = get_scope_value(StackLockValue::slot(value), T_LONG, objects, second); + assert(second == lock_data_value, "monitor is LONG value that occupies two stack slots"); + assert(lock_data_value->is_location(), "invalid monitor location"); + Location lock_data_loc = ((LocationValue*)lock_data_value)->location(); + + bool eliminated = false; + if (StackLockValue::eliminated(value)) { + eliminated = true; + } + + return new MonitorValue(owner_value, lock_data_loc, eliminated); +} + +void CodeInstaller::initialize_dependencies(oop compiled_code, OopRecorder* recorder) { + JavaThread* thread = JavaThread::current(); + CompilerThread* compilerThread = thread->is_Compiler_thread() ? thread->as_CompilerThread() : NULL; + _oop_recorder = recorder; + _dependencies = new Dependencies(&_arena, _oop_recorder, compilerThread != NULL ? compilerThread->log() : NULL); + objArrayHandle assumptions = HotSpotCompiledCode::assumptions(compiled_code); + if (!assumptions.is_null()) { + int length = assumptions->length(); + for (int i = 0; i < length; ++i) { + Handle assumption = assumptions->obj_at(i); + if (!assumption.is_null()) { + if (assumption->klass() == Assumptions_NoFinalizableSubclass::klass()) { + assumption_NoFinalizableSubclass(assumption); + } else if (assumption->klass() == Assumptions_ConcreteSubtype::klass()) { + assumption_ConcreteSubtype(assumption); + } else if (assumption->klass() == Assumptions_LeafType::klass()) { + assumption_LeafType(assumption); + } else if (assumption->klass() == Assumptions_ConcreteMethod::klass()) { + assumption_ConcreteMethod(assumption); + } else if (assumption->klass() == Assumptions_CallSiteTargetValue::klass()) { + assumption_CallSiteTargetValue(assumption); + } else { + assumption->print(); + fatal("unexpected Assumption subclass"); + } + } + } + } + objArrayHandle methods = HotSpotCompiledCode::methods(compiled_code); + if (!methods.is_null()) { + int length = methods->length(); + for (int i = 0; i < length; ++i) { + Handle method_handle = methods->obj_at(i); + methodHandle method = getMethodFromHotSpotMethod(method_handle()); + + _dependencies->assert_evol_method(method()); + } + } +} + +RelocBuffer::~RelocBuffer() { + if (_buffer != NULL) { + FREE_C_HEAP_ARRAY(char, _buffer); + } +} + +address RelocBuffer::begin() const { + if (_buffer != NULL) { + return (address) _buffer; + } + return (address) _static_buffer; +} + +void RelocBuffer::set_size(size_t bytes) { + assert(bytes <= _size, "can't grow in size!"); + _size = bytes; +} + +void RelocBuffer::ensure_size(size_t bytes) { + assert(_buffer == NULL, "can only be used once"); + assert(_size == 0, "can only be used once"); + if (bytes >= RelocBuffer::stack_size) { + _buffer = NEW_C_HEAP_ARRAY(char, bytes, mtInternal); + } + _size = bytes; +} + +JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata) { + CodeBuffer buffer("JVMCI Compiler CodeBuffer for Metadata"); + jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); + initialize_dependencies(JNIHandles::resolve(compiled_code_obj), NULL); + + // Get instructions and constants CodeSections early because we need it. + _instructions = buffer.insts(); + _constants = buffer.consts(); + + initialize_fields(target(), JNIHandles::resolve(compiled_code_obj)); + if (!initialize_buffer(buffer)) { + return JVMCIEnv::code_too_large; + } + process_exception_handlers(); + + _debug_recorder->pcs_size(); // ehm, create the sentinel record + + assert(_debug_recorder->pcs_length() >= 2, "must be at least 2"); + + metadata.set_pc_desc(_debug_recorder->pcs(), _debug_recorder->pcs_length()); + metadata.set_scopes(_debug_recorder->stream()->buffer(), _debug_recorder->data_size()); + metadata.set_exception_table(&_exception_handler_table); + + RelocBuffer* reloc_buffer = metadata.get_reloc_buffer(); + + reloc_buffer->ensure_size(buffer.total_relocation_size()); + size_t size = (size_t) buffer.copy_relocations_to(reloc_buffer->begin(), (CodeBuffer::csize_t) reloc_buffer->size(), true); + reloc_buffer->set_size(size); + return JVMCIEnv::ok; +} + +// constructor used to create a method +JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log) { + CodeBuffer buffer("JVMCI Compiler CodeBuffer"); + jobject compiled_code_obj = JNIHandles::make_local(compiled_code()); + OopRecorder* recorder = new OopRecorder(&_arena, true); + initialize_dependencies(JNIHandles::resolve(compiled_code_obj), recorder); + + // Get instructions and constants CodeSections early because we need it. + _instructions = buffer.insts(); + _constants = buffer.consts(); + + initialize_fields(target(), JNIHandles::resolve(compiled_code_obj)); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer); + if (result != JVMCIEnv::ok) { + return result; + } + process_exception_handlers(); + + int stack_slots = _total_frame_size / HeapWordSize; // conversion to words + + if (!compiled_code->is_a(HotSpotCompiledNmethod::klass())) { + oop stubName = HotSpotCompiledCode::name(compiled_code_obj); + char* name = strdup(java_lang_String::as_utf8_string(stubName)); + cb = RuntimeStub::new_runtime_stub(name, + &buffer, + CodeOffsets::frame_never_safe, + stack_slots, + _debug_recorder->_oopmaps, + false); + result = JVMCIEnv::ok; + } else { + nmethod* nm = NULL; + methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code)); + jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code); + jint id = HotSpotCompiledNmethod::id(compiled_code); + bool has_unsafe_access = HotSpotCompiledNmethod::hasUnsafeAccess(compiled_code) == JNI_TRUE; + JVMCIEnv* env = (JVMCIEnv*) (address) HotSpotCompiledNmethod::jvmciEnv(compiled_code); + if (id == -1) { + // Make sure a valid compile_id is associated with every compile + id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci); + } + result = JVMCIEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, + stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table, + compiler, _debug_recorder, _dependencies, env, id, + has_unsafe_access, _has_wide_vector, installed_code, compiled_code, speculation_log); + cb = nm; + } + + if (cb != NULL) { + // Make sure the pre-calculated constants section size was correct. + guarantee((cb->code_begin() - cb->content_begin()) >= _constants_size, "%d < %d", (int)(cb->code_begin() - cb->content_begin()), _constants_size); + } + return result; +} + +void CodeInstaller::initialize_fields(oop target, oop compiled_code) { + if (compiled_code->is_a(HotSpotCompiledNmethod::klass())) { + Handle hotspotJavaMethod = HotSpotCompiledNmethod::method(compiled_code); + methodHandle method = getMethodFromHotSpotMethod(hotspotJavaMethod()); + _parameter_count = method->size_of_parameters(); + TRACE_jvmci_2("installing code for %s", method->name_and_sig_as_C_string()); + } else { + // Must be a HotSpotCompiledRuntimeStub. + // Only used in OopMap constructor for non-product builds + _parameter_count = 0; + } + _sites_handle = JNIHandles::make_local(HotSpotCompiledCode::sites(compiled_code)); + _exception_handlers_handle = JNIHandles::make_local(HotSpotCompiledCode::exceptionHandlers(compiled_code)); + + _code_handle = JNIHandles::make_local(HotSpotCompiledCode::targetCode(compiled_code)); + _code_size = HotSpotCompiledCode::targetCodeSize(compiled_code); + _total_frame_size = HotSpotCompiledCode::totalFrameSize(compiled_code); + _custom_stack_area_offset = HotSpotCompiledCode::customStackAreaOffset(compiled_code); + + // Pre-calculate the constants section size. This is required for PC-relative addressing. + _data_section_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSection(compiled_code)); + guarantee(HotSpotCompiledCode::dataSectionAlignment(compiled_code) <= _constants->alignment(), "Alignment inside constants section is restricted by alignment of section begin"); + _constants_size = data_section()->length(); + + _data_section_patches_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSectionPatches(compiled_code)); + +#ifndef PRODUCT + _comments_handle = JNIHandles::make_local(HotSpotCompiledCode::comments(compiled_code)); +#endif + + _next_call_type = INVOKE_INVALID; + + _has_wide_vector = false; + + oop arch = TargetDescription::arch(target); + _word_kind_handle = JNIHandles::make_local(Architecture::wordKind(arch)); +} + +int CodeInstaller::estimate_stubs_size() { + // Return size for all stubs. + int static_call_stubs = 0; + objArrayOop sites = this->sites(); + for (int i = 0; i < sites->length(); i++) { + oop site = sites->obj_at(i); + if (site->is_a(CompilationResult_Mark::klass())) { + oop id_obj = CompilationResult_Mark::id(site); + if (id_obj != NULL) { + assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected"); + jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); + if (id == INVOKESTATIC || id == INVOKESPECIAL) { + static_call_stubs++; + } + } + } + } + return static_call_stubs * CompiledStaticCall::to_interp_stub_size(); +} + +// perform data and call relocation on the CodeBuffer +JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer) { + objArrayHandle sites = this->sites(); + int locs_buffer_size = sites->length() * (relocInfo::length_limit + sizeof(relocInfo)); + + // Allocate enough space in the stub section for the static call + // stubs. Stubs have extra relocs but they are managed by the stub + // section itself so they don't need to be accounted for in the + // locs_buffer above. + int stubs_size = estimate_stubs_size(); + int total_size = round_to(_code_size, buffer.insts()->alignment()) + round_to(_constants_size, buffer.consts()->alignment()) + round_to(stubs_size, buffer.stubs()->alignment()); + + if (total_size > JVMCINMethodSizeLimit) { + return JVMCIEnv::code_too_large; + } + + buffer.initialize(total_size, locs_buffer_size); + if (buffer.blob() == NULL) { + return JVMCIEnv::cache_full; + } + buffer.initialize_stubs_size(stubs_size); + buffer.initialize_consts_size(_constants_size); + + _debug_recorder = new DebugInformationRecorder(_oop_recorder); + _debug_recorder->set_oopmaps(new OopMapSet()); + + buffer.initialize_oop_recorder(_oop_recorder); + + // copy the constant data into the newly created CodeBuffer + address end_data = _constants->start() + _constants_size; + memcpy(_constants->start(), data_section()->base(T_BYTE), _constants_size); + _constants->set_end(end_data); + + // copy the code into the newly created CodeBuffer + address end_pc = _instructions->start() + _code_size; + guarantee(_instructions->allocates2(end_pc), "initialize should have reserved enough space for all the code"); + memcpy(_instructions->start(), code()->base(T_BYTE), _code_size); + _instructions->set_end(end_pc); + + for (int i = 0; i < data_section_patches()->length(); i++) { + Handle patch = data_section_patches()->obj_at(i); + Handle reference = CompilationResult_DataPatch::reference(patch); + assert(reference->is_a(CompilationResult_ConstantReference::klass()), "patch in data section must be a ConstantReference"); + Handle constant = CompilationResult_ConstantReference::constant(reference); + if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + record_metadata_in_patch(constant, _oop_recorder); + } else if (constant->is_a(HotSpotObjectConstantImpl::klass())) { + Handle obj = HotSpotObjectConstantImpl::object(constant); + jobject value = JNIHandles::make_local(obj()); + int oop_index = _oop_recorder->find_index(value); + + address dest = _constants->start() + CompilationResult_Site::pcOffset(patch); + if (HotSpotObjectConstantImpl::compressed(constant)) { +#ifdef _LP64 + _constants->relocate(dest, oop_Relocation::spec(oop_index), relocInfo::narrow_oop_in_const); +#else + fatal("unexpected compressed oop in 32-bit mode"); +#endif + } else { + _constants->relocate(dest, oop_Relocation::spec(oop_index)); + } + } else { + ShouldNotReachHere(); + } + } + jint last_pc_offset = -1; + for (int i = 0; i < sites->length(); i++) { + { + No_Safepoint_Verifier no_safepoint; + oop site = sites->obj_at(i); + jint pc_offset = CompilationResult_Site::pcOffset(site); + + if (site->is_a(CompilationResult_Call::klass())) { + TRACE_jvmci_4("call at %i", pc_offset); + site_Call(buffer, pc_offset, site); + } else if (site->is_a(CompilationResult_Infopoint::klass())) { + // three reasons for infopoints denote actual safepoints + oop reason = CompilationResult_Infopoint::reason(site); + if (InfopointReason::SAFEPOINT() == reason || InfopointReason::CALL() == reason || InfopointReason::IMPLICIT_EXCEPTION() == reason) { + TRACE_jvmci_4("safepoint at %i", pc_offset); + site_Safepoint(buffer, pc_offset, site); + } else { + // if the infopoint is not an actual safepoint, it must have one of the other reasons + // (safeguard against new safepoint types that require handling above) + assert(InfopointReason::METHOD_START() == reason || InfopointReason::METHOD_END() == reason || InfopointReason::LINE_NUMBER() == reason, ""); + site_Infopoint(buffer, pc_offset, site); + } + } else if (site->is_a(CompilationResult_DataPatch::klass())) { + TRACE_jvmci_4("datapatch at %i", pc_offset); + site_DataPatch(buffer, pc_offset, site); + } else if (site->is_a(CompilationResult_Mark::klass())) { + TRACE_jvmci_4("mark at %i", pc_offset); + site_Mark(buffer, pc_offset, site); + } else { + fatal("unexpected Site subclass"); + } + last_pc_offset = pc_offset; + } + if (CodeInstallSafepointChecks && SafepointSynchronize::do_call_back()) { + // this is a hacky way to force a safepoint check but nothing else was jumping out at me. + ThreadToNativeFromVM ttnfv(JavaThread::current()); + } + } + +#ifndef PRODUCT + if (comments() != NULL) { + No_Safepoint_Verifier no_safepoint; + for (int i = 0; i < comments()->length(); i++) { + oop comment = comments()->obj_at(i); + assert(comment->is_a(HotSpotCompiledCode_Comment::klass()), "cce"); + jint offset = HotSpotCompiledCode_Comment::pcOffset(comment); + char* text = java_lang_String::as_utf8_string(HotSpotCompiledCode_Comment::text(comment)); + buffer.block_comment(offset, text); + } + } +#endif + return JVMCIEnv::ok; +} + +void CodeInstaller::assumption_NoFinalizableSubclass(Handle assumption) { + Handle receiverType_handle = Assumptions_NoFinalizableSubclass::receiverType(assumption()); + Klass* receiverType = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(receiverType_handle)); + _dependencies->assert_has_no_finalizable_subclasses(receiverType); +} + +void CodeInstaller::assumption_ConcreteSubtype(Handle assumption) { + Handle context_handle = Assumptions_ConcreteSubtype::context(assumption()); + Handle subtype_handle = Assumptions_ConcreteSubtype::subtype(assumption()); + Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + Klass* subtype = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(subtype_handle)); + + assert(context->is_abstract(), ""); + _dependencies->assert_abstract_with_unique_concrete_subtype(context, subtype); +} + +void CodeInstaller::assumption_LeafType(Handle assumption) { + Handle context_handle = Assumptions_LeafType::context(assumption()); + Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + + _dependencies->assert_leaf_type(context); +} + +void CodeInstaller::assumption_ConcreteMethod(Handle assumption) { + Handle impl_handle = Assumptions_ConcreteMethod::impl(assumption()); + Handle context_handle = Assumptions_ConcreteMethod::context(assumption()); + + methodHandle impl = getMethodFromHotSpotMethod(impl_handle()); + Klass* context = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(context_handle)); + + _dependencies->assert_unique_concrete_method(context, impl()); +} + +void CodeInstaller::assumption_CallSiteTargetValue(Handle assumption) { + Handle callSite = Assumptions_CallSiteTargetValue::callSite(assumption()); + Handle methodHandle = Assumptions_CallSiteTargetValue::methodHandle(assumption()); + + _dependencies->assert_call_site_target_value(callSite(), methodHandle()); +} + +void CodeInstaller::process_exception_handlers() { + if (exception_handlers() != NULL) { + objArrayOop handlers = exception_handlers(); + for (int i = 0; i < handlers->length(); i++) { + oop exc = handlers->obj_at(i); + jint pc_offset = CompilationResult_Site::pcOffset(exc); + jint handler_offset = CompilationResult_ExceptionHandler::handlerPos(exc); + + // Subtable header + _exception_handler_table.add_entry(HandlerTableEntry(1, pc_offset, 0)); + + // Subtable entry + _exception_handler_table.add_entry(HandlerTableEntry(-1, handler_offset, 0)); + } + } +} + +// If deoptimization happens, the interpreter should reexecute these bytecodes. +// This function mainly helps the compilers to set up the reexecute bit. +static bool bytecode_should_reexecute(Bytecodes::Code code) { + switch (code) { + case Bytecodes::_invokedynamic: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + return false; + default: + return true; + } + return true; +} + +GrowableArray* CodeInstaller::record_virtual_objects(oop debug_info) { + objArrayOop virtualObjects = DebugInfo::virtualObjectMapping(debug_info); + if (virtualObjects == NULL) { + return NULL; + } + GrowableArray* objects = new GrowableArray(virtualObjects->length(), virtualObjects->length(), NULL); + // Create the unique ObjectValues + for (int i = 0; i < virtualObjects->length(); i++) { + oop value = virtualObjects->obj_at(i); + int id = VirtualObject::id(value); + oop type = VirtualObject::type(value); + oop javaMirror = HotSpotResolvedObjectTypeImpl::javaClass(type); + ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(JNIHandles::make_local(Thread::current(), javaMirror))); + assert(objects->at(id) == NULL, "once"); + objects->at_put(id, sv); + } + // All the values which could be referenced by the VirtualObjects + // exist, so now describe all the VirtualObjects themselves. + for (int i = 0; i < virtualObjects->length(); i++) { + oop value = virtualObjects->obj_at(i); + int id = VirtualObject::id(value); + record_object_value(objects->at(id)->as_ObjectValue(), value, objects); + } + _debug_recorder->dump_object_pool(objects); + return objects; +} + +void CodeInstaller::record_scope(jint pc_offset, oop debug_info) { + oop position = DebugInfo::bytecodePosition(debug_info); + if (position == NULL) { + // Stubs do not record scope info, just oop maps + return; + } + + GrowableArray* objectMapping = record_virtual_objects(debug_info); + record_scope(pc_offset, position, objectMapping); +} + +void CodeInstaller::record_scope(jint pc_offset, oop position, GrowableArray* objects) { + oop frame = NULL; + if (position->is_a(BytecodeFrame::klass())) { + frame = position; + } + oop caller_frame = BytecodePosition::caller(position); + if (caller_frame != NULL) { + record_scope(pc_offset, caller_frame, objects); + } + + oop hotspot_method = BytecodePosition::method(position); + Method* method = getMethodFromHotSpotMethod(hotspot_method); + jint bci = BytecodePosition::bci(position); + if (bci == BytecodeFrame::BEFORE_BCI()) { + bci = SynchronizationEntryBCI; + } + + TRACE_jvmci_2("Recording scope pc_offset=%d bci=%d method=%s", pc_offset, bci, method->name_and_sig_as_C_string()); + + bool reexecute = false; + if (frame != NULL) { + if (bci == SynchronizationEntryBCI){ + reexecute = false; + } else { + Bytecodes::Code code = Bytecodes::java_code_at(method, method->bcp_from(bci)); + reexecute = bytecode_should_reexecute(code); + if (frame != NULL) { + reexecute = (BytecodeFrame::duringCall(frame) == JNI_FALSE); + } + } + } + + DebugToken* locals_token = NULL; + DebugToken* expressions_token = NULL; + DebugToken* monitors_token = NULL; + bool throw_exception = false; + + if (frame != NULL) { + jint local_count = BytecodeFrame::numLocals(frame); + jint expression_count = BytecodeFrame::numStack(frame); + jint monitor_count = BytecodeFrame::numLocks(frame); + objArrayOop values = BytecodeFrame::values(frame); + objArrayOop slotKinds = BytecodeFrame::slotKinds(frame); + + assert(local_count + expression_count + monitor_count == values->length(), "unexpected values length"); + assert(local_count + expression_count == slotKinds->length(), "unexpected slotKinds length"); + + GrowableArray* locals = local_count > 0 ? new GrowableArray (local_count) : NULL; + GrowableArray* expressions = expression_count > 0 ? new GrowableArray (expression_count) : NULL; + GrowableArray* monitors = monitor_count > 0 ? new GrowableArray (monitor_count) : NULL; + + TRACE_jvmci_2("Scope at bci %d with %d values", bci, values->length()); + TRACE_jvmci_2("%d locals %d expressions, %d monitors", local_count, expression_count, monitor_count); + + for (jint i = 0; i < values->length(); i++) { + ScopeValue* second = NULL; + oop value = values->obj_at(i); + if (i < local_count) { + oop kind = slotKinds->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); + ScopeValue* first = get_scope_value(value, type, objects, second); + if (second != NULL) { + locals->append(second); + } + locals->append(first); + } else if (i < local_count + expression_count) { + oop kind = slotKinds->obj_at(i); + BasicType type = JVMCIRuntime::kindToBasicType(JavaKind::typeChar(kind)); + ScopeValue* first = get_scope_value(value, type, objects, second); + if (second != NULL) { + expressions->append(second); + } + expressions->append(first); + } else { + monitors->append(get_monitor_value(value, objects)); + } + if (second != NULL) { + i++; + assert(i < values->length(), "double-slot value not followed by Value.ILLEGAL"); + assert(values->obj_at(i) == Value::ILLEGAL(), "double-slot value not followed by Value.ILLEGAL"); + } + } + + locals_token = _debug_recorder->create_scope_values(locals); + expressions_token = _debug_recorder->create_scope_values(expressions); + monitors_token = _debug_recorder->create_monitor_values(monitors); + + throw_exception = BytecodeFrame::rethrowException(frame) == JNI_TRUE; + } + + _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, false, + locals_token, expressions_token, monitors_token); +} + +void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site) { + oop debug_info = CompilationResult_Infopoint::debugInfo(site); + assert(debug_info != NULL, "debug info expected"); + + // address instruction = _instructions->start() + pc_offset; + // jint next_pc_offset = Assembler::locate_next_instruction(instruction) - _instructions->start(); + _debug_recorder->add_safepoint(pc_offset, create_oop_map(debug_info)); + record_scope(pc_offset, debug_info); + _debug_recorder->end_safepoint(pc_offset); +} + +void CodeInstaller::site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site) { + oop debug_info = CompilationResult_Infopoint::debugInfo(site); + assert(debug_info != NULL, "debug info expected"); + + _debug_recorder->add_non_safepoint(pc_offset); + record_scope(pc_offset, debug_info); + _debug_recorder->end_non_safepoint(pc_offset); +} + +void CodeInstaller::site_Call(CodeBuffer& buffer, jint pc_offset, oop site) { + oop target = CompilationResult_Call::target(site); + InstanceKlass* target_klass = InstanceKlass::cast(target->klass()); + + oop hotspot_method = NULL; // JavaMethod + oop foreign_call = NULL; + + if (target_klass->is_subclass_of(SystemDictionary::HotSpotForeignCallTarget_klass())) { + foreign_call = target; + } else { + hotspot_method = target; + } + + oop debug_info = CompilationResult_Call::debugInfo(site); + + assert(!!hotspot_method ^ !!foreign_call, "Call site needs exactly one type"); + + NativeInstruction* inst = nativeInstruction_at(_instructions->start() + pc_offset); + jint next_pc_offset = CodeInstaller::pd_next_offset(inst, pc_offset, hotspot_method); + + if (debug_info != NULL) { + _debug_recorder->add_safepoint(next_pc_offset, create_oop_map(debug_info)); + record_scope(next_pc_offset, debug_info); + } + + if (foreign_call != NULL) { + jlong foreign_call_destination = HotSpotForeignCallTarget::address(foreign_call); + CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination); + } else { // method != NULL + assert(hotspot_method != NULL, "unexpected JavaMethod"); + assert(debug_info != NULL, "debug info expected"); + + TRACE_jvmci_3("method call"); + CodeInstaller::pd_relocate_JavaMethod(hotspot_method, pc_offset); + if (_next_call_type == INVOKESTATIC || _next_call_type == INVOKESPECIAL) { + // Need a static call stub for transitions from compiled to interpreted. + CompiledStaticCall::emit_to_interp_stub(buffer, _instructions->start() + pc_offset); + } + } + + _next_call_type = INVOKE_INVALID; + + if (debug_info != NULL) { + _debug_recorder->end_safepoint(next_pc_offset); + } +} + +void CodeInstaller::site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site) { + oop reference = CompilationResult_DataPatch::reference(site); + if (reference->is_a(CompilationResult_ConstantReference::klass())) { + Handle constant = CompilationResult_ConstantReference::constant(reference); + if (constant->is_a(HotSpotObjectConstantImpl::klass())) { + pd_patch_OopConstant(pc_offset, constant); + } else if (constant->is_a(HotSpotMetaspaceConstantImpl::klass())) { + record_metadata_in_patch(constant, _oop_recorder); + } else if (constant->is_a(HotSpotSentinelConstant::klass())) { + fatal("sentinel constant unsupported"); + } else { + fatal("unknown constant type in data patch"); + } + } else if (reference->is_a(CompilationResult_DataSectionReference::klass())) { + int data_offset = CompilationResult_DataSectionReference::offset(reference); + assert(0 <= data_offset && data_offset < _constants_size, "data offset 0x%X points outside data section (size 0x%X)", data_offset, _constants_size); + pd_patch_DataSectionReference(pc_offset, data_offset); + } else { + fatal("unknown data patch type"); + } +} + +void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, oop site) { + oop id_obj = CompilationResult_Mark::id(site); + + if (id_obj != NULL) { + assert(java_lang_boxing_object::is_instance(id_obj, T_INT), "Integer id expected"); + jint id = id_obj->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT)); + + address pc = _instructions->start() + pc_offset; + + switch (id) { + case UNVERIFIED_ENTRY: + _offsets.set_value(CodeOffsets::Entry, pc_offset); + break; + case VERIFIED_ENTRY: + _offsets.set_value(CodeOffsets::Verified_Entry, pc_offset); + break; + case OSR_ENTRY: + _offsets.set_value(CodeOffsets::OSR_Entry, pc_offset); + break; + case EXCEPTION_HANDLER_ENTRY: + _offsets.set_value(CodeOffsets::Exceptions, pc_offset); + break; + case DEOPT_HANDLER_ENTRY: + _offsets.set_value(CodeOffsets::Deopt, pc_offset); + break; + case INVOKEVIRTUAL: + case INVOKEINTERFACE: + case INLINE_INVOKE: + case INVOKESTATIC: + case INVOKESPECIAL: + _next_call_type = (MarkId) id; + _invoke_mark_pc = pc; + break; + case POLL_NEAR: + case POLL_FAR: + case POLL_RETURN_NEAR: + case POLL_RETURN_FAR: + pd_relocate_poll(pc, id); + break; + case CARD_TABLE_ADDRESS: + case HEAP_TOP_ADDRESS: + case HEAP_END_ADDRESS: + case NARROW_KLASS_BASE_ADDRESS: + case CRC_TABLE_ADDRESS: + break; + default: + ShouldNotReachHere(); + break; + } + } +} + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_CODE_INSTALLER_HPP +#define SHARE_VM_JVMCI_JVMCI_CODE_INSTALLER_HPP + +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "code/nativeInst.hpp" + +class RelocBuffer : public StackObj { + enum { stack_size = 1024 }; +public: + RelocBuffer() : _size(0), _buffer(0) {} + ~RelocBuffer(); + void ensure_size(size_t bytes); + void set_size(size_t bytes); + address begin() const; + size_t size() const { return _size; } +private: + size_t _size; + char _static_buffer[stack_size]; + char *_buffer; +}; + +class CodeMetadata { +public: + CodeMetadata() {} + + CodeBlob* get_code_blob() const { return _cb; } + + PcDesc* get_pc_desc() const { return _pc_desc; } + int get_nr_pc_desc() const { return _nr_pc_desc; } + + u_char* get_scopes_desc() const { return _scopes_desc; } + int get_scopes_size() const { return _nr_scopes_desc; } + + RelocBuffer* get_reloc_buffer() { return &_reloc_buffer; } + + ExceptionHandlerTable* get_exception_table() { return _exception_table; } + + void set_pc_desc(PcDesc* desc, int count) { + _pc_desc = desc; + _nr_pc_desc = count; + } + + void set_scopes(u_char* scopes, int size) { + _scopes_desc = scopes; + _nr_scopes_desc = size; + } + + void set_exception_table(ExceptionHandlerTable* table) { + _exception_table = table; + } + +private: + CodeBlob* _cb; + PcDesc* _pc_desc; + int _nr_pc_desc; + + u_char* _scopes_desc; + int _nr_scopes_desc; + + RelocBuffer _reloc_buffer; + ExceptionHandlerTable* _exception_table; +}; + +/* + * This class handles the conversion from a InstalledCode to a CodeBlob or an nmethod. + */ +class CodeInstaller : public StackObj { + friend class VMStructs; +private: + enum MarkId { + VERIFIED_ENTRY = 1, + UNVERIFIED_ENTRY = 2, + OSR_ENTRY = 3, + EXCEPTION_HANDLER_ENTRY = 4, + DEOPT_HANDLER_ENTRY = 5, + INVOKEINTERFACE = 6, + INVOKEVIRTUAL = 7, + INVOKESTATIC = 8, + INVOKESPECIAL = 9, + INLINE_INVOKE = 10, + POLL_NEAR = 11, + POLL_RETURN_NEAR = 12, + POLL_FAR = 13, + POLL_RETURN_FAR = 14, + CARD_TABLE_ADDRESS = 15, + HEAP_TOP_ADDRESS = 16, + HEAP_END_ADDRESS = 17, + NARROW_KLASS_BASE_ADDRESS = 18, + CRC_TABLE_ADDRESS = 19, + INVOKE_INVALID = -1 + }; + + Arena _arena; + + jobject _data_section_handle; + jobject _data_section_patches_handle; + jobject _sites_handle; + jobject _exception_handlers_handle; + CodeOffsets _offsets; + + jobject _code_handle; + jint _code_size; + jint _total_frame_size; + jint _custom_stack_area_offset; + jint _parameter_count; + jint _constants_size; +#ifndef PRODUCT + jobject _comments_handle; +#endif + + bool _has_wide_vector; + jobject _word_kind_handle; + + MarkId _next_call_type; + address _invoke_mark_pc; + + CodeSection* _instructions; + CodeSection* _constants; + + OopRecorder* _oop_recorder; + DebugInformationRecorder* _debug_recorder; + Dependencies* _dependencies; + ExceptionHandlerTable _exception_handler_table; + + static ConstantOopWriteValue* _oop_null_scope_value; + static ConstantIntValue* _int_m1_scope_value; + static ConstantIntValue* _int_0_scope_value; + static ConstantIntValue* _int_1_scope_value; + static ConstantIntValue* _int_2_scope_value; + static LocationValue* _illegal_value; + + jint pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method); + void pd_patch_OopConstant(int pc_offset, Handle& constant); + void pd_patch_DataSectionReference(int pc_offset, int data_offset); + void pd_relocate_CodeBlob(CodeBlob* cb, NativeInstruction* inst); + void pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination); + void pd_relocate_JavaMethod(oop method, jint pc_offset); + void pd_relocate_poll(address pc, jint mark); + + objArrayOop sites() { return (objArrayOop) JNIHandles::resolve(_sites_handle); } + arrayOop code() { return (arrayOop) JNIHandles::resolve(_code_handle); } + arrayOop data_section() { return (arrayOop) JNIHandles::resolve(_data_section_handle); } + objArrayOop data_section_patches() { return (objArrayOop) JNIHandles::resolve(_data_section_patches_handle); } + objArrayOop exception_handlers() { return (objArrayOop) JNIHandles::resolve(_exception_handlers_handle); } +#ifndef PRODUCT + objArrayOop comments() { return (objArrayOop) JNIHandles::resolve(_comments_handle); } +#endif + + void record_resolved(oop obj); + + oop word_kind() { return (oop) JNIHandles::resolve(_word_kind_handle); } + +public: + CodeInstaller() : _arena(mtCompiler) {} + + JVMCIEnv::CodeInstallResult gather_metadata(Handle target, Handle& compiled_code, CodeMetadata& metadata); + JVMCIEnv::CodeInstallResult install(JVMCICompiler* compiler, Handle target, Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle speculation_log); + + static address runtime_call_target_address(oop runtime_call); + static VMReg get_hotspot_reg(jint jvmciRegisterNumber); + static bool is_general_purpose_reg(VMReg hotspotRegister); + + const OopMapSet* oopMapSet() const { return _debug_recorder->_oopmaps; } + +protected: + Location::Type get_oop_type(oop value); + ScopeValue* get_scope_value(oop value, BasicType type, GrowableArray* objects, ScopeValue* &second); + MonitorValue* get_monitor_value(oop value, GrowableArray* objects); + + // extract the fields of the CompilationResult + void initialize_fields(oop target, oop target_method); + void initialize_dependencies(oop target_method, OopRecorder* oop_recorder); + + int estimate_stubs_size(); + + // perform data and call relocation on the CodeBuffer + JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer); + + void assumption_NoFinalizableSubclass(Handle assumption); + void assumption_ConcreteSubtype(Handle assumption); + void assumption_LeafType(Handle assumption); + void assumption_ConcreteMethod(Handle assumption); + void assumption_CallSiteTargetValue(Handle assumption); + + void site_Safepoint(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Infopoint(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Call(CodeBuffer& buffer, jint pc_offset, oop site); + void site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site); + void site_Mark(CodeBuffer& buffer, jint pc_offset, oop site); + + OopMap* create_oop_map(oop debug_info); + + void record_scope(jint pc_offset, oop debug_info); + void record_scope(jint pc_offset, oop code_pos, GrowableArray* objects); + void record_object_value(ObjectValue* sv, oop value, GrowableArray* objects); + + GrowableArray* record_virtual_objects(oop debug_info); + + void process_exception_handlers(); + int estimateStubSpace(int static_call_stubs); +}; + +/** + * Gets the Method metaspace object from a HotSpotResolvedJavaMethodImpl Java object. + */ +Method* getMethodFromHotSpotMethod(oop hotspot_method); + + + +#endif // SHARE_VM_JVMCI_JVMCI_CODE_INSTALLER_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciCompiler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/handles.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "runtime/compilationPolicy.hpp" +#include "runtime/globals_extension.hpp" + +JVMCICompiler* JVMCICompiler::_instance = NULL; +elapsedTimer JVMCICompiler::_codeInstallTimer; + +JVMCICompiler::JVMCICompiler() : AbstractCompiler(jvmci) { + _bootstrapping = false; + _methodsCompiled = 0; + assert(_instance == NULL, "only one instance allowed"); + _instance = this; +} + +// Initialization +void JVMCICompiler::initialize() { + if (!UseCompiler || !EnableJVMCI || !UseJVMCICompiler || !should_perform_init()) { + return; + } + + set_state(initialized); + + // JVMCI is considered as application code so we need to + // stop the VM deferring compilation now. + CompilationPolicy::completed_vm_startup(); +} + +void JVMCICompiler::bootstrap() { +#ifndef PRODUCT + // We turn off CompileTheWorld so that compilation requests are not + // ignored during bootstrap or that JVMCI can be compiled by C1/C2. + FlagSetting ctwOff(CompileTheWorld, false); +#endif + + JavaThread* THREAD = JavaThread::current(); + _bootstrapping = true; + ResourceMark rm; + HandleMark hm; + if (PrintBootstrap) { + tty->print("Bootstrapping JVMCI"); + } + jlong start = os::javaTimeMillis(); + + Array* objectMethods = InstanceKlass::cast(SystemDictionary::Object_klass())->methods(); + // Initialize compile queue with a selected set of methods. + int len = objectMethods->length(); + for (int i = 0; i < len; i++) { + methodHandle mh = objectMethods->at(i); + if (!mh->is_native() && !mh->is_static() && !mh->is_initializer()) { + ResourceMark rm; + int hot_count = 10; // TODO: what's the appropriate value? + CompileBroker::compile_method(mh, InvocationEntryBci, CompLevel_full_optimization, mh, hot_count, "bootstrap", THREAD); + } + } + + int qsize; + bool first_round = true; + int z = 0; + do { + // Loop until there is something in the queue. + do { + os::sleep(THREAD, 100, true); + qsize = CompileBroker::queue_size(CompLevel_full_optimization); + } while (first_round && qsize == 0); + first_round = false; + if (PrintBootstrap) { + while (z < (_methodsCompiled / 100)) { + ++z; + tty->print_raw("."); + } + } + } while (qsize != 0); + + if (PrintBootstrap) { + tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methodsCompiled); + } + _bootstrapping = false; +} + +void JVMCICompiler::compile_method(methodHandle method, int entry_bci, JVMCIEnv* env) { + JVMCI_EXCEPTION_CONTEXT + + bool is_osr = entry_bci != InvocationEntryBci; + if (_bootstrapping && is_osr) { + // no OSR compilations during bootstrap - the compiler is just too slow at this point, + // and we know that there are no endless loops + return; + } + + JVMCIRuntime::initialize_well_known_classes(CHECK_ABORT); + + HandleMark hm; + ResourceMark rm; + Handle receiver = JVMCIRuntime::get_HotSpotJVMCIRuntime(CHECK_ABORT); + + JavaValue method_result(T_OBJECT); + { + JavaCallArguments args; + args.push_long((jlong) (address) method()); + JavaCalls::call_static(&method_result, SystemDictionary::HotSpotResolvedJavaMethodImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::method_fromMetaspace_signature(), &args, CHECK_ABORT); + } + + JavaValue result(T_VOID); + JavaCallArguments args; + args.push_oop(receiver); + args.push_oop((oop)method_result.get_jobject()); + args.push_int(entry_bci); + args.push_long((jlong) (address) env); + args.push_int(env->task()->compile_id()); + JavaCalls::call_special(&result, receiver->klass(), vmSymbols::compileMethod_name(), vmSymbols::compileMethod_signature(), &args, CHECK_ABORT); + + _methodsCompiled++; +} + + +// Compilation entry point for methods +void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) { + ShouldNotReachHere(); +} + +// Print compilation timers and statistics +void JVMCICompiler::print_timers() { + print_compilation_timers(); +} + +// Print compilation timers and statistics +void JVMCICompiler::print_compilation_timers() { + TRACE_jvmci_1("JVMCICompiler::print_timers"); + tty->print_cr(" JVMCI code install time: %6.3f s", _codeInstallTimer.seconds()); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciCompiler.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_COMPILER_HPP +#define SHARE_VM_JVMCI_JVMCI_COMPILER_HPP + +#include "compiler/abstractCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "utilities/exceptions.hpp" + +class JVMCICompiler : public AbstractCompiler { +private: + bool _bootstrapping; + + /** + * Number of methods compiled by JVMCI. This is not synchronized + * so may not be 100% accurate. + */ + volatile int _methodsCompiled; + + static JVMCICompiler* _instance; + + static elapsedTimer _codeInstallTimer; + +public: + JVMCICompiler(); + + static JVMCICompiler* instance(TRAPS) { + if (!EnableJVMCI) { + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled") + } + return _instance; + } + + virtual const char* name() { return "JVMCI"; } + + virtual bool supports_native() { return true; } + virtual bool supports_osr () { return true; } + + bool is_jvmci() { return true; } + bool is_c1 () { return false; } + bool is_c2 () { return false; } + + bool needs_stubs () { return false; } + + // Initialization + virtual void initialize(); + + void bootstrap(); + + // Compilation entry point for methods + virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci); + + void compile_method(methodHandle target, int entry_bci, JVMCIEnv* env); + + // Print compilation timers and statistics + virtual void print_timers(); + + // Print compilation statistics + void reset_compilation_stats(); + + // Print compilation timers and statistics + static void print_compilation_timers(); + + static elapsedTimer* codeInstallTimer() { return &_codeInstallTimer; } +}; + +#endif // SHARE_VM_JVMCI_JVMCI_COMPILER_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1370 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "code/codeCache.hpp" +#include "code/scopeDesc.hpp" +#include "interpreter/linkResolver.hpp" +#include "memory/oopFactory.hpp" +#include "oops/generateOopMap.hpp" +#include "oops/fieldStreams.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "runtime/fieldDescriptor.hpp" +#include "runtime/javaCalls.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "compiler/abstractCompiler.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/compilerOracle.hpp" +#include "compiler/disassembler.hpp" +#include "compiler/oopMap.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "gc/g1/heapRegion.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/vframe.hpp" +#include "runtime/vframe_hp.hpp" +#include "runtime/vmStructs.hpp" + + +// Entry to native method implementation that transitions current thread to '_thread_in_vm'. +#define C2V_VMENTRY(result_type, name, signature) \ + JNIEXPORT result_type JNICALL c2v_ ## name signature { \ + TRACE_jvmci_1("CompilerToVM::" #name); \ + TRACE_CALL(result_type, jvmci_ ## name signature) \ + JVMCI_VM_ENTRY_MARK; \ + +#define C2V_END } + +oop CompilerToVM::get_jvmci_method(methodHandle method, TRAPS) { + if (method() != NULL) { + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_long((jlong) (address) method()); + JavaCalls::call_static(&result, SystemDictionary::HotSpotResolvedJavaMethodImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::method_fromMetaspace_signature(), &args, CHECK_NULL); + + return (oop)result.get_jobject(); + } + return NULL; +} + +oop CompilerToVM::get_jvmci_type(KlassHandle klass, TRAPS) { + if (klass() != NULL) { + JavaValue result(T_OBJECT); + JavaCallArguments args; + args.push_oop(klass->java_mirror()); + JavaCalls::call_static(&result, SystemDictionary::HotSpotResolvedObjectTypeImpl_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::klass_fromMetaspace_signature(), &args, CHECK_NULL); + + return (oop)result.get_jobject(); + } + return NULL; +} + +extern "C" { +extern VMStructEntry* gHotSpotVMStructs; +extern uint64_t gHotSpotVMStructEntryTypeNameOffset; +extern uint64_t gHotSpotVMStructEntryFieldNameOffset; +extern uint64_t gHotSpotVMStructEntryTypeStringOffset; +extern uint64_t gHotSpotVMStructEntryIsStaticOffset; +extern uint64_t gHotSpotVMStructEntryOffsetOffset; +extern uint64_t gHotSpotVMStructEntryAddressOffset; +extern uint64_t gHotSpotVMStructEntryArrayStride; + +extern VMTypeEntry* gHotSpotVMTypes; +extern uint64_t gHotSpotVMTypeEntryTypeNameOffset; +extern uint64_t gHotSpotVMTypeEntrySuperclassNameOffset; +extern uint64_t gHotSpotVMTypeEntryIsOopTypeOffset; +extern uint64_t gHotSpotVMTypeEntryIsIntegerTypeOffset; +extern uint64_t gHotSpotVMTypeEntryIsUnsignedOffset; +extern uint64_t gHotSpotVMTypeEntrySizeOffset; +extern uint64_t gHotSpotVMTypeEntryArrayStride; + +extern VMIntConstantEntry* gHotSpotVMIntConstants; +extern uint64_t gHotSpotVMIntConstantEntryNameOffset; +extern uint64_t gHotSpotVMIntConstantEntryValueOffset; +extern uint64_t gHotSpotVMIntConstantEntryArrayStride; + +extern VMLongConstantEntry* gHotSpotVMLongConstants; +extern uint64_t gHotSpotVMLongConstantEntryNameOffset; +extern uint64_t gHotSpotVMLongConstantEntryValueOffset; +extern uint64_t gHotSpotVMLongConstantEntryArrayStride; + +extern VMAddressEntry* gHotSpotVMAddresses; +extern uint64_t gHotSpotVMAddressEntryNameOffset; +extern uint64_t gHotSpotVMAddressEntryValueOffset; +extern uint64_t gHotSpotVMAddressEntryArrayStride; +} + +// FIXME This is only temporary until the GC code is changed. +bool CompilerToVM::_supports_inline_contig_alloc; +HeapWord** CompilerToVM::_heap_end_addr; +HeapWord** CompilerToVM::_heap_top_addr; + +/** + * We put all gHotSpotVM values in an array so we can read them easily from Java. + */ +static uintptr_t ciHotSpotVMData[28]; + +C2V_VMENTRY(jlong, initializeConfiguration, (JNIEnv *env, jobject)) + ciHotSpotVMData[0] = (uintptr_t) gHotSpotVMStructs; + ciHotSpotVMData[1] = gHotSpotVMStructEntryTypeNameOffset; + ciHotSpotVMData[2] = gHotSpotVMStructEntryFieldNameOffset; + ciHotSpotVMData[3] = gHotSpotVMStructEntryTypeStringOffset; + ciHotSpotVMData[4] = gHotSpotVMStructEntryIsStaticOffset; + ciHotSpotVMData[5] = gHotSpotVMStructEntryOffsetOffset; + ciHotSpotVMData[6] = gHotSpotVMStructEntryAddressOffset; + ciHotSpotVMData[7] = gHotSpotVMStructEntryArrayStride; + + ciHotSpotVMData[8] = (uintptr_t) gHotSpotVMTypes; + ciHotSpotVMData[9] = gHotSpotVMTypeEntryTypeNameOffset; + ciHotSpotVMData[10] = gHotSpotVMTypeEntrySuperclassNameOffset; + ciHotSpotVMData[11] = gHotSpotVMTypeEntryIsOopTypeOffset; + ciHotSpotVMData[12] = gHotSpotVMTypeEntryIsIntegerTypeOffset; + ciHotSpotVMData[13] = gHotSpotVMTypeEntryIsUnsignedOffset; + ciHotSpotVMData[14] = gHotSpotVMTypeEntrySizeOffset; + ciHotSpotVMData[15] = gHotSpotVMTypeEntryArrayStride; + + ciHotSpotVMData[16] = (uintptr_t) gHotSpotVMIntConstants; + ciHotSpotVMData[17] = gHotSpotVMIntConstantEntryNameOffset; + ciHotSpotVMData[18] = gHotSpotVMIntConstantEntryValueOffset; + ciHotSpotVMData[19] = gHotSpotVMIntConstantEntryArrayStride; + + ciHotSpotVMData[20] = (uintptr_t) gHotSpotVMLongConstants; + ciHotSpotVMData[21] = gHotSpotVMLongConstantEntryNameOffset; + ciHotSpotVMData[22] = gHotSpotVMLongConstantEntryValueOffset; + ciHotSpotVMData[23] = gHotSpotVMLongConstantEntryArrayStride; + + ciHotSpotVMData[24] = (uintptr_t) gHotSpotVMAddresses; + ciHotSpotVMData[25] = gHotSpotVMAddressEntryNameOffset; + ciHotSpotVMData[26] = gHotSpotVMAddressEntryValueOffset; + ciHotSpotVMData[27] = gHotSpotVMAddressEntryArrayStride; + + // FIXME This is only temporary until the GC code is changed. + CompilerToVM::_supports_inline_contig_alloc = Universe::heap()->supports_inline_contig_alloc(); + CompilerToVM::_heap_end_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->end_addr() : (HeapWord**) -1; + CompilerToVM::_heap_top_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->top_addr() : (HeapWord**) -1; + + return (jlong) (address) &ciHotSpotVMData; +C2V_END + +C2V_VMENTRY(jbyteArray, getBytecode, (JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + ResourceMark rm; + + int code_size = method->code_size(); + typeArrayOop reconstituted_code = oopFactory::new_byteArray(code_size, CHECK_NULL); + + guarantee(method->method_holder()->is_rewritten(), "Method's holder should be rewritten"); + // iterate over all bytecodes and replace non-Java bytecodes + + for (BytecodeStream s(method); s.next() != Bytecodes::_illegal; ) { + Bytecodes::Code code = s.code(); + Bytecodes::Code raw_code = s.raw_code(); + int bci = s.bci(); + int len = s.instruction_size(); + + // Restore original byte code. + reconstituted_code->byte_at_put(bci, (jbyte) (s.is_wide()? Bytecodes::_wide : code)); + if (len > 1) { + memcpy(reconstituted_code->byte_at_addr(bci + 1), s.bcp()+1, len-1); + } + + if (len > 1) { + // Restore the big-endian constant pool indexes. + // Cf. Rewriter::scan_method + switch (code) { + case Bytecodes::_getstatic: + case Bytecodes::_putstatic: + case Bytecodes::_getfield: + case Bytecodes::_putfield: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokehandle: { + int cp_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1)); + Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index); + break; + } + + case Bytecodes::_invokedynamic: + int cp_index = Bytes::get_native_u4((address) reconstituted_code->byte_at_addr(bci + 1)); + Bytes::put_Java_u4((address) reconstituted_code->byte_at_addr(bci + 1), (u4) cp_index); + break; + } + + // Not all ldc byte code are rewritten. + switch (raw_code) { + case Bytecodes::_fast_aldc: { + int cpc_index = reconstituted_code->byte_at(bci + 1) & 0xff; + int cp_index = method->constants()->object_to_cp_index(cpc_index); + assert(cp_index < method->constants()->length(), "sanity check"); + reconstituted_code->byte_at_put(bci + 1, (jbyte) cp_index); + break; + } + + case Bytecodes::_fast_aldc_w: { + int cpc_index = Bytes::get_native_u2((address) reconstituted_code->byte_at_addr(bci + 1)); + int cp_index = method->constants()->object_to_cp_index(cpc_index); + assert(cp_index < method->constants()->length(), "sanity check"); + Bytes::put_Java_u2((address) reconstituted_code->byte_at_addr(bci + 1), (u2) cp_index); + break; + } + } + } + } + + return (jbyteArray) JNIHandles::make_local(THREAD, reconstituted_code); +C2V_END + +C2V_VMENTRY(jint, getExceptionTableLength, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return method->exception_table_length(); +C2V_END + +C2V_VMENTRY(jlong, getExceptionTableStart, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + methodHandle method = CompilerToVM::asMethod(jvmci_method); + if (method->exception_table_length() == 0) { + return 0L; + } + return (jlong) (address) method->exception_table_start(); +C2V_END + +C2V_VMENTRY(jobject, getResolvedJavaMethodAtSlot, (JNIEnv *, jobject, jclass holder_handle, jint slot)) + oop java_class = JNIHandles::resolve(holder_handle); + Klass* holder = java_lang_Class::as_Klass(java_class); + methodHandle method = InstanceKlass::cast(holder)->method_with_idnum(slot); + oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +} + +C2V_VMENTRY(jobject, getResolvedJavaMethod, (JNIEnv *, jobject, jobject base, jlong offset)) + methodHandle method; + oop base_object = JNIHandles::resolve(base); + if (base_object == NULL) { + method = *((Method**)(offset)); + } else if (base_object->is_a(SystemDictionary::MemberName_klass())) { + method = (Method*) (intptr_t) base_object->long_field(offset); + } else if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + method = *((Method**)(HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object) + offset)); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected type: %s", base_object->klass()->external_name())); + } + assert (method.is_null() || method->is_method(), "invalid read"); + oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +} + +C2V_VMENTRY(jobject, getConstantPool, (JNIEnv *, jobject, jobject base, jlong offset)) + constantPoolHandle cp; + oop base_object = JNIHandles::resolve(base); + jlong base_address = 0; + if (base_object != NULL) { + if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + base_address = HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotConstantPool_klass())) { + base_address = HotSpotConstantPool::metaspaceConstantPool(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { + base_address = (jlong) CompilerToVM::asKlass(base_object); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected type: %s", base_object->klass()->external_name())); + } + } + cp = *((ConstantPool**) (intptr_t) (base_address + offset)); + if (!cp.is_null()) { + JavaValue method_result(T_OBJECT); + JavaCallArguments args; + args.push_long((jlong) (address) cp()); + JavaCalls::call_static(&method_result, SystemDictionary::HotSpotConstantPool_klass(), vmSymbols::fromMetaspace_name(), vmSymbols::constantPool_fromMetaspace_signature(), &args, CHECK_NULL); + return JNIHandles::make_local(THREAD, (oop)method_result.get_jobject()); + } + return NULL; +} + +C2V_VMENTRY(jobject, getResolvedJavaType, (JNIEnv *, jobject, jobject base, jlong offset, jboolean compressed)) + KlassHandle klass; + oop base_object = JNIHandles::resolve(base); + jlong base_address = 0; + if (base_object != NULL && offset == oopDesc::klass_offset_in_bytes()) { + klass = base_object->klass(); + } else if (!compressed) { + if (base_object != NULL) { + if (base_object->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + base_address = HotSpotResolvedJavaMethodImpl::metaspaceMethod(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotConstantPool_klass())) { + base_address = HotSpotConstantPool::metaspaceConstantPool(base_object); + } else if (base_object->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { + base_address = (jlong) CompilerToVM::asKlass(base_object); + } else if (base_object->is_a(SystemDictionary::Class_klass())) { + base_address = (jlong) (address) base_object; + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected arguments: %s " JLONG_FORMAT " %s", base_object->klass()->external_name(), offset, compressed ? "true" : "false")); + } + } + klass = *((Klass**) (intptr_t) (base_address + offset)); + } else { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Unexpected arguments: %s " JLONG_FORMAT " %s", base_object->klass()->external_name(), offset, compressed ? "true" : "false")); + } + assert (klass.is_null() || klass->is_klass(), "invalid read"); + oop result = CompilerToVM::get_jvmci_type(klass, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +} + +C2V_VMENTRY(jobject, findUniqueConcreteMethod, (JNIEnv *, jobject, jobject jvmci_type, jobject jvmci_method)) + ResourceMark rm; + methodHandle method = CompilerToVM::asMethod(jvmci_method); + KlassHandle holder = CompilerToVM::asKlass(jvmci_type); + if (holder->is_interface()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Interface %s should be handled in Java code", holder->external_name())); + } + + methodHandle ucm; + { + MutexLocker locker(Compile_lock); + ucm = Dependencies::find_unique_concrete_method(holder(), method()); + } + oop result = CompilerToVM::get_jvmci_method(ucm, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jobject, getImplementor, (JNIEnv *, jobject, jobject jvmci_type)) + InstanceKlass* klass = (InstanceKlass*) CompilerToVM::asKlass(jvmci_type); + oop implementor = CompilerToVM::get_jvmci_type(klass->implementor(), CHECK_NULL); + return JNIHandles::make_local(THREAD, implementor); +C2V_END + +C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return method->is_ignored_by_security_stack_walk(); +C2V_END + +C2V_VMENTRY(jboolean, canInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return !method->is_not_compilable() && !CompilerOracle::should_not_inline(method) && !method->dont_inline(); +C2V_END + +C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return CompilerOracle::should_inline(method) || method->force_inline(); +C2V_END + +C2V_VMENTRY(jobject, lookupType, (JNIEnv*, jobject, jstring jname, jclass accessing_class, jboolean resolve)) + ResourceMark rm; + Handle name = JNIHandles::resolve(jname); + Symbol* class_name = java_lang_String::as_symbol(name, CHECK_0); + if (java_lang_String::length(name()) <= 1) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Primitive type %s should be handled in Java code", class_name->as_C_string())); + } + + Klass* resolved_klass = NULL; + Handle class_loader; + Handle protection_domain; + if (JNIHandles::resolve(accessing_class) == NULL) { + THROW_0(vmSymbols::java_lang_NullPointerException()); + } + Klass* accessing_klass = java_lang_Class::as_Klass(JNIHandles::resolve(accessing_class)); + class_loader = accessing_klass->class_loader(); + protection_domain = accessing_klass->protection_domain(); + + if (resolve) { + resolved_klass = SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK_0); + } else { + if (class_name->byte_at(0) == 'L' && + class_name->byte_at(class_name->utf8_length()-1) == ';') { + // This is a name from a signature. Strip off the trimmings. + // Call recursive to keep scope of strippedsym. + TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1, + class_name->utf8_length()-2, + CHECK_0); + resolved_klass = SystemDictionary::find(strippedsym, class_loader, protection_domain, CHECK_0); + } else if (FieldType::is_array(class_name)) { + FieldArrayInfo fd; + // dimension and object_key in FieldArrayInfo are assigned as a side-effect + // of this call + BasicType t = FieldType::get_array_info(class_name, fd, CHECK_0); + if (t == T_OBJECT) { + TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1+fd.dimension(), + class_name->utf8_length()-2-fd.dimension(), + CHECK_0); + // naked oop "k" is OK here -- we assign back into it + resolved_klass = SystemDictionary::find(strippedsym, + class_loader, + protection_domain, + CHECK_0); + if (resolved_klass != NULL) { + resolved_klass = resolved_klass->array_klass(fd.dimension(), CHECK_0); + } + } else { + resolved_klass = Universe::typeArrayKlassObj(t); + resolved_klass = TypeArrayKlass::cast(resolved_klass)->array_klass(fd.dimension(), CHECK_0); + } + } + } + Handle result = CompilerToVM::get_jvmci_type(resolved_klass, CHECK_NULL); + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + oop result = cp->resolve_constant_at(index, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + return cp->name_and_type_ref_index_at(index); +C2V_END + +C2V_VMENTRY(jobject, lookupNameInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint which)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Handle sym = java_lang_String::create_from_symbol(cp->name_ref_at(which), CHECK_NULL); + return JNIHandles::make_local(THREAD, sym()); +C2V_END + +C2V_VMENTRY(jobject, lookupSignatureInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint which)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Handle sym = java_lang_String::create_from_symbol(cp->signature_ref_at(which), CHECK_NULL); + return JNIHandles::make_local(THREAD, sym()); +C2V_END + +C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + return cp->klass_ref_index_at(index); +C2V_END + +C2V_VMENTRY(jobject, resolveTypeInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Klass* resolved_klass = cp->klass_at(index, CHECK_NULL); + Handle klass = CompilerToVM::get_jvmci_type(resolved_klass, CHECK_NULL); + return JNIHandles::make_local(THREAD, klass()); +C2V_END + +C2V_VMENTRY(jobject, lookupKlassInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + KlassHandle loading_klass(cp->pool_holder()); + bool is_accessible = false; + KlassHandle klass = JVMCIEnv::get_klass_by_index(cp, index, is_accessible, loading_klass); + Symbol* symbol = NULL; + if (klass.is_null()) { + symbol = cp->klass_name_at(index); + } + Handle result; + if (!klass.is_null()) { + result = CompilerToVM::get_jvmci_type(klass, CHECK_NULL); + } else { + result = java_lang_String::create_from_symbol(symbol, CHECK_NULL); + } + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index); + return JNIHandles::make_local(THREAD, appendix_oop); +C2V_END + +C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + instanceKlassHandle pool_holder(cp->pool_holder()); + Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF); + methodHandle method = JVMCIEnv::get_method_by_index(cp, index, bc, pool_holder); + oop result = CompilerToVM::get_jvmci_method(method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + return cp->remap_instruction_operand_from_cache(index); +C2V_END + +C2V_VMENTRY(jobject, resolveFieldInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode, jlongArray info_handle)) + ResourceMark rm; + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF); + fieldDescriptor fd; + LinkInfo link_info(cp, index, CHECK_0); + LinkResolver::resolve_field(fd, link_info, Bytecodes::java_code(code), false, CHECK_0); + typeArrayOop info = (typeArrayOop) JNIHandles::resolve(info_handle); + assert(info != NULL && info->length() == 2, "must be"); + info->long_at_put(0, (jlong) fd.access_flags().as_int()); + info->long_at_put(1, (jlong) fd.offset()); + oop field_holder = CompilerToVM::get_jvmci_type(fd.field_holder(), CHECK_NULL); + return JNIHandles::make_local(THREAD, field_holder); +C2V_END + +C2V_VMENTRY(jint, getVtableIndexForInterfaceMethod, (JNIEnv *, jobject, jobject jvmci_type, jobject jvmci_method)) + ResourceMark rm; + Klass* klass = CompilerToVM::asKlass(jvmci_type); + Method* method = CompilerToVM::asMethod(jvmci_method); + if (klass->is_interface()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Interface %s should be handled in Java code", klass->external_name())); + } + if (!method->method_holder()->is_interface()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Method %s is not held by an interface, this case should be handled in Java code", method->name_and_sig_as_C_string())); + } + if (!InstanceKlass::cast(klass)->is_initialized()) { + THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("Class %s must be initialized", klass->external_name())); + } + return LinkResolver::vtable_index_of_interface_method(klass, method); +C2V_END + +C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_type, jobject jvmci_method, jobject caller_jvmci_type)) + Klass* recv_klass = CompilerToVM::asKlass(receiver_jvmci_type); + Klass* caller_klass = CompilerToVM::asKlass(caller_jvmci_type); + Method* method = CompilerToVM::asMethod(jvmci_method); + + if (recv_klass->oop_is_array() || (InstanceKlass::cast(recv_klass)->is_linked())) { + Klass* holder_klass = method->method_holder(); + Symbol* method_name = method->name(); + Symbol* method_signature = method->signature(); + + if (holder_klass->is_interface()) { + // do link-time resolution to check all access rules. + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + methodHandle resolved_method = LinkResolver::linktime_resolve_interface_method_or_null(link_info); + if (resolved_method.is_null() || resolved_method->is_private()) { + return NULL; + } + assert(recv_klass->is_subtype_of(holder_klass), ""); + // do actual lookup + methodHandle sel_method = LinkResolver::lookup_instance_method_in_klasses(recv_klass, resolved_method->name(), resolved_method->signature(), CHECK_AND_CLEAR_0); + oop result = CompilerToVM::get_jvmci_method(sel_method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); + } else { + // do link-time resolution to check all access rules. + LinkInfo link_info(holder_klass, method_name, method_signature, caller_klass, true); + methodHandle resolved_method = LinkResolver::linktime_resolve_virtual_method_or_null(link_info); + if (resolved_method.is_null()) { + return NULL; + } + // do actual lookup (see LinkResolver::runtime_resolve_virtual_method) + int vtable_index = Method::invalid_vtable_index; + Method* selected_method; + + if (resolved_method->method_holder()->is_interface()) { // miranda method + vtable_index = LinkResolver::vtable_index_of_interface_method(holder_klass, resolved_method); + assert(vtable_index >= 0 , "we should have valid vtable index at this point"); + + InstanceKlass* inst = InstanceKlass::cast(recv_klass); + selected_method = inst->method_at_vtable(vtable_index); + } else { + // at this point we are sure that resolved_method is virtual and not + // a miranda method; therefore, it must have a valid vtable index. + assert(!resolved_method->has_itable_index(), ""); + vtable_index = resolved_method->vtable_index(); + // We could get a negative vtable_index for final methods, + // because as an optimization they are they are never put in the vtable, + // unless they override an existing method. + // If we do get a negative, it means the resolved method is the the selected + // method, and it can never be changed by an override. + if (vtable_index == Method::nonvirtual_vtable_index) { + assert(resolved_method->can_be_statically_bound(), "cannot override this method"); + selected_method = resolved_method(); + } else { + // recv_klass might be an arrayKlassOop but all vtables start at + // the same place. The cast is to avoid virtual call and assertion. + InstanceKlass* inst = (InstanceKlass*)recv_klass; + selected_method = inst->method_at_vtable(vtable_index); + } + } + oop result = CompilerToVM::get_jvmci_method(selected_method, CHECK_NULL); + return JNIHandles::make_local(THREAD, result); + } + } + return NULL; +C2V_END + +C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv *, jobject, jobject jvmci_type)) + Klass* klass = CompilerToVM::asKlass(jvmci_type); + assert(klass != NULL, "method must not be called for primitive types"); + return Dependencies::find_finalizable_subclass(klass) != NULL; +C2V_END + +C2V_VMENTRY(jobject, getClassInitializer, (JNIEnv *, jobject, jobject jvmci_type)) + InstanceKlass* klass = (InstanceKlass*) CompilerToVM::asKlass(jvmci_type); + oop result = CompilerToVM::get_jvmci_method(klass->class_initializer(), CHECK_NULL); + return JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv*, jobject, jlong addr)) + address target_addr = (address) addr; + if (target_addr != 0x0) { + int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int)); + int64_t off_high = (int64_t)target_addr - ((int64_t)CodeCache::high_bound() + sizeof(int)); + return MAX2(ABS(off_low), ABS(off_high)); + } + return -1; +C2V_END + +C2V_VMENTRY(void, doNotInlineOrCompile,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + method->set_not_c1_compilable(); + method->set_not_c2_compilable(); + method->set_dont_inline(true); +C2V_END + +C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject target, jobject compiled_code, jobject installed_code, jobject speculation_log)) + ResourceMark rm; + HandleMark hm; + Handle target_handle = JNIHandles::resolve(target); + Handle compiled_code_handle = JNIHandles::resolve(compiled_code); + CodeBlob* cb = NULL; + Handle installed_code_handle = JNIHandles::resolve(installed_code); + Handle speculation_log_handle = JNIHandles::resolve(speculation_log); + + JVMCICompiler* compiler = JVMCICompiler::instance(CHECK_JNI_ERR); + + TraceTime install_time("installCode", JVMCICompiler::codeInstallTimer()); + CodeInstaller installer; + JVMCIEnv::CodeInstallResult result = installer.install(compiler, target_handle, compiled_code_handle, cb, installed_code_handle, speculation_log_handle); + + if (PrintCodeCacheOnCompilation) { + stringStream s; + // Dump code cache into a buffer before locking the tty, + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeCache::print_summary(&s, false); + } + ttyLocker ttyl; + tty->print_raw_cr(s.as_string()); + } + + if (result != JVMCIEnv::ok) { + assert(cb == NULL, "should be"); + } else { + if (!installed_code_handle.is_null()) { + assert(installed_code_handle->is_a(InstalledCode::klass()), "wrong type"); + InstalledCode::set_address(installed_code_handle, (jlong) cb); + InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1); + if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { + HotSpotInstalledCode::set_size(installed_code_handle, cb->size()); + HotSpotInstalledCode::set_codeStart(installed_code_handle, (jlong) cb->code_begin()); + HotSpotInstalledCode::set_codeSize(installed_code_handle, cb->code_size()); + } + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL && installed_code_handle->is_scavengable()) { + assert(nm->detect_scavenge_root_oops(), "nm should be scavengable if installed_code is scavengable"); + if (!UseG1GC) { + assert(nm->on_scavenge_root_list(), "nm should be on scavengable list"); + } + } + } + } + return result; +C2V_END + +C2V_VMENTRY(jint, getMetadata, (JNIEnv *jniEnv, jobject, jobject target, jobject compiled_code, jobject metadata)) + ResourceMark rm; + HandleMark hm; + + Handle target_handle = JNIHandles::resolve(target); + Handle compiled_code_handle = JNIHandles::resolve(compiled_code); + Handle metadata_handle = JNIHandles::resolve(metadata); + + HotSpotOopMap::klass()->initialize(thread); + + CodeMetadata code_metadata; + CodeBlob *cb = NULL; + CodeInstaller installer; + + JVMCIEnv::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata); //cb, pc_descs, nr_pc_descs, scopes_descs, scopes_size, reloc_buffer); + if (result != JVMCIEnv::ok) { + return result; + } + + if (code_metadata.get_nr_pc_desc() > 0) { + typeArrayHandle pcArrayOop = oopFactory::new_byteArray(sizeof(PcDesc) * code_metadata.get_nr_pc_desc(), CHECK_(JVMCIEnv::cache_full)); + memcpy(pcArrayOop->byte_at_addr(0), code_metadata.get_pc_desc(), sizeof(PcDesc) * code_metadata.get_nr_pc_desc()); + HotSpotMetaData::set_pcDescBytes(metadata_handle, pcArrayOop()); + } + + if (code_metadata.get_scopes_size() > 0) { + typeArrayHandle scopesArrayOop = oopFactory::new_byteArray(code_metadata.get_scopes_size(), CHECK_(JVMCIEnv::cache_full)); + memcpy(scopesArrayOop->byte_at_addr(0), code_metadata.get_scopes_desc(), code_metadata.get_scopes_size()); + HotSpotMetaData::set_scopesDescBytes(metadata_handle, scopesArrayOop()); + } + + RelocBuffer* reloc_buffer = code_metadata.get_reloc_buffer(); + typeArrayHandle relocArrayOop = oopFactory::new_byteArray((int) reloc_buffer->size(), CHECK_(JVMCIEnv::cache_full)); + if (reloc_buffer->size() > 0) { + memcpy(relocArrayOop->byte_at_addr(0), reloc_buffer->begin(), reloc_buffer->size()); + } + HotSpotMetaData::set_relocBytes(metadata_handle, relocArrayOop()); + + const OopMapSet* oopMapSet = installer.oopMapSet(); + { + ResourceMark mark; + ImmutableOopMapBuilder builder(oopMapSet); + int oopmap_size = builder.heap_size(); + typeArrayHandle oopMapArrayHandle = oopFactory::new_byteArray(oopmap_size, CHECK_(JVMCIEnv::cache_full)); + builder.generate_into((address) oopMapArrayHandle->byte_at_addr(0)); + HotSpotMetaData::set_oopMaps(metadata_handle, oopMapArrayHandle()); + } + + HotSpotMetaData::set_metadata(metadata_handle, NULL); + + ExceptionHandlerTable* handler = code_metadata.get_exception_table(); + int table_size = handler->size_in_bytes(); + typeArrayHandle exceptionArrayOop = oopFactory::new_byteArray(table_size, CHECK_(JVMCIEnv::cache_full)); + + if (table_size > 0) { + handler->copy_bytes_to((address) exceptionArrayOop->byte_at_addr(0)); + } + HotSpotMetaData::set_exceptionBytes(metadata_handle, exceptionArrayOop()); + + return result; +C2V_END + +C2V_VMENTRY(void, notifyCompilationStatistics, (JNIEnv *jniEnv, jobject, jint id, jobject hotspot_method, jboolean osr, jint processedBytecodes, jlong time, jlong timeUnitsPerSecond, jobject installed_code)) + JVMCICompiler* compiler = JVMCICompiler::instance(CHECK); + CompilerStatistics* stats = compiler->stats(); + + elapsedTimer timer = elapsedTimer(time, timeUnitsPerSecond); + if (osr) { + stats->_osr.update(timer, processedBytecodes); + } else { + stats->_standard.update(timer, processedBytecodes); + } + Handle installed_code_handle = JNIHandles::resolve(installed_code); + if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { + stats->_nmethods_size += HotSpotInstalledCode::size(installed_code_handle); + stats->_nmethods_code_size += HotSpotInstalledCode::codeSize(installed_code_handle); + } + + if (CITimeEach) { + methodHandle method = CompilerToVM::asMethod(hotspot_method); + float bytes_per_sec = 1.0 * processedBytecodes / timer.seconds(); + tty->print_cr("%3d seconds: %f bytes/sec: %f (bytes %d)", + id, timer.seconds(), bytes_per_sec, processedBytecodes); + } +C2V_END + +C2V_VMENTRY(void, resetCompilationStatistics, (JNIEnv *jniEnv, jobject)) + JVMCICompiler* compiler = JVMCICompiler::instance(CHECK); + CompilerStatistics* stats = compiler->stats(); + stats->_standard.reset(); + stats->_osr.reset(); +C2V_END + +C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv *jniEnv, jobject, jlong codeBlob)) + ResourceMark rm; + HandleMark hm; + + CodeBlob* cb = (CodeBlob*) (address) codeBlob; + if (cb == NULL) { + return NULL; + } + + // We don't want the stringStream buffer to resize during disassembly as it + // uses scoped resource memory. If a nested function called during disassembly uses + // a ResourceMark and the buffer expands within the scope of the mark, + // the buffer becomes garbage when that scope is exited. Experience shows that + // the disassembled code is typically about 10x the code size so a fixed buffer + // sized to 20x code size plus a fixed amount for header info should be sufficient. + int bufferSize = cb->code_size() * 20 + 1024; + char* buffer = NEW_RESOURCE_ARRAY(char, bufferSize); + stringStream st(buffer, bufferSize); + if (cb->is_nmethod()) { + nmethod* nm = (nmethod*) cb; + if (!nm->is_alive()) { + return NULL; + } + Disassembler::decode(nm, &st); + } else { + Disassembler::decode(cb, &st); + } + if (st.size() <= 0) { + return NULL; + } + + Handle result = java_lang_String::create_from_platform_dependent_str(st.as_string(), CHECK_NULL); + return JNIHandles::make_local(THREAD, result()); +C2V_END + +C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv*, jobject, jobject jvmci_method, int bci)) + ResourceMark rm; + HandleMark hm; + + methodHandle method = CompilerToVM::asMethod(jvmci_method); + oop element = java_lang_StackTraceElement::create(method, bci, CHECK_NULL); + return JNIHandles::make_local(THREAD, element); +C2V_END + +C2V_VMENTRY(jobject, executeInstalledCode, (JNIEnv*, jobject, jobject args, jobject hotspotInstalledCode)) + ResourceMark rm; + HandleMark hm; + + jlong nmethodValue = InstalledCode::address(hotspotInstalledCode); + if (nmethodValue == 0L) { + THROW_NULL(vmSymbols::jdk_vm_ci_code_InvalidInstalledCodeException()); + } + nmethod* nm = (nmethod*) (address) nmethodValue; + methodHandle mh = nm->method(); + Symbol* signature = mh->signature(); + JavaCallArguments jca(mh->size_of_parameters()); + + JavaArgumentUnboxer jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static()); + JavaValue result(jap.get_ret_type()); + jca.set_alternative_target(nm); + JavaCalls::call(&result, mh, &jca, CHECK_NULL); + + if (jap.get_ret_type() == T_VOID) { + return NULL; + } else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) { + return JNIHandles::make_local(THREAD, (oop) result.get_jobject()); + } else { + jvalue *value = (jvalue *) result.get_value_addr(); + // Narrow the value down if required (Important on big endian machines) + switch (jap.get_ret_type()) { + case T_BOOLEAN: + value->z = (jboolean) value->i; + break; + case T_BYTE: + value->b = (jbyte) value->i; + break; + case T_CHAR: + value->c = (jchar) value->i; + break; + case T_SHORT: + value->s = (jshort) value->i; + break; + } + oop o = java_lang_boxing_object::create(jap.get_ret_type(), value, CHECK_NULL); + return JNIHandles::make_local(THREAD, o); + } +C2V_END + +C2V_VMENTRY(jlongArray, getLineNumberTable, (JNIEnv *, jobject, jobject jvmci_method)) + Method* method = CompilerToVM::asMethod(jvmci_method); + if (!method->has_linenumber_table()) { + return NULL; + } + u2 num_entries = 0; + CompressedLineNumberReadStream streamForSize(method->compressed_linenumber_table()); + while (streamForSize.read_pair()) { + num_entries++; + } + + CompressedLineNumberReadStream stream(method->compressed_linenumber_table()); + typeArrayOop result = oopFactory::new_longArray(2 * num_entries, CHECK_NULL); + + int i = 0; + jlong value; + while (stream.read_pair()) { + value = ((long) stream.bci()); + result->long_at_put(i, value); + value = ((long) stream.line()); + result->long_at_put(i + 1, value); + i += 2; + } + + return (jlongArray) JNIHandles::make_local(THREAD, result); +C2V_END + +C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + Method* method = CompilerToVM::asMethod(jvmci_method); + if (!method->has_localvariable_table()) { + return 0; + } + return (jlong) (address) method->localvariable_table_start(); +C2V_END + +C2V_VMENTRY(jint, getLocalVariableTableLength, (JNIEnv *, jobject, jobject jvmci_method)) + ResourceMark rm; + Method* method = CompilerToVM::asMethod(jvmci_method); + return method->localvariable_table_length(); +C2V_END + +C2V_VMENTRY(void, reprofile, (JNIEnv*, jobject, jobject jvmci_method)) + Method* method = CompilerToVM::asMethod(jvmci_method); + MethodCounters* mcs = method->method_counters(); + if (mcs != NULL) { + mcs->clear_counters(); + } + NOT_PRODUCT(method->set_compiled_invocation_count(0)); + + nmethod* code = method->code(); + if (code != NULL) { + code->make_not_entrant(); + } + + MethodData* method_data = method->method_data(); + if (method_data == NULL) { + ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); + method_data = MethodData::allocate(loader_data, method, CHECK); + method->set_method_data(method_data); + } else { + method_data->initialize(); + } +C2V_END + + +C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv*, jobject, jobject hotspotInstalledCode)) + jlong nativeMethod = InstalledCode::address(hotspotInstalledCode); + nmethod* m = (nmethod*)nativeMethod; + if (m != NULL && !m->is_not_entrant()) { + m->mark_for_deoptimization(); + VM_Deoptimize op; + VMThread::execute(&op); + } + InstalledCode::set_address(hotspotInstalledCode, 0); +C2V_END + +C2V_VMENTRY(jobject, readUncompressedOop, (JNIEnv*, jobject, jlong addr)) + oop ret = oopDesc::load_decode_heap_oop((oop*)(address)addr); + return JNIHandles::make_local(THREAD, ret); +C2V_END + +C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv*, jobject)) + typeArrayOop arrayOop = oopFactory::new_longArray(JVMCICounterSize, CHECK_NULL); + JavaThread::collect_counters(arrayOop); + return (jlongArray) JNIHandles::make_local(THREAD, arrayOop); +C2V_END + +C2V_VMENTRY(int, allocateCompileId, (JNIEnv*, jobject, jobject jvmci_method, int entry_bci)) + HandleMark hm; + ResourceMark rm; + if (JNIHandles::resolve(jvmci_method) == NULL) { + THROW_0(vmSymbols::java_lang_NullPointerException()); + } + Method* method = CompilerToVM::asMethod(jvmci_method); + if (entry_bci >= method->code_size() || entry_bci < -1) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Unexpected bci %d", entry_bci)); + } + return CompileBroker::assign_compile_id_unlocked(THREAD, method, entry_bci); +C2V_END + + +C2V_VMENTRY(jboolean, isMature, (JNIEnv*, jobject, jlong metaspace_method_data)) + MethodData* mdo = CompilerToVM::asMethodData(metaspace_method_data); + return mdo != NULL && mdo->is_mature(); +C2V_END + +C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv*, jobject, jobject jvmci_method, int entry_bci, int comp_level)) + Method* method = CompilerToVM::asMethod(jvmci_method); + return method->lookup_osr_nmethod_for(entry_bci, comp_level, true) != NULL; +C2V_END + +C2V_VMENTRY(jobject, getSymbol, (JNIEnv*, jobject, jlong symbol)) + Handle sym = java_lang_String::create_from_symbol((Symbol*)(address)symbol, CHECK_NULL); + return JNIHandles::make_local(THREAD, sym()); +C2V_END + +bool matches(jobjectArray methods, Method* method) { + objArrayOop methods_oop = (objArrayOop) JNIHandles::resolve(methods); + + for (int i = 0; i < methods_oop->length(); i++) { + if (CompilerToVM::asMethod(methods_oop->obj_at(i)) == method) { + return true; + } + } + return false; +} + +C2V_VMENTRY(jobject, getNextStackFrame, (JNIEnv*, jobject compilerToVM, jobject hs_frame, jobjectArray methods, jint initialSkip)) + ResourceMark rm; + + if (!thread->has_last_Java_frame()) return NULL; + Handle result = HotSpotStackFrameReference::klass()->allocate_instance(thread); + HotSpotStackFrameReference::klass()->initialize(thread); + + StackFrameStream fst(thread); + if (hs_frame != NULL) { + // look for the correct stack frame if one is given + intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(hs_frame); + while (fst.current()->sp() != stack_pointer && !fst.is_done()) { + fst.next(); + } + if (fst.current()->sp() != stack_pointer) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "stack frame not found") + } + } + + int frame_number = 0; + vframe* vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + if (hs_frame != NULL) { + // look for the correct vframe within the stack frame if one is given + int last_frame_number = HotSpotStackFrameReference::frameNumber(hs_frame); + while (frame_number < last_frame_number) { + if (vf->is_top()) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalStateException(), "invalid frame number") + } + vf = vf->sender(); + frame_number ++; + } + // move one frame forward + if (vf->is_top()) { + if (fst.is_done()) { + return NULL; + } + fst.next(); + vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + frame_number = 0; + } else { + vf = vf->sender(); + frame_number++; + } + } + + while (true) { + // look for the given method + while (true) { + StackValueCollection* locals = NULL; + if (vf->is_compiled_frame()) { + // compiled method frame + compiledVFrame* cvf = compiledVFrame::cast(vf); + if (methods == NULL || matches(methods, cvf->method())) { + if (initialSkip > 0) { + initialSkip --; + } else { + ScopeDesc* scope = cvf->scope(); + // native wrapper do not have a scope + if (scope != NULL && scope->objects() != NULL) { + bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), scope->objects(), THREAD); + Deoptimization::reassign_fields(fst.current(), fst.register_map(), scope->objects(), realloc_failures, false); + + GrowableArray* local_values = scope->locals(); + typeArrayHandle array = oopFactory::new_boolArray(local_values->length(), thread); + for (int i = 0; i < local_values->length(); i++) { + ScopeValue* value = local_values->at(i); + if (value->is_object()) { + array->bool_at_put(i, true); + } + } + HotSpotStackFrameReference::set_localIsVirtual(result, array()); + } else { + HotSpotStackFrameReference::set_localIsVirtual(result, NULL); + } + + locals = cvf->locals(); + HotSpotStackFrameReference::set_bci(result, cvf->bci()); + oop method = CompilerToVM::get_jvmci_method(cvf->method(), CHECK_NULL); + HotSpotStackFrameReference::set_method(result, method); + } + } + } else if (vf->is_interpreted_frame()) { + // interpreted method frame + interpretedVFrame* ivf = interpretedVFrame::cast(vf); + if (methods == NULL || matches(methods, ivf->method())) { + if (initialSkip > 0) { + initialSkip --; + } else { + locals = ivf->locals(); + HotSpotStackFrameReference::set_bci(result, ivf->bci()); + oop method = CompilerToVM::get_jvmci_method(ivf->method(), CHECK_NULL); + HotSpotStackFrameReference::set_method(result, method); + HotSpotStackFrameReference::set_localIsVirtual(result, NULL); + } + } + } + + // locals != NULL means that we found a matching frame and result is already partially initialized + if (locals != NULL) { + HotSpotStackFrameReference::set_compilerToVM(result, JNIHandles::resolve(compilerToVM)); + HotSpotStackFrameReference::set_stackPointer(result, (jlong) fst.current()->sp()); + HotSpotStackFrameReference::set_frameNumber(result, frame_number); + + // initialize the locals array + objArrayHandle array = oopFactory::new_objectArray(locals->size(), thread); + for (int i = 0; i < locals->size(); i++) { + StackValue* var = locals->at(i); + if (var->type() == T_OBJECT) { + array->obj_at_put(i, locals->at(i)->get_obj()()); + } + } + HotSpotStackFrameReference::set_locals(result, array()); + + return JNIHandles::make_local(thread, result()); + } + + if (vf->is_top()) { + break; + } + frame_number++; + vf = vf->sender(); + } // end of vframe loop + + if (fst.is_done()) { + break; + } + fst.next(); + vf = vframe::new_vframe(fst.current(), fst.register_map(), thread); + frame_number = 0; + } // end of frame loop + + // the end was reached without finding a matching method + return NULL; +C2V_END + +C2V_VMENTRY(void, resolveInvokeDynamicInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + CallInfo callInfo; + LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokedynamic, CHECK); + ConstantPoolCacheEntry* cp_cache_entry = cp->invokedynamic_cp_cache_entry_at(index); + cp_cache_entry->set_dynamic_call(cp, callInfo); +C2V_END + +C2V_VMENTRY(void, resolveInvokeHandleInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) + constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); + CallInfo callInfo; + LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokehandle, CHECK); + ConstantPoolCacheEntry* cp_cache_entry = cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index)); + cp_cache_entry->set_method_handle(cp, callInfo); +C2V_END + +C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv*, jobject)) + //see compute_recording_non_safepoints in debugInfroRec.cpp + if (JvmtiExport::should_post_compiled_method_load() && FLAG_IS_DEFAULT(DebugNonSafepoints)) { + return true; + } + return DebugNonSafepoints; +C2V_END + +// public native void materializeVirtualObjects(HotSpotStackFrameReference stackFrame, boolean invalidate); +C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv*, jobject, jobject hs_frame, bool invalidate)) + ResourceMark rm; + + if (hs_frame == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), "stack frame is null") + } + + HotSpotStackFrameReference::klass()->initialize(thread); + + // look for the given stack frame + StackFrameStream fst(thread); + intptr_t* stack_pointer = (intptr_t*) HotSpotStackFrameReference::stackPointer(hs_frame); + while (fst.current()->sp() != stack_pointer && !fst.is_done()) { + fst.next(); + } + if (fst.current()->sp() != stack_pointer) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "stack frame not found") + } + + if (invalidate) { + if (!fst.current()->is_compiled_frame()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected") + } + assert(fst.current()->cb()->is_nmethod(), "nmethod expected"); + ((nmethod*) fst.current()->cb())->make_not_entrant(); + } + Deoptimization::deoptimize(thread, *fst.current(), fst.register_map(), Deoptimization::Reason_none); + // look for the frame again as it has been updated by deopt (pc, deopt state...) + StackFrameStream fstAfterDeopt(thread); + while (fstAfterDeopt.current()->sp() != stack_pointer && !fstAfterDeopt.is_done()) { + fstAfterDeopt.next(); + } + if (fstAfterDeopt.current()->sp() != stack_pointer) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "stack frame not found after deopt") + } + + vframe* vf = vframe::new_vframe(fstAfterDeopt.current(), fstAfterDeopt.register_map(), thread); + if (!vf->is_compiled_frame()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "compiled stack frame expected") + } + + GrowableArray* virtualFrames = new GrowableArray(10); + while (true) { + assert(vf->is_compiled_frame(), "Wrong frame type"); + virtualFrames->push(compiledVFrame::cast(vf)); + if (vf->is_top()) { + break; + } + vf = vf->sender(); + } + + int last_frame_number = HotSpotStackFrameReference::frameNumber(hs_frame); + if (last_frame_number >= virtualFrames->length()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "invalid frame number") + } + + // Reallocate the non-escaping objects and restore their fields. + assert (virtualFrames->at(last_frame_number)->scope() != NULL,"invalid scope"); + GrowableArray* objects = virtualFrames->at(last_frame_number)->scope()->objects(); + + if (objects == NULL) { + // no objects to materialize + return; + } + + bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), objects, THREAD); + Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false); + + for (int frame_index = 0; frame_index < virtualFrames->length(); frame_index++) { + compiledVFrame* cvf = virtualFrames->at(frame_index); + + GrowableArray* scopeLocals = cvf->scope()->locals(); + StackValueCollection* locals = cvf->locals(); + + if (locals != NULL) { + for (int i2 = 0; i2 < locals->size(); i2++) { + StackValue* var = locals->at(i2); + if (var->type() == T_OBJECT && scopeLocals->at(i2)->is_object()) { + jvalue val; + val.l = (jobject) locals->at(i2)->get_obj()(); + cvf->update_local(T_OBJECT, i2, val); + } + } + } + } + + // all locals are materialized by now + HotSpotStackFrameReference::set_localIsVirtual(hs_frame, NULL); + + // update the locals array + objArrayHandle array = HotSpotStackFrameReference::locals(hs_frame); + StackValueCollection* locals = virtualFrames->at(last_frame_number)->locals(); + for (int i = 0; i < locals->size(); i++) { + StackValue* var = locals->at(i); + if (var->type() == T_OBJECT) { + array->obj_at_put(i, locals->at(i)->get_obj()()); + } + } +C2V_END + +C2V_VMENTRY(void, writeDebugOutput, (JNIEnv*, jobject, jbyteArray bytes, jint offset, jint length)) + if (bytes == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + typeArrayOop array = (typeArrayOop) JNIHandles::resolve(bytes); + + // Check if offset and length are non negative. + if (offset < 0 || length < 0) { + THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + } + // Check if the range is valid. + if ((((unsigned int) length + (unsigned int) offset) > (unsigned int) array->length())) { + THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException()); + } + while (length > 0) { + jbyte* start = array->byte_at_addr(offset); + tty->write((char*) start, MIN2(length, O_BUFLEN)); + length -= O_BUFLEN; + offset += O_BUFLEN; + } +C2V_END + +C2V_VMENTRY(void, flushDebugOutput, (JNIEnv*, jobject)) + tty->flush(); +C2V_END + + +#define CC (char*) /*cast a literal from (const char*)*/ +#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) + +#define SPECULATION_LOG "Ljdk/vm/ci/meta/SpeculationLog;" +#define STRING "Ljava/lang/String;" +#define OBJECT "Ljava/lang/Object;" +#define CLASS "Ljava/lang/Class;" +#define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;" +#define INSTALLED_CODE "Ljdk/vm/ci/code/InstalledCode;" +#define TARGET_DESCRIPTION "Ljdk/vm/ci/code/TargetDescription;" +#define RESOLVED_METHOD "Ljdk/vm/ci/meta/ResolvedJavaMethod;" +#define HS_RESOLVED_METHOD "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;" +#define HS_RESOLVED_KLASS "Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;" +#define HS_CONSTANT_POOL "Ljdk/vm/ci/hotspot/HotSpotConstantPool;" +#define HS_COMPILED_CODE "Ljdk/vm/ci/hotspot/HotSpotCompiledCode;" +#define HS_METADATA "Ljdk/vm/ci/hotspot/HotSpotMetaData;" +#define HS_STACK_FRAME_REF "Ljdk/vm/ci/hotspot/HotSpotStackFrameReference;" +#define METASPACE_METHOD_DATA "J" + +JNINativeMethod CompilerToVM::methods[] = { + {CC"getBytecode", CC"("HS_RESOLVED_METHOD")[B", FN_PTR(getBytecode)}, + {CC"getExceptionTableStart", CC"("HS_RESOLVED_METHOD")J", FN_PTR(getExceptionTableStart)}, + {CC"getExceptionTableLength", CC"("HS_RESOLVED_METHOD")I", FN_PTR(getExceptionTableLength)}, + {CC"findUniqueConcreteMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD")"HS_RESOLVED_METHOD, FN_PTR(findUniqueConcreteMethod)}, + {CC"getImplementor", CC"("HS_RESOLVED_KLASS")"HS_RESOLVED_KLASS, FN_PTR(getImplementor)}, + {CC"getStackTraceElement", CC"("HS_RESOLVED_METHOD"I)"STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, + {CC"methodIsIgnoredBySecurityStackWalk", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, + {CC"doNotInlineOrCompile", CC"("HS_RESOLVED_METHOD")V", FN_PTR(doNotInlineOrCompile)}, + {CC"canInlineMethod", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(canInlineMethod)}, + {CC"shouldInlineMethod", CC"("HS_RESOLVED_METHOD")Z", FN_PTR(shouldInlineMethod)}, + {CC"lookupType", CC"("STRING CLASS"Z)"HS_RESOLVED_KLASS, FN_PTR(lookupType)}, + {CC"lookupNameInPool", CC"("HS_CONSTANT_POOL"I)"STRING, FN_PTR(lookupNameInPool)}, + {CC"lookupNameAndTypeRefIndexInPool", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, + {CC"lookupSignatureInPool", CC"("HS_CONSTANT_POOL"I)"STRING, FN_PTR(lookupSignatureInPool)}, + {CC"lookupKlassRefIndexInPool", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(lookupKlassRefIndexInPool)}, + {CC"lookupKlassInPool", CC"("HS_CONSTANT_POOL"I)Ljava/lang/Object;", FN_PTR(lookupKlassInPool)}, + {CC"lookupAppendixInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(lookupAppendixInPool)}, + {CC"lookupMethodInPool", CC"("HS_CONSTANT_POOL"IB)"HS_RESOLVED_METHOD, FN_PTR(lookupMethodInPool)}, + {CC"constantPoolRemapInstructionOperandFromCache", CC"("HS_CONSTANT_POOL"I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)}, + {CC"resolveConstantInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolveConstantInPool)}, + {CC"resolvePossiblyCachedConstantInPool", CC"("HS_CONSTANT_POOL"I)"OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)}, + {CC"resolveTypeInPool", CC"("HS_CONSTANT_POOL"I)"HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)}, + {CC"resolveFieldInPool", CC"("HS_CONSTANT_POOL"IB[J)"HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)}, + {CC"resolveInvokeDynamicInPool", CC"("HS_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeDynamicInPool)}, + {CC"resolveInvokeHandleInPool", CC"("HS_CONSTANT_POOL"I)V", FN_PTR(resolveInvokeHandleInPool)}, + {CC"resolveMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS")"HS_RESOLVED_METHOD, FN_PTR(resolveMethod)}, + {CC"getVtableIndexForInterfaceMethod", CC"("HS_RESOLVED_KLASS HS_RESOLVED_METHOD")I", FN_PTR(getVtableIndexForInterfaceMethod)}, + {CC"getClassInitializer", CC"("HS_RESOLVED_KLASS")"HS_RESOLVED_METHOD, FN_PTR(getClassInitializer)}, + {CC"hasFinalizableSubclass", CC"("HS_RESOLVED_KLASS")Z", FN_PTR(hasFinalizableSubclass)}, + {CC"getMaxCallTargetOffset", CC"(J)J", FN_PTR(getMaxCallTargetOffset)}, + {CC"getResolvedJavaMethodAtSlot", CC"("CLASS"I)"HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethodAtSlot)}, + {CC"getResolvedJavaMethod", CC"(Ljava/lang/Object;J)"HS_RESOLVED_METHOD, FN_PTR(getResolvedJavaMethod)}, + {CC"getConstantPool", CC"(Ljava/lang/Object;J)"HS_CONSTANT_POOL, FN_PTR(getConstantPool)}, + {CC"getResolvedJavaType", CC"(Ljava/lang/Object;JZ)"HS_RESOLVED_KLASS, FN_PTR(getResolvedJavaType)}, + {CC"initializeConfiguration", CC"()J", FN_PTR(initializeConfiguration)}, + {CC"installCode", CC"("TARGET_DESCRIPTION HS_COMPILED_CODE INSTALLED_CODE SPECULATION_LOG")I", FN_PTR(installCode)}, + {CC"getMetadata", CC"("TARGET_DESCRIPTION HS_COMPILED_CODE HS_METADATA")I", FN_PTR(getMetadata)}, + {CC"notifyCompilationStatistics", CC"(I"HS_RESOLVED_METHOD"ZIJJ"INSTALLED_CODE")V", FN_PTR(notifyCompilationStatistics)}, + {CC"resetCompilationStatistics", CC"()V", FN_PTR(resetCompilationStatistics)}, + {CC"disassembleCodeBlob", CC"(J)"STRING, FN_PTR(disassembleCodeBlob)}, + {CC"executeInstalledCode", CC"(["OBJECT INSTALLED_CODE")"OBJECT, FN_PTR(executeInstalledCode)}, + {CC"getLineNumberTable", CC"("HS_RESOLVED_METHOD")[J", FN_PTR(getLineNumberTable)}, + {CC"getLocalVariableTableStart", CC"("HS_RESOLVED_METHOD")J", FN_PTR(getLocalVariableTableStart)}, + {CC"getLocalVariableTableLength", CC"("HS_RESOLVED_METHOD")I", FN_PTR(getLocalVariableTableLength)}, + {CC"reprofile", CC"("HS_RESOLVED_METHOD")V", FN_PTR(reprofile)}, + {CC"invalidateInstalledCode", CC"("INSTALLED_CODE")V", FN_PTR(invalidateInstalledCode)}, + {CC"readUncompressedOop", CC"(J)"OBJECT, FN_PTR(readUncompressedOop)}, + {CC"collectCounters", CC"()[J", FN_PTR(collectCounters)}, + {CC"allocateCompileId", CC"("HS_RESOLVED_METHOD"I)I", FN_PTR(allocateCompileId)}, + {CC"isMature", CC"("METASPACE_METHOD_DATA")Z", FN_PTR(isMature)}, + {CC"hasCompiledCodeForOSR", CC"("HS_RESOLVED_METHOD"II)Z", FN_PTR(hasCompiledCodeForOSR)}, + {CC"getSymbol", CC"(J)"STRING, FN_PTR(getSymbol)}, + {CC"getNextStackFrame", CC"("HS_STACK_FRAME_REF "["HS_RESOLVED_METHOD"I)"HS_STACK_FRAME_REF, FN_PTR(getNextStackFrame)}, + {CC"materializeVirtualObjects", CC"("HS_STACK_FRAME_REF"Z)V", FN_PTR(materializeVirtualObjects)}, + {CC"shouldDebugNonSafepoints", CC"()Z", FN_PTR(shouldDebugNonSafepoints)}, + {CC"writeDebugOutput", CC"([BII)V", FN_PTR(writeDebugOutput)}, + {CC"flushDebugOutput", CC"()V", FN_PTR(flushDebugOutput)}, +}; + +int CompilerToVM::methods_count() { + return sizeof(methods) / sizeof(JNINativeMethod); +} + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP +#define SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP + +#include "prims/jni.h" +#include "runtime/javaCalls.hpp" +#include "jvmci/jvmciJavaClasses.hpp" + +class CompilerToVM { +public: + /** + * Tag bits used by lookupKlassInPool to distinguish the types in Java. + */ + enum Tags { + KLASS_TAG = 0x0, + SYMBOL_TAG = 0x1 + }; + + // FIXME This is only temporary until the GC code is changed. + static bool _supports_inline_contig_alloc; + static HeapWord** _heap_end_addr; + static HeapWord** _heap_top_addr; + + static intptr_t tag_pointer(Klass* klass) { + return ((intptr_t) klass) | KLASS_TAG; + } + + static intptr_t tag_pointer(Symbol* symbol) { + return ((intptr_t) symbol) | SYMBOL_TAG; + } + + static JNINativeMethod methods[]; + static int methods_count(); + + static inline Method* asMethod(jobject jvmci_method) { + return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); + } + + static inline Method* asMethod(Handle jvmci_method) { + return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); + } + + static inline Method* asMethod(oop jvmci_method) { + return (Method*) (address) HotSpotResolvedJavaMethodImpl::metaspaceMethod(jvmci_method); + } + + static inline ConstantPool* asConstantPool(jobject jvmci_constant_pool) { + return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); + } + + static inline ConstantPool* asConstantPool(Handle jvmci_constant_pool) { + return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); + } + + static inline ConstantPool* asConstantPool(oop jvmci_constant_pool) { + return (ConstantPool*) (address) HotSpotConstantPool::metaspaceConstantPool(jvmci_constant_pool); + } + + static inline Klass* asKlass(jobject jvmci_type) { + return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); + } + + static inline Klass* asKlass(Handle jvmci_type) { + return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); + } + + static inline Klass* asKlass(oop jvmci_type) { + return java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(jvmci_type)); + } + + static inline MethodData* asMethodData(jlong metaspaceMethodData) { + return (MethodData*) (address) metaspaceMethodData; + } + + static oop get_jvmci_method(methodHandle method, TRAPS); + + static oop get_jvmci_type(KlassHandle klass, TRAPS); +}; + +class JavaArgumentUnboxer : public SignatureIterator { + protected: + JavaCallArguments* _jca; + arrayOop _args; + int _index; + + oop next_arg(BasicType expectedType) { + assert(_index < _args->length(), "out of bounds"); + oop arg=((objArrayOop) (_args))->obj_at(_index++); + assert(expectedType == T_OBJECT || java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch"); + return arg; + } + + public: + JavaArgumentUnboxer(Symbol* signature, JavaCallArguments* jca, arrayOop args, bool is_static) : SignatureIterator(signature) { + this->_return_type = T_ILLEGAL; + _jca = jca; + _index = 0; + _args = args; + if (!is_static) { + _jca->push_oop(next_arg(T_OBJECT)); + } + iterate(); + assert(_index == args->length(), "arg count mismatch with signature"); + } + + inline void do_bool() { if (!is_return_type()) _jca->push_int(next_arg(T_BOOLEAN)->bool_field(java_lang_boxing_object::value_offset_in_bytes(T_BOOLEAN))); } + inline void do_char() { if (!is_return_type()) _jca->push_int(next_arg(T_CHAR)->char_field(java_lang_boxing_object::value_offset_in_bytes(T_CHAR))); } + inline void do_short() { if (!is_return_type()) _jca->push_int(next_arg(T_SHORT)->short_field(java_lang_boxing_object::value_offset_in_bytes(T_SHORT))); } + inline void do_byte() { if (!is_return_type()) _jca->push_int(next_arg(T_BYTE)->byte_field(java_lang_boxing_object::value_offset_in_bytes(T_BYTE))); } + inline void do_int() { if (!is_return_type()) _jca->push_int(next_arg(T_INT)->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT))); } + + inline void do_long() { if (!is_return_type()) _jca->push_long(next_arg(T_LONG)->long_field(java_lang_boxing_object::value_offset_in_bytes(T_LONG))); } + inline void do_float() { if (!is_return_type()) _jca->push_float(next_arg(T_FLOAT)->float_field(java_lang_boxing_object::value_offset_in_bytes(T_FLOAT))); } + inline void do_double() { if (!is_return_type()) _jca->push_double(next_arg(T_DOUBLE)->double_field(java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE))); } + + inline void do_object() { _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_object(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_array(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); } + inline void do_void() { } +}; + +#endif // SHARE_VM_JVMCI_JVMCI_COMPILER_TO_VM_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciEnv.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,595 @@ +/* + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "classfile/javaAssertions.hpp" +#include "classfile/systemDictionary.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/codeCache.hpp" +#include "code/scopeDesc.hpp" +#include "runtime/sweeper.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/compileLog.hpp" +#include "compiler/compilerOracle.hpp" +#include "interpreter/linkResolver.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/oopFactory.hpp" +#include "memory/universe.inline.hpp" +#include "oops/methodData.hpp" +#include "oops/objArrayKlass.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "runtime/init.hpp" +#include "runtime/reflection.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/dtrace.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciJavaClasses.hpp" + +JVMCIEnv::JVMCIEnv(CompileTask* task, int system_dictionary_modification_counter) { + _task = task; + _system_dictionary_modification_counter = system_dictionary_modification_counter; + { + // Get Jvmti capabilities under lock to get consistent values. + MutexLocker mu(JvmtiThreadState_lock); + _jvmti_can_hotswap_or_post_breakpoint = JvmtiExport::can_hotswap_or_post_breakpoint(); + _jvmti_can_access_local_variables = JvmtiExport::can_access_local_variables(); + _jvmti_can_post_on_exceptions = JvmtiExport::can_post_on_exceptions(); + } +} + +// ------------------------------------------------------------------ +// Note: the logic of this method should mirror the logic of +// constantPoolOopDesc::verify_constant_pool_resolve. +bool JVMCIEnv::check_klass_accessibility(KlassHandle accessing_klass, KlassHandle resolved_klass) { + if (accessing_klass->oop_is_objArray()) { + accessing_klass = ObjArrayKlass::cast(accessing_klass())->bottom_klass(); + } + if (!accessing_klass->oop_is_instance()) { + return true; + } + + if (resolved_klass->oop_is_objArray()) { + // Find the element klass, if this is an array. + resolved_klass = ObjArrayKlass::cast(resolved_klass())->bottom_klass(); + } + if (resolved_klass->oop_is_instance()) { + return Reflection::verify_class_access(accessing_klass(), resolved_klass(), true); + } + return true; +} + +// ------------------------------------------------------------------ +KlassHandle JVMCIEnv::get_klass_by_name_impl(KlassHandle& accessing_klass, + constantPoolHandle& cpool, + Symbol* sym, + bool require_local) { + JVMCI_EXCEPTION_CONTEXT; + + // Now we need to check the SystemDictionary + if (sym->byte_at(0) == 'L' && + sym->byte_at(sym->utf8_length()-1) == ';') { + // This is a name from a signature. Strip off the trimmings. + // Call recursive to keep scope of strippedsym. + TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1, + sym->utf8_length()-2, + CHECK_(KlassHandle())); + return get_klass_by_name_impl(accessing_klass, cpool, strippedsym, require_local); + } + + Handle loader(THREAD, (oop)NULL); + Handle domain(THREAD, (oop)NULL); + if (!accessing_klass.is_null()) { + loader = Handle(THREAD, accessing_klass->class_loader()); + domain = Handle(THREAD, accessing_klass->protection_domain()); + } + + KlassHandle found_klass; + { + ttyUnlocker ttyul; // release tty lock to avoid ordering problems + MutexLocker ml(Compile_lock); + Klass* kls; + if (!require_local) { + kls = SystemDictionary::find_constrained_instance_or_array_klass(sym, loader, CHECK_(KlassHandle())); + } else { + kls = SystemDictionary::find_instance_or_array_klass(sym, loader, domain, CHECK_(KlassHandle())); + } + found_klass = KlassHandle(THREAD, kls); + } + + // If we fail to find an array klass, look again for its element type. + // The element type may be available either locally or via constraints. + // In either case, if we can find the element type in the system dictionary, + // we must build an array type around it. The CI requires array klasses + // to be loaded if their element klasses are loaded, except when memory + // is exhausted. + if (sym->byte_at(0) == '[' && + (sym->byte_at(1) == '[' || sym->byte_at(1) == 'L')) { + // We have an unloaded array. + // Build it on the fly if the element class exists. + TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1, + sym->utf8_length()-1, + CHECK_(KlassHandle())); + + // Get element Klass recursively. + KlassHandle elem_klass = + get_klass_by_name_impl(accessing_klass, + cpool, + elem_sym, + require_local); + if (!elem_klass.is_null()) { + // Now make an array for it + return elem_klass->array_klass(CHECK_(KlassHandle())); + } + } + + if (found_klass.is_null() && !cpool.is_null() && cpool->has_preresolution()) { + // Look inside the constant pool for pre-resolved class entries. + for (int i = cpool->length() - 1; i >= 1; i--) { + if (cpool->tag_at(i).is_klass()) { + Klass* kls = cpool->resolved_klass_at(i); + if (kls->name() == sym) { + return kls; + } + } + } + } + + return found_klass(); +} + +// ------------------------------------------------------------------ +KlassHandle JVMCIEnv::get_klass_by_name(KlassHandle& accessing_klass, + Symbol* klass_name, + bool require_local) { + ResourceMark rm; + constantPoolHandle cpool; + return get_klass_by_name_impl(accessing_klass, + cpool, + klass_name, + require_local); +} + +// ------------------------------------------------------------------ +// Implementation of get_klass_by_index. +KlassHandle JVMCIEnv::get_klass_by_index_impl(constantPoolHandle& cpool, + int index, + bool& is_accessible, + KlassHandle& accessor) { + JVMCI_EXCEPTION_CONTEXT; + KlassHandle klass (THREAD, ConstantPool::klass_at_if_loaded(cpool, index)); + Symbol* klass_name = NULL; + if (klass.is_null()) { + klass_name = cpool->klass_name_at(index); + } + + if (klass.is_null()) { + // Not found in constant pool. Use the name to do the lookup. + KlassHandle k = get_klass_by_name_impl(accessor, + cpool, + klass_name, + false); + // Calculate accessibility the hard way. + if (k.is_null()) { + is_accessible = false; + } else if (k->class_loader() != accessor->class_loader() && + get_klass_by_name_impl(accessor, cpool, k->name(), true).is_null()) { + // Loaded only remotely. Not linked yet. + is_accessible = false; + } else { + // Linked locally, and we must also check public/private, etc. + is_accessible = check_klass_accessibility(accessor, k); + } + if (!is_accessible) { + return KlassHandle(); + } + return k; + } + + // It is known to be accessible, since it was found in the constant pool. + is_accessible = true; + return klass; +} + +// ------------------------------------------------------------------ +// Get a klass from the constant pool. +KlassHandle JVMCIEnv::get_klass_by_index(constantPoolHandle& cpool, + int index, + bool& is_accessible, + KlassHandle& accessor) { + ResourceMark rm; + KlassHandle result = get_klass_by_index_impl(cpool, index, is_accessible, accessor); + return result; +} + +// ------------------------------------------------------------------ +// Implementation of get_field_by_index. +// +// Implementation note: the results of field lookups are cached +// in the accessor klass. +void JVMCIEnv::get_field_by_index_impl(instanceKlassHandle& klass, fieldDescriptor& field_desc, + int index) { + JVMCI_EXCEPTION_CONTEXT; + + assert(klass->is_linked(), "must be linked before using its constant-pool"); + + constantPoolHandle cpool(thread, klass->constants()); + + // Get the field's name, signature, and type. + Symbol* name = cpool->name_ref_at(index); + + int nt_index = cpool->name_and_type_ref_index_at(index); + int sig_index = cpool->signature_ref_index_at(nt_index); + Symbol* signature = cpool->symbol_at(sig_index); + + // Get the field's declared holder. + int holder_index = cpool->klass_ref_index_at(index); + bool holder_is_accessible; + KlassHandle declared_holder = get_klass_by_index(cpool, holder_index, + holder_is_accessible, + klass); + + // The declared holder of this field may not have been loaded. + // Bail out with partial field information. + if (!holder_is_accessible) { + return; + } + + + // Perform the field lookup. + Klass* canonical_holder = + InstanceKlass::cast(declared_holder())->find_field(name, signature, &field_desc); + if (canonical_holder == NULL) { + return; + } + + assert(canonical_holder == field_desc.field_holder(), "just checking"); +} + +// ------------------------------------------------------------------ +// Get a field by index from a klass's constant pool. +void JVMCIEnv::get_field_by_index(instanceKlassHandle& accessor, fieldDescriptor& fd, int index) { + ResourceMark rm; + return get_field_by_index_impl(accessor, fd, index); +} + +// ------------------------------------------------------------------ +// Perform an appropriate method lookup based on accessor, holder, +// name, signature, and bytecode. +methodHandle JVMCIEnv::lookup_method(instanceKlassHandle& h_accessor, + instanceKlassHandle& h_holder, + Symbol* name, + Symbol* sig, + Bytecodes::Code bc) { + JVMCI_EXCEPTION_CONTEXT; + LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL)); + methodHandle dest_method; + LinkInfo link_info(h_holder, name, sig, h_accessor, /*check_access*/true); + switch (bc) { + case Bytecodes::_invokestatic: + dest_method = + LinkResolver::resolve_static_call_or_null(link_info); + break; + case Bytecodes::_invokespecial: + dest_method = + LinkResolver::resolve_special_call_or_null(link_info); + break; + case Bytecodes::_invokeinterface: + dest_method = + LinkResolver::linktime_resolve_interface_method_or_null(link_info); + break; + case Bytecodes::_invokevirtual: + dest_method = + LinkResolver::linktime_resolve_virtual_method_or_null(link_info); + break; + default: ShouldNotReachHere(); + } + + return dest_method; +} + + +// ------------------------------------------------------------------ +methodHandle JVMCIEnv::get_method_by_index_impl(constantPoolHandle& cpool, + int index, Bytecodes::Code bc, + instanceKlassHandle& accessor) { + if (bc == Bytecodes::_invokedynamic) { + ConstantPoolCacheEntry* cpce = cpool->invokedynamic_cp_cache_entry_at(index); + bool is_resolved = !cpce->is_f1_null(); + if (is_resolved) { + // Get the invoker Method* from the constant pool. + // (The appendix argument, if any, will be noted in the method's signature.) + Method* adapter = cpce->f1_as_method(); + return methodHandle(adapter); + } + + return NULL; + } + + int holder_index = cpool->klass_ref_index_at(index); + bool holder_is_accessible; + KlassHandle holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor); + + // Get the method's name and signature. + Symbol* name_sym = cpool->name_ref_at(index); + Symbol* sig_sym = cpool->signature_ref_at(index); + + if (cpool->has_preresolution() + || (holder() == SystemDictionary::MethodHandle_klass() && + MethodHandles::is_signature_polymorphic_name(holder(), name_sym))) { + // Short-circuit lookups for JSR 292-related call sites. + // That is, do not rely only on name-based lookups, because they may fail + // if the names are not resolvable in the boot class loader (7056328). + switch (bc) { + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + case Bytecodes::_invokespecial: + case Bytecodes::_invokestatic: + { + Method* m = ConstantPool::method_at_if_loaded(cpool, index); + if (m != NULL) { + return m; + } + } + break; + } + } + + if (holder_is_accessible) { // Our declared holder is loaded. + instanceKlassHandle lookup = get_instance_klass_for_declared_method_holder(holder); + methodHandle m = lookup_method(accessor, lookup, name_sym, sig_sym, bc); + if (!m.is_null() && + (bc == Bytecodes::_invokestatic + ? InstanceKlass::cast(m->method_holder())->is_not_initialized() + : !InstanceKlass::cast(m->method_holder())->is_loaded())) { + m = NULL; + } + if (!m.is_null()) { + // We found the method. + return m; + } + } + + // Either the declared holder was not loaded, or the method could + // not be found. + + return NULL; +} + +// ------------------------------------------------------------------ +instanceKlassHandle JVMCIEnv::get_instance_klass_for_declared_method_holder(KlassHandle& method_holder) { + // For the case of .clone(), the method holder can be an ArrayKlass* + // instead of an InstanceKlass*. For that case simply pretend that the + // declared holder is Object.clone since that's where the call will bottom out. + if (method_holder->oop_is_instance()) { + return instanceKlassHandle(method_holder()); + } else if (method_holder->oop_is_array()) { + return instanceKlassHandle(SystemDictionary::Object_klass()); + } else { + ShouldNotReachHere(); + } + return NULL; +} + + +// ------------------------------------------------------------------ +methodHandle JVMCIEnv::get_method_by_index(constantPoolHandle& cpool, + int index, Bytecodes::Code bc, + instanceKlassHandle& accessor) { + ResourceMark rm; + return get_method_by_index_impl(cpool, index, bc, accessor); +} + +// ------------------------------------------------------------------ +// Check for changes to the system dictionary during compilation +// class loads, evolution, breakpoints +JVMCIEnv::CodeInstallResult JVMCIEnv::check_for_system_dictionary_modification(Dependencies* dependencies, Handle compiled_code, + JVMCIEnv* env, char** failure_detail) { + // If JVMTI capabilities were enabled during compile, the compilation is invalidated. + if (env != NULL) { + if (!env->_jvmti_can_hotswap_or_post_breakpoint && JvmtiExport::can_hotswap_or_post_breakpoint()) { + *failure_detail = (char*) "Hotswapping or breakpointing was enabled during compilation"; + return JVMCIEnv::dependencies_failed; + } + } + + // Dependencies must be checked when the system dictionary changes + // or if we don't know whether it has changed (i.e., env == NULL). + // In debug mode, always check dependencies. + bool counter_changed = env != NULL && env->_system_dictionary_modification_counter != SystemDictionary::number_of_modifications(); + bool verify_deps = env == NULL || trueInDebug || JavaAssertions::enabled(SystemDictionary::HotSpotInstalledCode_klass()->name()->as_C_string(), true); + if (!counter_changed && !verify_deps) { + return JVMCIEnv::ok; + } + + for (Dependencies::DepStream deps(dependencies); deps.next(); ) { + Klass* witness = deps.check_dependency(); + if (witness != NULL) { + // Use a fixed size buffer to prevent the string stream from + // resizing in the context of an inner resource mark. + char* buffer = NEW_RESOURCE_ARRAY(char, O_BUFLEN); + stringStream st(buffer, O_BUFLEN); + deps.print_dependency(witness, true, &st); + *failure_detail = st.as_string(); + if (env == NULL || counter_changed) { + return JVMCIEnv::dependencies_failed; + } else { + // The dependencies were invalid at the time of installation + // without any intervening modification of the system + // dictionary. That means they were invalidly constructed. + return JVMCIEnv::dependencies_invalid; + } + } + if (LogCompilation) { + deps.log_dependency(); + } + } + + return JVMCIEnv::ok; +} + +// ------------------------------------------------------------------ +JVMCIEnv::CodeInstallResult JVMCIEnv::register_method( + methodHandle& method, + nmethod*& nm, + int entry_bci, + CodeOffsets* offsets, + int orig_pc_offset, + CodeBuffer* code_buffer, + int frame_words, + OopMapSet* oop_map_set, + ExceptionHandlerTable* handler_table, + AbstractCompiler* compiler, + DebugInformationRecorder* debug_info, + Dependencies* dependencies, + JVMCIEnv* env, + int compile_id, + bool has_unsafe_access, + bool has_wide_vector, + Handle installed_code, + Handle compiled_code, + Handle speculation_log) { + JVMCI_EXCEPTION_CONTEXT; + nm = NULL; + int comp_level = CompLevel_full_optimization; + char* failure_detail = NULL; + JVMCIEnv::CodeInstallResult result; + { + // To prevent compile queue updates. + MutexLocker locker(MethodCompileQueue_lock, THREAD); + + // Prevent SystemDictionary::add_to_hierarchy from running + // and invalidating our dependencies until we install this method. + MutexLocker ml(Compile_lock); + + // Encode the dependencies now, so we can check them right away. + dependencies->encode_content_bytes(); + + // Check for {class loads, evolution, breakpoints} during compilation + result = check_for_system_dictionary_modification(dependencies, compiled_code, env, &failure_detail); + if (result != JVMCIEnv::ok) { + // While not a true deoptimization, it is a preemptive decompile. + MethodData* mdp = method()->method_data(); + if (mdp != NULL) { + mdp->inc_decompile_count(); + if (mdp->decompile_count() > (uint)PerMethodRecompilationCutoff) { + // TODO (chaeubl) enable this in the fastdebug build only once we are more stable + ResourceMark m; + tty->print_cr("WARN: endless recompilation of %s. Method was set to not compilable.", method()->name_and_sig_as_C_string()); + //ShouldNotReachHere(); + } + } + + // All buffers in the CodeBuffer are allocated in the CodeCache. + // If the code buffer is created on each compile attempt + // as in C2, then it must be freed. + //code_buffer->free_blob(); + } else { + ImplicitExceptionTable implicit_tbl; + nm = nmethod::new_nmethod(method, + compile_id, + entry_bci, + offsets, + orig_pc_offset, + debug_info, dependencies, code_buffer, + frame_words, oop_map_set, + handler_table, &implicit_tbl, + compiler, comp_level, installed_code, speculation_log); + + // Free codeBlobs + //code_buffer->free_blob(); + if (nm == NULL) { + // The CodeCache is full. Print out warning and disable compilation. + { + MutexUnlocker ml(Compile_lock); + MutexUnlocker locker(MethodCompileQueue_lock); + CompileBroker::handle_full_code_cache(CodeCache::get_code_blob_type(comp_level)); + } + } else { + nm->set_has_unsafe_access(has_unsafe_access); + nm->set_has_wide_vectors(has_wide_vector); + + // Record successful registration. + // (Put nm into the task handle *before* publishing to the Java heap.) + CompileTask* task = env == NULL ? NULL : env->task(); + if (task != NULL) task->set_code(nm); + + if (installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(installed_code())) { + if (entry_bci == InvocationEntryBci) { + 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 (TraceNMethodInstalls) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + ttyLocker ttyl; + tty->print_cr("Installing method (%d) %s [entry point: %p]", + comp_level, + method_name, nm->entry_point()); + } + // Allow the code to be executed + method->set_code(method, nm); + } else { + if (TraceNMethodInstalls ) { + ResourceMark rm; + char *method_name = method->name_and_sig_as_C_string(); + ttyLocker ttyl; + tty->print_cr("Installing osr method (%d) %s @ %d", + comp_level, + method_name, + entry_bci); + } + InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm); + } + } + } + result = nm != NULL ? JVMCIEnv::ok :JVMCIEnv::cache_full; + } + } + + // String creation must be done outside lock + if (failure_detail != NULL) { + // A failure to allocate the string is silently ignored. + Handle message = java_lang_String::create_from_str(failure_detail, THREAD); + HotSpotCompiledNmethod::set_installationFailureMessage(compiled_code, message()); + } + + // JVMTI -- compiled method notification (must be done outside lock) + if (nm != NULL) { + nm->post_compiled_method_load_event(); + } + + return result; +} + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciEnv.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_JVMCIENV_HPP +#define SHARE_VM_JVMCI_JVMCIENV_HPP + +#include "classfile/systemDictionary.hpp" +#include "code/debugInfoRec.hpp" +#include "code/dependencies.hpp" +#include "code/exceptionHandlerTable.hpp" +#include "compiler/oopMap.hpp" +#include "runtime/thread.hpp" + +class CompileTask; + +// Bring the JVMCI compiler thread into the VM state. +#define JVMCI_VM_ENTRY_MARK \ + JavaThread* thread = JavaThread::current(); \ + ThreadInVMfromNative __tiv(thread); \ + ResetNoHandleMark rnhm; \ + HandleMarkCleaner __hm(thread); \ + Thread* THREAD = thread; \ + debug_only(VMNativeEntryWrapper __vew;) + +#define JVMCI_EXCEPTION_CONTEXT \ + JavaThread* thread=JavaThread::current(); \ + Thread* THREAD = thread; + +// +// This class is the top level broker for requests from the compiler +// to the VM. +class JVMCIEnv : StackObj { + CI_PACKAGE_ACCESS_TO + + friend class CompileBroker; + friend class Dependencies; // for get_object, during logging + +public: + + enum CodeInstallResult { + ok, + dependencies_failed, + dependencies_invalid, + cache_full, + code_too_large + }; + + // Look up a klass by name from a particular class loader (the accessor's). + // If require_local, result must be defined in that class loader, or NULL. + // If !require_local, a result from remote class loader may be reported, + // if sufficient class loader constraints exist such that initiating + // a class loading request from the given loader is bound to return + // the class defined in the remote loader (or throw an error). + // + // Return an unloaded klass if !require_local and no class at all is found. + // + // The CI treats a klass as loaded if it is consistently defined in + // another loader, even if it hasn't yet been loaded in all loaders + // that could potentially see it via delegation. + static KlassHandle get_klass_by_name(KlassHandle& accessing_klass, + Symbol* klass_name, + bool require_local); + + // Constant pool access. + static KlassHandle get_klass_by_index(constantPoolHandle& cpool, + int klass_index, + bool& is_accessible, + KlassHandle& loading_klass); + static void get_field_by_index(instanceKlassHandle& loading_klass, fieldDescriptor& fd, + int field_index); + static methodHandle get_method_by_index(constantPoolHandle& cpool, + int method_index, Bytecodes::Code bc, + instanceKlassHandle& loading_klass); + + JVMCIEnv(CompileTask* task, int system_dictionary_modification_counter); + +private: + CompileTask* _task; + int _system_dictionary_modification_counter; + + // Cache JVMTI state + bool _jvmti_can_hotswap_or_post_breakpoint; + bool _jvmti_can_access_local_variables; + bool _jvmti_can_post_on_exceptions; + + // Implementation methods for loading and constant pool access. + static KlassHandle get_klass_by_name_impl(KlassHandle& accessing_klass, + constantPoolHandle& cpool, + Symbol* klass_name, + bool require_local); + static KlassHandle get_klass_by_index_impl(constantPoolHandle& cpool, + int klass_index, + bool& is_accessible, + KlassHandle& loading_klass); + static void get_field_by_index_impl(instanceKlassHandle& loading_klass, fieldDescriptor& fd, + int field_index); + static methodHandle get_method_by_index_impl(constantPoolHandle& cpool, + int method_index, Bytecodes::Code bc, + instanceKlassHandle& loading_klass); + + // Helper methods + static bool check_klass_accessibility(KlassHandle accessing_klass, KlassHandle resolved_klass); + static methodHandle lookup_method(instanceKlassHandle& accessor, + instanceKlassHandle& holder, + Symbol* name, + Symbol* sig, + Bytecodes::Code bc); + + private: + + // Is this thread currently in the VM state? + static bool is_in_vm(); + + // Helper routine for determining the validity of a compilation + // with respect to concurrent class loading. + static JVMCIEnv::CodeInstallResult check_for_system_dictionary_modification(Dependencies* target, Handle compiled_code, + JVMCIEnv* env, char** failure_detail); + +public: + CompileTask* task() { return _task; } + + // Register the result of a compilation. + static JVMCIEnv::CodeInstallResult register_method( + methodHandle& target, + nmethod*& nm, + int entry_bci, + CodeOffsets* offsets, + int orig_pc_offset, + CodeBuffer* code_buffer, + int frame_words, + OopMapSet* oop_map_set, + ExceptionHandlerTable* handler_table, + AbstractCompiler* compiler, + DebugInformationRecorder* debug_info, + Dependencies* dependencies, + JVMCIEnv* env, + int compile_id, + bool has_unsafe_access, + bool has_wide_vector, + Handle installed_code, + Handle compiled_code, + Handle speculation_log); + + // converts the Klass* representing the holder of a method into a + // InstanceKlass*. This is needed since the holder of a method in + // the bytecodes could be an array type. Basically this converts + // array types into java/lang/Object and other types stay as they are. + static instanceKlassHandle get_instance_klass_for_declared_method_holder(KlassHandle& klass); +}; + +#endif // SHARE_VM_JVMCI_JVMCIENV_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "runtime/jniHandles.hpp" +#include "classfile/symbolTable.hpp" +#include "memory/resourceArea.hpp" + +// This function is similar to javaClasses.cpp, it computes the field offset of a (static or instance) field. +// It looks up the name and signature symbols without creating new ones, all the symbols of these classes need to be already loaded. + +void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field) { + InstanceKlass* ik = InstanceKlass::cast(klass); + Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name)); + Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature)); + if (name_symbol == NULL || signature_symbol == NULL) { +#ifndef PRODUCT + ik->print_on(tty); +#endif + fatal("symbol with name %s and signature %s was not found in symbol table (klass=%s)", name, signature, klass->name()->as_C_string()); + } + + fieldDescriptor fd; + if (!ik->find_field(name_symbol, signature_symbol, &fd)) { + ResourceMark rm; + fatal("Invalid layout of %s at %s", name_symbol->as_C_string(), ik->external_name()); + } + guarantee(fd.is_static() == static_field, "static/instance mismatch"); + dest_offset = fd.offset(); + assert(dest_offset != 0, "must be valid offset"); +} + +// This piece of macro magic creates the contents of the jvmci_compute_offsets method that initializes the field indices of all the access classes. + +#define START_CLASS(name) { Klass* k = SystemDictionary::name##_klass(); assert(k != NULL, "Could not find class " #name ""); + +#define END_CLASS } + +#define FIELD(klass, name, signature, static_field) compute_offset(klass::_##name##_offset, k, #name, signature, static_field); +#define CHAR_FIELD(klass, name) FIELD(klass, name, "C", false) +#define INT_FIELD(klass, name) FIELD(klass, name, "I", false) +#define BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", false) +#define LONG_FIELD(klass, name) FIELD(klass, name, "J", false) +#define FLOAT_FIELD(klass, name) FIELD(klass, name, "F", false) +#define OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, false) +#define STATIC_OOP_FIELD(klass, name, signature) FIELD(klass, name, signature, true) +#define STATIC_INT_FIELD(klass, name) FIELD(klass, name, "I", true) +#define STATIC_BOOLEAN_FIELD(klass, name) FIELD(klass, name, "Z", true) + + +void JVMCIJavaClasses::compute_offsets() { + COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, OOP_FIELD, OOP_FIELD, STATIC_OOP_FIELD, STATIC_OOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) + guarantee(InstalledCode::_address_offset == sizeof(oopDesc), "codeBlob must be first field!"); +} + +#define EMPTY0 +#define EMPTY1(x) +#define EMPTY2(x,y) +#define FIELD2(klass, name) int klass::_##name##_offset = 0; +#define FIELD3(klass, name, sig) FIELD2(klass, name) + +COMPILER_CLASSES_DO(EMPTY1, EMPTY0, FIELD2, FIELD2, FIELD2, FIELD2, FIELD2, FIELD3, FIELD3, FIELD3, FIELD3, FIELD3, FIELD2, FIELD2) + + + + + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP +#define SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP + +#include "classfile/systemDictionary.hpp" +#include "oops/instanceMirrorKlass.hpp" + +class JVMCIJavaClasses : AllStatic { + public: + static void compute_offsets(); +}; + +/* This macro defines the structure of the CompilationResult - classes. + * It will generate classes with accessors similar to javaClasses.hpp, but with specializations for oops, Handles and jni handles. + * + * The public interface of these classes will look like this: + + * class StackSlot : AllStatic { + * public: + * static Klass* klass(); + * static jint index(oop obj); + * static jint index(Handle obj); + * static jint index(jobject obj); + * static void set_index(oop obj, jint x); + * static void set_index(Handle obj, jint x); + * static void set_index(jobject obj, jint x); + * }; + * + */ + +#define COMPILER_CLASSES_DO(start_class, end_class, char_field, int_field, boolean_field, long_field, float_field, oop_field, typeArrayOop_field, objArrayOop_field, static_oop_field, static_objArrayOop_field, static_int_field, static_boolean_field) \ + start_class(Architecture) \ + oop_field(Architecture, wordKind, "Ljdk/vm/ci/meta/PlatformKind;") \ + end_class \ + start_class(TargetDescription) \ + oop_field(TargetDescription, arch, "Ljdk/vm/ci/code/Architecture;") \ + end_class \ + start_class(HotSpotResolvedObjectTypeImpl) \ + oop_field(HotSpotResolvedObjectTypeImpl, javaClass, "Ljava/lang/Class;") \ + end_class \ + start_class(HotSpotResolvedJavaMethodImpl) \ + long_field(HotSpotResolvedJavaMethodImpl, metaspaceMethod) \ + end_class \ + start_class(InstalledCode) \ + long_field(InstalledCode, address) \ + long_field(InstalledCode, version) \ + oop_field(InstalledCode, name, "Ljava/lang/String;") \ + end_class \ + start_class(HotSpotInstalledCode) \ + int_field(HotSpotInstalledCode, size) \ + long_field(HotSpotInstalledCode, codeStart) \ + int_field(HotSpotInstalledCode, codeSize) \ + end_class \ + start_class(HotSpotNmethod) \ + boolean_field(HotSpotNmethod, isDefault) \ + end_class \ + start_class(HotSpotCompiledCode) \ + oop_field(HotSpotCompiledCode, name, "Ljava/lang/String;") \ + objArrayOop_field(HotSpotCompiledCode, sites, "[Ljdk/vm/ci/code/CompilationResult$Site;") \ + objArrayOop_field(HotSpotCompiledCode, exceptionHandlers, "[Ljdk/vm/ci/code/CompilationResult$ExceptionHandler;") \ + objArrayOop_field(HotSpotCompiledCode, comments, "[Ljdk/vm/ci/hotspot/HotSpotCompiledCode$Comment;") \ + objArrayOop_field(HotSpotCompiledCode, assumptions, "[Ljdk/vm/ci/meta/Assumptions$Assumption;") \ + typeArrayOop_field(HotSpotCompiledCode, targetCode, "[B") \ + int_field(HotSpotCompiledCode, targetCodeSize) \ + typeArrayOop_field(HotSpotCompiledCode, dataSection, "[B") \ + int_field(HotSpotCompiledCode, dataSectionAlignment) \ + objArrayOop_field(HotSpotCompiledCode, dataSectionPatches, "[Ljdk/vm/ci/code/CompilationResult$DataPatch;") \ + boolean_field(HotSpotCompiledCode, isImmutablePIC) \ + int_field(HotSpotCompiledCode, totalFrameSize) \ + int_field(HotSpotCompiledCode, customStackAreaOffset) \ + objArrayOop_field(HotSpotCompiledCode, methods, "[Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + end_class \ + start_class(HotSpotCompiledCode_Comment) \ + oop_field(HotSpotCompiledCode_Comment, text, "Ljava/lang/String;") \ + int_field(HotSpotCompiledCode_Comment, pcOffset) \ + end_class \ + start_class(HotSpotCompiledNmethod) \ + oop_field(HotSpotCompiledNmethod, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ + oop_field(HotSpotCompiledNmethod, installationFailureMessage, "Ljava/lang/String;") \ + int_field(HotSpotCompiledNmethod, entryBCI) \ + int_field(HotSpotCompiledNmethod, id) \ + long_field(HotSpotCompiledNmethod, jvmciEnv) \ + boolean_field(HotSpotCompiledNmethod, hasUnsafeAccess) \ + end_class \ + start_class(HotSpotJVMCIMetaAccessContext) \ + static_objArrayOop_field(HotSpotJVMCIMetaAccessContext, allContexts, "[Ljava/lang/ref/WeakReference;") \ + objArrayOop_field(HotSpotJVMCIMetaAccessContext, metadataRoots, "[Ljava/lang/Object;") \ + end_class \ + start_class(HotSpotForeignCallTarget) \ + long_field(HotSpotForeignCallTarget, address) \ + end_class \ + start_class(Assumptions_NoFinalizableSubclass) \ + oop_field(Assumptions_NoFinalizableSubclass, receiverType, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_ConcreteSubtype) \ + oop_field(Assumptions_ConcreteSubtype, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + oop_field(Assumptions_ConcreteSubtype, subtype, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_LeafType) \ + oop_field(Assumptions_LeafType, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + end_class \ + start_class(Assumptions_ConcreteMethod) \ + oop_field(Assumptions_ConcreteMethod, method, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + oop_field(Assumptions_ConcreteMethod, context, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + oop_field(Assumptions_ConcreteMethod, impl, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + end_class \ + start_class(Assumptions_CallSiteTargetValue) \ + oop_field(Assumptions_CallSiteTargetValue, callSite, "Ljava/lang/invoke/CallSite;") \ + oop_field(Assumptions_CallSiteTargetValue, methodHandle, "Ljava/lang/invoke/MethodHandle;") \ + end_class \ + start_class(CompilationResult_Site) \ + int_field(CompilationResult_Site, pcOffset) \ + end_class \ + start_class(CompilationResult_Call) \ + oop_field(CompilationResult_Call, target, "Ljdk/vm/ci/meta/InvokeTarget;") \ + oop_field(CompilationResult_Call, debugInfo, "Ljdk/vm/ci/code/DebugInfo;") \ + end_class \ + start_class(CompilationResult_DataPatch) \ + oop_field(CompilationResult_DataPatch, reference, "Ljdk/vm/ci/code/CompilationResult$Reference;") \ + end_class \ + start_class(CompilationResult_ConstantReference) \ + oop_field(CompilationResult_ConstantReference, constant, "Ljdk/vm/ci/meta/VMConstant;") \ + end_class \ + start_class(CompilationResult_DataSectionReference) \ + int_field(CompilationResult_DataSectionReference, offset) \ + end_class \ + start_class(InfopointReason) \ + static_oop_field(InfopointReason, UNKNOWN, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, SAFEPOINT, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, CALL, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, IMPLICIT_EXCEPTION, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, METHOD_START, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, METHOD_END, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, LINE_NUMBER, "Ljdk/vm/ci/code/InfopointReason;") \ + static_oop_field(InfopointReason, METASPACE_ACCESS, "Ljdk/vm/ci/code/InfopointReason;") \ + end_class \ + start_class(CompilationResult_Infopoint) \ + oop_field(CompilationResult_Infopoint, debugInfo, "Ljdk/vm/ci/code/DebugInfo;") \ + oop_field(CompilationResult_Infopoint, reason, "Ljdk/vm/ci/code/InfopointReason;") \ + end_class \ + start_class(CompilationResult_ExceptionHandler) \ + int_field(CompilationResult_ExceptionHandler, handlerPos) \ + end_class \ + start_class(CompilationResult_Mark) \ + oop_field(CompilationResult_Mark, id, "Ljava/lang/Object;") \ + end_class \ + start_class(DebugInfo) \ + oop_field(DebugInfo, bytecodePosition, "Ljdk/vm/ci/code/BytecodePosition;") \ + oop_field(DebugInfo, referenceMap, "Ljdk/vm/ci/code/ReferenceMap;") \ + oop_field(DebugInfo, calleeSaveInfo, "Ljdk/vm/ci/code/RegisterSaveLayout;") \ + objArrayOop_field(DebugInfo, virtualObjectMapping, "[Ljdk/vm/ci/code/VirtualObject;") \ + end_class \ + start_class(HotSpotReferenceMap) \ + objArrayOop_field(HotSpotReferenceMap, objects, "[Ljdk/vm/ci/code/Location;") \ + objArrayOop_field(HotSpotReferenceMap, derivedBase, "[Ljdk/vm/ci/code/Location;") \ + typeArrayOop_field(HotSpotReferenceMap, sizeInBytes, "[I") \ + int_field(HotSpotReferenceMap, maxRegisterSize) \ + end_class \ + start_class(RegisterSaveLayout) \ + objArrayOop_field(RegisterSaveLayout, registers, "[Ljdk/vm/ci/code/Register;") \ + typeArrayOop_field(RegisterSaveLayout, slots, "[I") \ + end_class \ + start_class(BytecodeFrame) \ + objArrayOop_field(BytecodeFrame, values, "[Ljdk/vm/ci/meta/JavaValue;") \ + objArrayOop_field(BytecodeFrame, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;") \ + int_field(BytecodeFrame, numLocals) \ + int_field(BytecodeFrame, numStack) \ + int_field(BytecodeFrame, numLocks) \ + boolean_field(BytecodeFrame, rethrowException) \ + boolean_field(BytecodeFrame, duringCall) \ + static_int_field(BytecodeFrame, BEFORE_BCI) \ + end_class \ + start_class(BytecodePosition) \ + oop_field(BytecodePosition, caller, "Ljdk/vm/ci/code/BytecodePosition;") \ + oop_field(BytecodePosition, method, "Ljdk/vm/ci/meta/ResolvedJavaMethod;") \ + int_field(BytecodePosition, bci) \ + end_class \ + start_class(JavaConstant) \ + end_class \ + start_class(PrimitiveConstant) \ + oop_field(PrimitiveConstant, kind, "Ljdk/vm/ci/meta/JavaKind;") \ + long_field(PrimitiveConstant, primitive) \ + end_class \ + start_class(RawConstant) \ + long_field(RawConstant, primitive) \ + end_class \ + start_class(NullConstant) \ + end_class \ + start_class(HotSpotCompressedNullConstant) \ + end_class \ + start_class(HotSpotObjectConstantImpl) \ + oop_field(HotSpotObjectConstantImpl, object, "Ljava/lang/Object;") \ + boolean_field(HotSpotObjectConstantImpl, compressed) \ + end_class \ + start_class(HotSpotMetaspaceConstantImpl) \ + long_field(HotSpotMetaspaceConstantImpl, primitive) \ + oop_field(HotSpotMetaspaceConstantImpl, metaspaceObject, "Ljava/lang/Object;") \ + boolean_field(HotSpotMetaspaceConstantImpl, compressed) \ + end_class \ + start_class(HotSpotSentinelConstant) \ + end_class \ + start_class(JavaKind) \ + char_field(JavaKind, typeChar) \ + static_oop_field(JavaKind, Boolean, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Byte, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Char, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Short, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Int, "Ljdk/vm/ci/meta/JavaKind;"); \ + static_oop_field(JavaKind, Long, "Ljdk/vm/ci/meta/JavaKind;"); \ + end_class \ + start_class(LIRKind) \ + oop_field(LIRKind, platformKind, "Ljdk/vm/ci/meta/PlatformKind;") \ + int_field(LIRKind, referenceMask) \ + end_class \ + start_class(Value) \ + oop_field(Value, lirKind, "Ljdk/vm/ci/meta/LIRKind;") \ + static_oop_field(Value, ILLEGAL, "Ljdk/vm/ci/meta/AllocatableValue;"); \ + end_class \ + start_class(RegisterValue) \ + oop_field(RegisterValue, reg, "Ljdk/vm/ci/code/Register;") \ + end_class \ + start_class(code_Location) \ + oop_field(code_Location, reg, "Ljdk/vm/ci/code/Register;") \ + int_field(code_Location, offset) \ + end_class \ + start_class(code_Register) \ + int_field(code_Register, number) \ + int_field(code_Register, encoding) \ + end_class \ + start_class(StackSlot) \ + int_field(StackSlot, offset) \ + boolean_field(StackSlot, addFrameSize) \ + end_class \ + start_class(VirtualObject) \ + int_field(VirtualObject, id) \ + oop_field(VirtualObject, type, "Ljdk/vm/ci/meta/ResolvedJavaType;") \ + objArrayOop_field(VirtualObject, values, "[Ljdk/vm/ci/meta/JavaValue;") \ + objArrayOop_field(VirtualObject, slotKinds, "[Ljdk/vm/ci/meta/JavaKind;") \ + end_class \ + start_class(StackLockValue) \ + oop_field(StackLockValue, owner, "Ljdk/vm/ci/meta/JavaValue;") \ + oop_field(StackLockValue, slot, "Ljdk/vm/ci/code/StackSlotValue;") \ + boolean_field(StackLockValue, eliminated) \ + end_class \ + start_class(SpeculationLog) \ + oop_field(SpeculationLog, lastFailed, "Ljava/lang/Object;") \ + end_class \ + start_class(HotSpotStackFrameReference) \ + oop_field(HotSpotStackFrameReference, compilerToVM, "Ljdk/vm/ci/hotspot/CompilerToVM;") \ + long_field(HotSpotStackFrameReference, stackPointer) \ + int_field(HotSpotStackFrameReference, frameNumber) \ + int_field(HotSpotStackFrameReference, bci) \ + oop_field(HotSpotStackFrameReference, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ + objArrayOop_field(HotSpotStackFrameReference, locals, "[Ljava/lang/Object;") \ + typeArrayOop_field(HotSpotStackFrameReference, localIsVirtual, "[Z") \ + end_class \ + start_class(HotSpotMetaData) \ + typeArrayOop_field(HotSpotMetaData, pcDescBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, scopesDescBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, relocBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, exceptionBytes, "[B") \ + typeArrayOop_field(HotSpotMetaData, oopMaps, "[B") \ + objArrayOop_field(HotSpotMetaData, metadata, "[Ljava/lang/String;") \ + end_class \ + start_class(HotSpotOopMap) \ + int_field(HotSpotOopMap, offset) \ + int_field(HotSpotOopMap, count) \ + typeArrayOop_field(HotSpotOopMap, data, "[B") \ + end_class \ + start_class(HotSpotConstantPool) \ + long_field(HotSpotConstantPool, metaspaceConstantPool) \ + end_class \ + /* end*/ + + +#define START_CLASS(name) \ +class name : AllStatic { \ + private: \ + friend class JVMCICompiler; \ + static void check(oop obj, const char* field_name, int offset) { \ + assert(obj != NULL, "NULL field access of %s.%s", #name, field_name); \ + assert(obj->is_a(SystemDictionary::name##_klass()), "wrong class, " #name " expected, found %s", obj->klass()->external_name()); \ + assert(offset != 0, "must be valid offset"); \ + } \ + static void compute_offsets(); \ + public: \ + static InstanceKlass* klass() { return SystemDictionary::name##_klass() == NULL ? NULL : InstanceKlass::cast(SystemDictionary::name##_klass()); } + +#define END_CLASS }; + +#define FIELD(name, type, accessor, cast) \ + static int _##name##_offset; \ + static type name(oop obj) { check(obj, #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ + static type name(Handle& obj) { check(obj(), #name, _##name##_offset); return cast obj->accessor(_##name##_offset); } \ + static type name(jobject obj) { check(JNIHandles::resolve(obj), #name, _##name##_offset); return cast JNIHandles::resolve(obj)->accessor(_##name##_offset); } \ + static void set_##name(oop obj, type x) { check(obj, #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ + static void set_##name(Handle& obj, type x) { check(obj(), #name, _##name##_offset); obj->accessor##_put(_##name##_offset, x); } \ + static void set_##name(jobject obj, type x) { check(JNIHandles::resolve(obj), #name, _##name##_offset); JNIHandles::resolve(obj)->accessor##_put(_##name##_offset, x); } + +#define EMPTY_CAST +#define CHAR_FIELD(klass, name) FIELD(name, jchar, char_field, EMPTY_CAST) +#define INT_FIELD(klass, name) FIELD(name, jint, int_field, EMPTY_CAST) +#define BOOLEAN_FIELD(klass, name) FIELD(name, jboolean, bool_field, EMPTY_CAST) +#define LONG_FIELD(klass, name) FIELD(name, jlong, long_field, EMPTY_CAST) +#define FLOAT_FIELD(klass, name) FIELD(name, jfloat, float_field, EMPTY_CAST) +#define OOP_FIELD(klass, name, signature) FIELD(name, oop, obj_field, EMPTY_CAST) +#define OBJARRAYOOP_FIELD(klass, name, signature) FIELD(name, objArrayOop, obj_field, (objArrayOop)) +#define TYPEARRAYOOP_FIELD(klass, name, signature) FIELD(name, typeArrayOop, obj_field, (typeArrayOop)) +#define STATIC_OOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, oop, signature) +#define STATIC_OBJARRAYOOP_FIELD(klassName, name, signature) STATIC_OOPISH_FIELD(klassName, name, objArrayOop, signature) +#define STATIC_OOPISH_FIELD(klassName, name, type, signature) \ + static int _##name##_offset; \ + static type name() { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + if (UseCompressedOops) { \ + return (type) oopDesc::load_decode_heap_oop((narrowOop *)addr); \ + } else { \ + return (type) oopDesc::load_decode_heap_oop((oop*)addr); \ + } \ + } \ + static void set_##name(type x) { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + assert(klassName::klass() != NULL, "Class not yet loaded: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + if (UseCompressedOops) { \ + oop_store((narrowOop *)addr, x); \ + } else { \ + oop_store((oop*)addr, x); \ + } \ + } +#define STATIC_PRIMITIVE_FIELD(klassName, name, jtypename) \ + static int _##name##_offset; \ + static jtypename name() { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + return *((jtypename *)addr); \ + } \ + static void set_##name(jtypename x) { \ + assert(klassName::klass() != NULL && klassName::klass()->is_linked(), "Class not yet linked: " #klassName); \ + InstanceKlass* ik = klassName::klass(); \ + address addr = ik->static_field_addr(_##name##_offset - InstanceMirrorKlass::offset_of_static_fields()); \ + *((jtypename *)addr) = x; \ + } + +#define STATIC_INT_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jint) +#define STATIC_BOOLEAN_FIELD(klassName, name) STATIC_PRIMITIVE_FIELD(klassName, name, jboolean) + +COMPILER_CLASSES_DO(START_CLASS, END_CLASS, CHAR_FIELD, INT_FIELD, BOOLEAN_FIELD, LONG_FIELD, FLOAT_FIELD, OOP_FIELD, TYPEARRAYOOP_FIELD, OBJARRAYOOP_FIELD, STATIC_OOP_FIELD, STATIC_OBJARRAYOOP_FIELD, STATIC_INT_FIELD, STATIC_BOOLEAN_FIELD) +#undef START_CLASS +#undef END_CLASS +#undef FIELD +#undef CHAR_FIELD +#undef INT_FIELD +#undef BOOLEAN_FIELD +#undef LONG_FIELD +#undef FLOAT_FIELD +#undef OOP_FIELD +#undef TYPEARRAYOOP_FIELD +#undef OBJARRAYOOP_FIELD +#undef STATIC_OOPISH_FIELD +#undef STATIC_OOP_FIELD +#undef STATIC_OBJARRAYOOP_FIELD +#undef STATIC_INT_FIELD +#undef STATIC_BOOLEAN_FIELD +#undef EMPTY_CAST + +void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field); + +#endif // SHARE_VM_JVMCI_JVMCIJAVACLASSES_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciRuntime.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1014 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "asm/codeBuffer.hpp" +#include "code/codeCache.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "memory/oopFactory.hpp" +#include "oops/oop.inline.hpp" +#include "oops/objArrayOop.inline.hpp" +#include "prims/jvm.h" +#include "runtime/biasedLocking.hpp" +#include "runtime/interfaceSupport.hpp" +#include "runtime/reflection.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/debug.hpp" +#include "utilities/defaultStream.hpp" + +#if defined(_MSC_VER) +#define strtoll _strtoi64 +#endif + +jobject JVMCIRuntime::_HotSpotJVMCIRuntime_instance = NULL; +bool JVMCIRuntime::_HotSpotJVMCIRuntime_initialized = false; +bool JVMCIRuntime::_well_known_classes_initialized = false; +const char* JVMCIRuntime::_compiler = NULL; +int JVMCIRuntime::_options_count = 0; +SystemProperty** JVMCIRuntime::_options = NULL; +bool JVMCIRuntime::_shutdown_called = false; + +static const char* OPTION_PREFIX = "jvmci.option."; +static const size_t OPTION_PREFIX_LEN = strlen(OPTION_PREFIX); + +BasicType JVMCIRuntime::kindToBasicType(jchar ch) { + switch(ch) { + case 'z': return T_BOOLEAN; + case 'b': return T_BYTE; + case 's': return T_SHORT; + case 'c': return T_CHAR; + case 'i': return T_INT; + case 'f': return T_FLOAT; + case 'j': return T_LONG; + case 'd': return T_DOUBLE; + case 'a': return T_OBJECT; + case '-': return T_ILLEGAL; + default: + fatal("unexpected Kind: %c", ch); + break; + } + return T_ILLEGAL; +} + +// Simple helper to see if the caller of a runtime stub which +// entered the VM has been deoptimized + +static bool caller_is_deopted() { + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, false); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + assert(caller_frame.is_compiled_frame(), "must be compiled"); + return caller_frame.is_deoptimized_frame(); +} + +// Stress deoptimization +static void deopt_caller() { + if ( !caller_is_deopted()) { + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, false); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); + assert(caller_is_deopted(), "Must be deoptimized"); + } +} + +JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance(JavaThread* thread, Klass* klass)) + JRT_BLOCK; + assert(klass->is_klass(), "not a class"); + instanceKlassHandle h(thread, klass); + h->check_valid_for_instantiation(true, CHECK); + // make sure klass is initialized + h->initialize(CHECK); + // allocate instance and return via TLS + oop obj = h->allocate_instance(CHECK); + thread->set_vm_result(obj); + JRT_BLOCK_END; + + if (ReduceInitialCardMarks) { + new_store_pre_barrier(thread); + } +JRT_END + +JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_klass, jint length)) + JRT_BLOCK; + // Note: no handle for klass needed since they are not used + // anymore after new_objArray() and no GC can happen before. + // (This may have to change if this code changes!) + assert(array_klass->is_klass(), "not a class"); + oop obj; + if (array_klass->oop_is_typeArray()) { + BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type(); + obj = oopFactory::new_typeArray(elt_type, length, CHECK); + } else { + Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); + obj = oopFactory::new_objArray(elem_klass, length, CHECK); + } + thread->set_vm_result(obj); + // This is pretty rare but this runtime patch is stressful to deoptimization + // if we deoptimize here so force a deopt to stress the path. + if (DeoptimizeALot) { + static int deopts = 0; + // Alternate between deoptimizing and raising an error (which will also cause a deopt) + if (deopts++ % 2 == 0) { + ResourceMark rm(THREAD); + THROW(vmSymbols::java_lang_OutOfMemoryError()); + } else { + deopt_caller(); + } + } + JRT_BLOCK_END; + + if (ReduceInitialCardMarks) { + new_store_pre_barrier(thread); + } +JRT_END + +void JVMCIRuntime::new_store_pre_barrier(JavaThread* thread) { + // After any safepoint, just before going back to compiled code, + // we inform the GC that we will be doing initializing writes to + // this object in the future without emitting card-marks, so + // GC may take any compensating steps. + // NOTE: Keep this code consistent with GraphKit::store_barrier. + + oop new_obj = thread->vm_result(); + if (new_obj == NULL) return; + + assert(Universe::heap()->can_elide_tlab_store_barriers(), + "compiler must check this first"); + // GC may decide to give back a safer copy of new_obj. + new_obj = Universe::heap()->new_store_pre_barrier(thread, new_obj); + thread->set_vm_result(new_obj); +} + +JRT_ENTRY(void, JVMCIRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims)) + assert(klass->is_klass(), "not a class"); + assert(rank >= 1, "rank must be nonzero"); + oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length)) + oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror)) + instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(type_mirror)); + + if (klass == NULL) { + ResourceMark rm(THREAD); + THROW(vmSymbols::java_lang_InstantiationException()); + } + + // Create new instance (the receiver) + klass->check_valid_for_instantiation(false, CHECK); + + // Make sure klass gets initialized + klass->initialize(CHECK); + + oop obj = klass->allocate_instance(CHECK); + thread->set_vm_result(obj); +JRT_END + +extern void vm_exit(int code); + +// Enter this method from compiled code handler below. This is where we transition +// to VM mode. This is done as a helper routine so that the method called directly +// from compiled code does not have to transition to VM. This allows the entry +// method to see if the nmethod that we have just looked up a handler for has +// been deoptimized while we were in the vm. This simplifies the assembly code +// cpu directories. +// +// We are entering here from exception stub (via the entry method below) +// If there is a compiled exception handler in this method, we will continue there; +// otherwise we will unwind the stack and continue at the caller of top frame method +// Note: we enter in Java using a special JRT wrapper. This wrapper allows us to +// control the area where we can allow a safepoint. After we exit the safepoint area we can +// check to see if the handler we are going to return is now in a nmethod that has +// been deoptimized. If that is the case we return the deopt blob +// unpack_with_exception entry instead. This makes life for the exception blob easier +// because making that same check and diverting is painful from assembly language. +JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm)) + // Reset method handle flag. + thread->set_is_method_handle_return(false); + + Handle exception(thread, ex); + nm = CodeCache::find_nmethod(pc); + assert(nm != NULL, "this is not a compiled method"); + // Adjust the pc as needed/ + if (nm->is_deopt_pc(pc)) { + RegisterMap map(thread, false); + frame exception_frame = thread->last_frame().sender(&map); + // if the frame isn't deopted then pc must not correspond to the caller of last_frame + assert(exception_frame.is_deoptimized_frame(), "must be deopted"); + pc = exception_frame.pc(); + } +#ifdef ASSERT + assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); + assert(exception->is_oop(), "just checking"); + // Check that exception is a subclass of Throwable, otherwise we have a VerifyError + if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { + if (ExitVMOnVerifyError) vm_exit(-1); + ShouldNotReachHere(); + } +#endif + + // Check the stack guard pages and reenable them if necessary and there is + // enough space on the stack to do so. Use fast exceptions only if the guard + // pages are enabled. + bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); + if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); + + if (JvmtiExport::can_post_on_exceptions()) { + // To ensure correct notification of exception catches and throws + // we have to deoptimize here. If we attempted to notify the + // catches and throws during this exception lookup it's possible + // we could deoptimize on the way out of the VM and end back in + // the interpreter at the throw site. This would result in double + // notifications since the interpreter would also notify about + // these same catches and throws as it unwound the frame. + + RegisterMap reg_map(thread); + frame stub_frame = thread->last_frame(); + frame caller_frame = stub_frame.sender(®_map); + + // We don't really want to deoptimize the nmethod itself since we + // can actually continue in the exception handler ourselves but I + // don't see an easy way to have the desired effect. + Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); + assert(caller_is_deopted(), "Must be deoptimized"); + + return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + + // ExceptionCache is used only for exceptions at call sites and not for implicit exceptions + if (guard_pages_enabled) { + address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); + if (fast_continuation != NULL) { + // Set flag if return address is a method handle call site. + thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); + return fast_continuation; + } + } + + // If the stack guard pages are enabled, check whether there is a handler in + // the current method. Otherwise (guard pages disabled), force an unwind and + // skip the exception cache update (i.e., just leave continuation==NULL). + address continuation = NULL; + if (guard_pages_enabled) { + + // New exception handling mechanism can support inlined methods + // with exception handlers since the mappings are from PC to PC + + // debugging support + // tracing + if (TraceExceptions) { + ttyLocker ttyl; + ResourceMark rm; + tty->print_cr("Exception <%s> (" INTPTR_FORMAT ") thrown in compiled method <%s> at PC " INTPTR_FORMAT " for thread " INTPTR_FORMAT "", + exception->print_value_string(), p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread)); + } + // for AbortVMOnException flag + NOT_PRODUCT(Exceptions::debug_check_abort(exception)); + + // Clear out the exception oop and pc since looking up an + // exception handler can cause class loading, which might throw an + // exception and those fields are expected to be clear during + // normal bytecode execution. + thread->clear_exception_oop_and_pc(); + + continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false); + // If an exception was thrown during exception dispatch, the exception oop may have changed + thread->set_exception_oop(exception()); + thread->set_exception_pc(pc); + + // the exception cache is used only by non-implicit exceptions + if (continuation != NULL && !SharedRuntime::deopt_blob()->contains(continuation)) { + nm->add_handler_for_exception_and_pc(exception, pc, continuation); + } + } + + // Set flag if return address is a method handle call site. + thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); + + if (TraceExceptions) { + ttyLocker ttyl; + ResourceMark rm; + tty->print_cr("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT " for exception thrown at PC " PTR_FORMAT, + p2i(thread), p2i(continuation), p2i(pc)); + } + + return continuation; +JRT_END + +// Enter this method from compiled code only if there is a Java exception handler +// in the method handling the exception. +// We are entering here from exception stub. We don't do a normal VM transition here. +// We do it in a helper. This is so we can check to see if the nmethod we have just +// searched for an exception handler has been deoptimized in the meantime. +address JVMCIRuntime::exception_handler_for_pc(JavaThread* thread) { + oop exception = thread->exception_oop(); + address pc = thread->exception_pc(); + // Still in Java mode + DEBUG_ONLY(ResetNoHandleMark rnhm); + nmethod* nm = NULL; + address continuation = NULL; + { + // Enter VM mode by calling the helper + ResetNoHandleMark rnhm; + continuation = exception_handler_for_pc_helper(thread, exception, pc, nm); + } + // Back in JAVA, use no oops DON'T safepoint + + // Now check to see if the compiled method we were called from is now deoptimized. + // If so we must return to the deopt blob and deoptimize the nmethod + if (nm != NULL && caller_is_deopted()) { + continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + + assert(continuation != NULL, "no handler found"); + return continuation; +} + +JRT_ENTRY(void, JVMCIRuntime::create_null_exception(JavaThread* thread)) + SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_NullPointerException()); + thread->set_vm_result(PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::create_out_of_bounds_exception(JavaThread* thread, jint index)) + char message[jintAsStringSize]; + sprintf(message, "%d", index); + SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message); + thread->set_vm_result(PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; +JRT_END + +JRT_ENTRY_NO_ASYNC(void, JVMCIRuntime::monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock)) + IF_TRACE_jvmci_3 { + char type[O_BUFLEN]; + obj->klass()->name()->as_C_string(type, O_BUFLEN); + markOop mark = obj->mark(); + TRACE_jvmci_3("%s: entered locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(mark), p2i(lock)); + tty->flush(); + } +#ifdef ASSERT + if (PrintBiasedLockingStatistics) { + Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); + } +#endif + Handle h_obj(thread, obj); + assert(h_obj()->is_oop(), "must be NULL or an object"); + if (UseBiasedLocking) { + // Retry fast entry if bias is revoked to avoid unnecessary inflation + ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); + } else { + if (JVMCIUseFastLocking) { + // When using fast locking, the compiled code has already tried the fast case + ObjectSynchronizer::slow_enter(h_obj, lock, THREAD); + } else { + ObjectSynchronizer::fast_enter(h_obj, lock, false, THREAD); + } + } + TRACE_jvmci_3("%s: exiting locking slow with obj=" INTPTR_FORMAT, thread->name(), p2i(obj)); +JRT_END + +JRT_LEAF(void, JVMCIRuntime::monitorexit(JavaThread* thread, oopDesc* obj, BasicLock* lock)) + assert(thread == JavaThread::current(), "threads must correspond"); + assert(thread->last_Java_sp(), "last_Java_sp must be set"); + // monitorexit is non-blocking (leaf routine) => no exceptions can be thrown + EXCEPTION_MARK; + +#ifdef DEBUG + if (!obj->is_oop()) { + ResetNoHandleMark rhm; + nmethod* method = thread->last_frame().cb()->as_nmethod_or_null(); + if (method != NULL) { + tty->print_cr("ERROR in monitorexit in method %s wrong obj " INTPTR_FORMAT, method->name(), p2i(obj)); + } + thread->print_stack_on(tty); + assert(false, "invalid lock object pointer dected"); + } +#endif + + if (JVMCIUseFastLocking) { + // When using fast locking, the compiled code has already tried the fast case + ObjectSynchronizer::slow_exit(obj, lock, THREAD); + } else { + ObjectSynchronizer::fast_exit(obj, lock, THREAD); + } + IF_TRACE_jvmci_3 { + char type[O_BUFLEN]; + obj->klass()->name()->as_C_string(type, O_BUFLEN); + TRACE_jvmci_3("%s: exited locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(obj->mark()), p2i(lock)); + tty->flush(); + } +JRT_END + +JRT_LEAF(void, JVMCIRuntime::log_object(JavaThread* thread, oopDesc* obj, jint flags)) + bool string = mask_bits_are_true(flags, LOG_OBJECT_STRING); + bool addr = mask_bits_are_true(flags, LOG_OBJECT_ADDRESS); + bool newline = mask_bits_are_true(flags, LOG_OBJECT_NEWLINE); + if (!string) { + if (!addr && obj->is_oop_or_null(true)) { + char buf[O_BUFLEN]; + tty->print("%s@" INTPTR_FORMAT, obj->klass()->name()->as_C_string(buf, O_BUFLEN), p2i(obj)); + } else { + tty->print(INTPTR_FORMAT, p2i(obj)); + } + } else { + ResourceMark rm; + assert(obj != NULL && java_lang_String::is_instance(obj), "must be"); + char *buf = java_lang_String::as_utf8_string(obj); + tty->print_raw(buf); + } + if (newline) { + tty->cr(); + } +JRT_END + +JRT_LEAF(void, JVMCIRuntime::write_barrier_pre(JavaThread* thread, oopDesc* obj)) + thread->satb_mark_queue().enqueue(obj); +JRT_END + +JRT_LEAF(void, JVMCIRuntime::write_barrier_post(JavaThread* thread, void* card_addr)) + thread->dirty_card_queue().enqueue(card_addr); +JRT_END + +JRT_LEAF(jboolean, JVMCIRuntime::validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child)) + bool ret = true; + if(!Universe::heap()->is_in_closed_subset(parent)) { + tty->print_cr("Parent Object " INTPTR_FORMAT " not in heap", p2i(parent)); + parent->print(); + ret=false; + } + if(!Universe::heap()->is_in_closed_subset(child)) { + tty->print_cr("Child Object " INTPTR_FORMAT " not in heap", p2i(child)); + child->print(); + ret=false; + } + return (jint)ret; +JRT_END + +JRT_ENTRY(void, JVMCIRuntime::vm_error(JavaThread* thread, jlong where, jlong format, jlong value)) + ResourceMark rm; + const char *error_msg = where == 0L ? "" : (char*) (address) where; + char *detail_msg = NULL; + if (format != 0L) { + const char* buf = (char*) (address) format; + size_t detail_msg_length = strlen(buf) * 2; + detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length); + jio_snprintf(detail_msg, detail_msg_length, buf, value); + report_vm_error(__FILE__, __LINE__, error_msg, "%s", detail_msg); + } else { + report_vm_error(__FILE__, __LINE__, error_msg); + } +JRT_END + +JRT_LEAF(oopDesc*, JVMCIRuntime::load_and_clear_exception(JavaThread* thread)) + oop exception = thread->exception_oop(); + assert(exception != NULL, "npe"); + thread->set_exception_oop(NULL); + thread->set_exception_pc(0); + return exception; +JRT_END + +PRAGMA_DIAG_PUSH +PRAGMA_FORMAT_NONLITERAL_IGNORED +JRT_LEAF(void, JVMCIRuntime::log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3)) + ResourceMark rm; + assert(format != NULL && java_lang_String::is_instance(format), "must be"); + char *buf = java_lang_String::as_utf8_string(format); + tty->print((const char*)buf, v1, v2, v3); +JRT_END +PRAGMA_DIAG_POP + +static void decipher(jlong v, bool ignoreZero) { + if (v != 0 || !ignoreZero) { + void* p = (void *)(address) v; + CodeBlob* cb = CodeCache::find_blob(p); + if (cb) { + if (cb->is_nmethod()) { + char buf[O_BUFLEN]; + tty->print("%s [" INTPTR_FORMAT "+" JLONG_FORMAT "]", cb->as_nmethod_or_null()->method()->name_and_sig_as_C_string(buf, O_BUFLEN), p2i(cb->code_begin()), (jlong)((address)v - cb->code_begin())); + return; + } + cb->print_value_on(tty); + return; + } + if (Universe::heap()->is_in(p)) { + oop obj = oop(p); + obj->print_value_on(tty); + return; + } + tty->print(INTPTR_FORMAT " [long: " JLONG_FORMAT ", double %lf, char %c]",p2i((void *)v), (jlong)v, (jdouble)v, (char)v); + } +} + +PRAGMA_DIAG_PUSH +PRAGMA_FORMAT_NONLITERAL_IGNORED +JRT_LEAF(void, JVMCIRuntime::vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3)) + ResourceMark rm; + const char *buf = (const char*) (address) format; + if (vmError) { + if (buf != NULL) { + fatal(buf, v1, v2, v3); + } else { + fatal(""); + } + } else if (buf != NULL) { + tty->print(buf, v1, v2, v3); + } else { + assert(v2 == 0, "v2 != 0"); + assert(v3 == 0, "v3 != 0"); + decipher(v1, false); + } +JRT_END +PRAGMA_DIAG_POP + +JRT_LEAF(void, JVMCIRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) + union { + jlong l; + jdouble d; + jfloat f; + } uu; + uu.l = value; + switch (typeChar) { + case 'z': tty->print(value == 0 ? "false" : "true"); break; + case 'b': tty->print("%d", (jbyte) value); break; + case 'c': tty->print("%c", (jchar) value); break; + case 's': tty->print("%d", (jshort) value); break; + case 'i': tty->print("%d", (jint) value); break; + case 'f': tty->print("%f", uu.f); break; + case 'j': tty->print(JLONG_FORMAT, value); break; + case 'd': tty->print("%lf", uu.d); break; + default: assert(false, "unknown typeChar"); break; + } + if (newline) { + tty->cr(); + } +JRT_END + +JRT_ENTRY(jint, JVMCIRuntime::identity_hash_code(JavaThread* thread, oopDesc* obj)) + return (jint) obj->identity_hash(); +JRT_END + +JRT_ENTRY(jboolean, JVMCIRuntime::thread_is_interrupted(JavaThread* thread, oopDesc* receiver, jboolean clear_interrupted)) + // Ensure that the C++ Thread and OSThread structures aren't freed before we operate. + // This locking requires thread_in_vm which is why this method cannot be JRT_LEAF. + Handle receiverHandle(thread, receiver); + MutexLockerEx ml(thread->threadObj() == (void*)receiver ? NULL : Threads_lock); + JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle()); + if (receiverThread == NULL) { + // The other thread may exit during this process, which is ok so return false. + return JNI_FALSE; + } else { + return (jint) Thread::is_interrupted(receiverThread, clear_interrupted != 0); + } +JRT_END + +JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_call_int(JavaThread* thread, int value)) + deopt_caller(); + return value; +JRT_END + +// private static JVMCIRuntime JVMCI.initializeRuntime() +JVM_ENTRY(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) + if (!EnableJVMCI) { + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled") + } + JVMCIRuntime::initialize_HotSpotJVMCIRuntime(CHECK_NULL); + jobject ret = JVMCIRuntime::get_HotSpotJVMCIRuntime_jobject(CHECK_NULL); + return ret; +JVM_END + +Handle JVMCIRuntime::callStatic(const char* className, const char* methodName, const char* signature, JavaCallArguments* args, TRAPS) { + guarantee(!_HotSpotJVMCIRuntime_initialized, "cannot reinitialize HotSpotJVMCIRuntime"); + + TempNewSymbol name = SymbolTable::new_symbol(className, CHECK_(Handle())); + KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, CHECK_(Handle())); + TempNewSymbol runtime = SymbolTable::new_symbol(methodName, CHECK_(Handle())); + TempNewSymbol sig = SymbolTable::new_symbol(signature, CHECK_(Handle())); + JavaValue result(T_OBJECT); + if (args == NULL) { + JavaCalls::call_static(&result, klass, runtime, sig, CHECK_(Handle())); + } else { + JavaCalls::call_static(&result, klass, runtime, sig, args, CHECK_(Handle())); + } + return Handle((oop)result.get_jobject()); +} + +static bool jvmci_options_file_exists() { + const char* home = Arguments::get_java_home(); + size_t path_len = strlen(home) + strlen("/lib/jvmci/options") + 1; + char path[JVM_MAXPATHLEN]; + char sep = os::file_separator()[0]; + jio_snprintf(path, JVM_MAXPATHLEN, "%s%clib%cjvmci%coptions", home, sep, sep, sep); + struct stat st; + return os::stat(path, &st) == 0; +} + +void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) { + if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { +#ifdef ASSERT + // This should only be called in the context of the JVMCI class being initialized + TempNewSymbol name = SymbolTable::new_symbol("jdk/vm/ci/runtime/JVMCI", CHECK); + Klass* k = SystemDictionary::resolve_or_null(name, CHECK); + instanceKlassHandle klass = InstanceKlass::cast(k); + assert(klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD), + "HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization"); +#endif + + bool parseOptionsFile = jvmci_options_file_exists(); + if (_options != NULL || parseOptionsFile) { + JavaCallArguments args; + objArrayOop options; + if (_options != NULL) { + options = oopFactory::new_objArray(SystemDictionary::String_klass(), _options_count * 2, CHECK); + for (int i = 0; i < _options_count; i++) { + SystemProperty* prop = _options[i]; + oop name = java_lang_String::create_oop_from_str(prop->key() + OPTION_PREFIX_LEN, CHECK); + oop value = java_lang_String::create_oop_from_str(prop->value(), CHECK); + options->obj_at_put(i * 2, name); + options->obj_at_put((i * 2) + 1, value); + } + } else { + options = NULL; + } + args.push_oop(options); + args.push_int(parseOptionsFile); + callStatic("jdk/vm/ci/options/OptionsParser", + "parseOptionsFromVM", + "([Ljava/lang/String;Z)Ljava/lang/Boolean;", &args, CHECK); + } + + if (_compiler != NULL) { + JavaCallArguments args; + oop compiler = java_lang_String::create_oop_from_str(_compiler, CHECK); + args.push_oop(compiler); + callStatic("jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig", + "selectCompiler", + "(Ljava/lang/String;)Ljava/lang/Boolean;", &args, CHECK); + } + + Handle result = callStatic("jdk/vm/ci/hotspot/HotSpotJVMCIRuntime", + "runtime", + "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;", NULL, CHECK); + _HotSpotJVMCIRuntime_initialized = true; + _HotSpotJVMCIRuntime_instance = JNIHandles::make_global(result()); + } +} + +void JVMCIRuntime::initialize_JVMCI(TRAPS) { + if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { + callStatic("jdk/vm/ci/runtime/JVMCI", + "getRuntime", + "()Ljdk/vm/ci/runtime/JVMCIRuntime;", NULL, CHECK); + } + assert(_HotSpotJVMCIRuntime_initialized == true, "what?"); +} + +void JVMCIRuntime::initialize_well_known_classes(TRAPS) { + if (JVMCIRuntime::_well_known_classes_initialized == false) { + SystemDictionary::WKID scan = SystemDictionary::FIRST_JVMCI_WKID; + SystemDictionary::initialize_wk_klasses_through(SystemDictionary::LAST_JVMCI_WKID, scan, CHECK); + JVMCIJavaClasses::compute_offsets(); + JVMCIRuntime::_well_known_classes_initialized = true; + } +} + +void JVMCIRuntime::metadata_do(void f(Metadata*)) { + // For simplicity, the existence of HotSpotJVMCIMetaAccessContext in + // the SystemDictionary well known classes should ensure the other + // classes have already been loaded, so make sure their order in the + // table enforces that. + assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl) < + SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); + assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotConstantPool) < + SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); + assert(SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl) < + SystemDictionary::WK_KLASS_ENUM_NAME(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext), "must be loaded earlier"); + + if (HotSpotJVMCIMetaAccessContext::klass() == NULL || + !HotSpotJVMCIMetaAccessContext::klass()->is_linked()) { + // Nothing could be registered yet + return; + } + + // WeakReference[] + objArrayOop allContexts = HotSpotJVMCIMetaAccessContext::allContexts(); + if (allContexts == NULL) { + return; + } + + // These must be loaded at this point but the linking state doesn't matter. + assert(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass() != NULL, "must be loaded"); + assert(SystemDictionary::HotSpotConstantPool_klass() != NULL, "must be loaded"); + assert(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass() != NULL, "must be loaded"); + + for (int i = 0; i < allContexts->length(); i++) { + oop ref = allContexts->obj_at(i); + if (ref != NULL) { + oop referent = java_lang_ref_Reference::referent(ref); + if (referent != NULL) { + // Chunked Object[] with last element pointing to next chunk + objArrayOop metadataRoots = HotSpotJVMCIMetaAccessContext::metadataRoots(referent); + while (metadataRoots != NULL) { + for (int typeIndex = 0; typeIndex < metadataRoots->length() - 1; typeIndex++) { + oop reference = metadataRoots->obj_at(typeIndex); + if (reference == NULL) { + continue; + } + oop metadataRoot = java_lang_ref_Reference::referent(reference); + if (metadataRoot == NULL) { + continue; + } + if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedJavaMethodImpl_klass())) { + Method* method = CompilerToVM::asMethod(metadataRoot); + f(method); + } else if (metadataRoot->is_a(SystemDictionary::HotSpotConstantPool_klass())) { + ConstantPool* constantPool = CompilerToVM::asConstantPool(metadataRoot); + f(constantPool); + } else if (metadataRoot->is_a(SystemDictionary::HotSpotResolvedObjectTypeImpl_klass())) { + Klass* klass = CompilerToVM::asKlass(metadataRoot); + f(klass); + } else { + metadataRoot->print(); + ShouldNotReachHere(); + } + } + metadataRoots = (objArrayOop)metadataRoots->obj_at(metadataRoots->length() - 1); + assert(metadataRoots == NULL || metadataRoots->is_objArray(), "wrong type"); + } + } + } + } +} + +// private static void CompilerToVM.registerNatives() +JVM_ENTRY(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass)) + if (!EnableJVMCI) { + THROW_MSG(vmSymbols::java_lang_InternalError(), "JVMCI is not enabled"); + } + +#ifdef _LP64 +#ifndef TARGET_ARCH_sparc + uintptr_t heap_end = (uintptr_t) Universe::heap()->reserved_region().end(); + uintptr_t allocation_end = heap_end + ((uintptr_t)16) * 1024 * 1024 * 1024; + guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)"); +#endif // TARGET_ARCH_sparc +#else + fatal("check TLAB allocation code for address space conflicts"); +#endif + + JVMCIRuntime::initialize_well_known_classes(CHECK); + + { + ThreadToNativeFromVM trans(thread); + + // Ensure _non_oop_bits is initialized + Universe::non_oop_word(); + + env->RegisterNatives(c2vmClass, CompilerToVM::methods, CompilerToVM::methods_count()); + } +JVM_END + +/** + * Closure for parsing a line from a *.properties file in jre/lib/jvmci/properties. + * The line must match the regular expression "[^=]+=.*". That is one or more + * characters other than '=' followed by '=' followed by zero or more characters. + * Everything before the '=' is the property name and everything after '=' is the value. + * Lines that start with '#' are treated as comments and ignored. + * No special processing of whitespace or any escape characters is performed. + * The last definition of a property "wins" (i.e., it overrides all earlier + * definitions of the property). + */ +class JVMCIPropertiesFileClosure : public ParseClosure { + SystemProperty** _plist; +public: + JVMCIPropertiesFileClosure(SystemProperty** plist) : _plist(plist) {} + void do_line(char* line) { + if (line[0] == '#') { + // skip comment + return; + } + size_t len = strlen(line); + char* sep = strchr(line, '='); + if (sep == NULL) { + warn_and_abort("invalid format: could not find '=' character"); + return; + } + if (sep == line) { + warn_and_abort("invalid format: name cannot be empty"); + return; + } + *sep = '\0'; + const char* name = line; + char* value = sep + 1; + Arguments::PropertyList_unique_add(_plist, name, value); + } +}; + +void JVMCIRuntime::init_system_properties(SystemProperty** plist) { + char jvmciDir[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + jio_snprintf(jvmciDir, sizeof(jvmciDir), "%s%slib%sjvmci", + Arguments::get_java_home(), fileSep, fileSep, fileSep); + DIR* dir = os::opendir(jvmciDir); + if (dir != NULL) { + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(jvmciDir), mtInternal); + JVMCIPropertiesFileClosure closure(plist); + const unsigned suffix_len = (unsigned)strlen(".properties"); + while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL && !closure.is_aborted()) { + const char* name = entry->d_name; + if (strlen(name) > suffix_len && strcmp(name + strlen(name) - suffix_len, ".properties") == 0) { + char propertiesFilePath[JVM_MAXPATHLEN]; + jio_snprintf(propertiesFilePath, sizeof(propertiesFilePath), "%s%s%s",jvmciDir, fileSep, name); + JVMCIRuntime::parse_lines(propertiesFilePath, &closure, false); + } + } + FREE_C_HEAP_ARRAY(char, dbuf); + os::closedir(dir); + } +} + +#define CHECK_WARN_ABORT_(message) THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + warning(message); \ + char buf[512]; \ + jio_snprintf(buf, 512, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return; \ + } \ + (void)(0 + +void JVMCIRuntime::save_compiler(const char* compiler) { + assert(compiler != NULL, "npe"); + assert(_compiler == NULL, "cannot reassign JVMCI compiler"); + _compiler = compiler; +} + +jint JVMCIRuntime::save_options(SystemProperty* props) { + int count = 0; + SystemProperty* first = NULL; + for (SystemProperty* p = props; p != NULL; p = p->next()) { + if (strncmp(p->key(), OPTION_PREFIX, OPTION_PREFIX_LEN) == 0) { + if (p->value() == NULL || strlen(p->value()) == 0) { + jio_fprintf(defaultStream::output_stream(), "JVMCI option %s must have non-zero length value\n", p->key()); + return JNI_ERR; + } + if (first == NULL) { + first = p; + } + count++; + } + } + if (count != 0) { + _options_count = count; + _options = NEW_C_HEAP_ARRAY(SystemProperty*, count, mtCompiler); + _options[0] = first; + SystemProperty** insert_pos = _options + 1; + for (SystemProperty* p = first->next(); p != NULL; p = p->next()) { + if (strncmp(p->key(), OPTION_PREFIX, OPTION_PREFIX_LEN) == 0) { + *insert_pos = p; + insert_pos++; + } + } + assert (insert_pos - _options == count, "must be"); + } + return JNI_OK; +} + +void JVMCIRuntime::shutdown() { + if (_HotSpotJVMCIRuntime_instance != NULL) { + _shutdown_called = true; + JavaThread* THREAD = JavaThread::current(); + HandleMark hm(THREAD); + Handle receiver = get_HotSpotJVMCIRuntime(CHECK_ABORT); + JavaValue result(T_VOID); + JavaCallArguments args; + args.push_oop(receiver); + JavaCalls::call_special(&result, receiver->klass(), vmSymbols::shutdown_method_name(), vmSymbols::void_method_signature(), &args, CHECK_ABORT); + } +} + +void JVMCIRuntime::call_printStackTrace(Handle exception, Thread* thread) { + assert(exception->is_a(SystemDictionary::Throwable_klass()), "Throwable instance expected"); + JavaValue result(T_VOID); + JavaCalls::call_virtual(&result, + exception, + KlassHandle(thread, + SystemDictionary::Throwable_klass()), + vmSymbols::printStackTrace_name(), + vmSymbols::void_method_signature(), + thread); +} + +void JVMCIRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) { + Thread* THREAD = Thread::current(); + CLEAR_PENDING_EXCEPTION; + tty->print_raw_cr(message); + call_printStackTrace(exception, THREAD); + + // Give other aborting threads to also print their stack traces. + // This can be very useful when debugging class initialization + // failures. + os::sleep(THREAD, 200, false); + + vm_abort(dump_core); +} + +void JVMCIRuntime::parse_lines(char* path, ParseClosure* closure, bool warnStatFailure) { + struct stat st; + if (os::stat(path, &st) == 0 && (st.st_mode & S_IFREG) == S_IFREG) { // exists & is regular file + int file_handle = os::open(path, 0, 0); + if (file_handle != -1) { + char* buffer = NEW_C_HEAP_ARRAY(char, st.st_size + 1, mtInternal); + int num_read; + num_read = (int) os::read(file_handle, (char*) buffer, st.st_size); + if (num_read == -1) { + warning("Error reading file %s due to %s", path, strerror(errno)); + } else if (num_read != st.st_size) { + warning("Only read %d of " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path); + } + os::close(file_handle); + closure->set_filename(path); + if (num_read == st.st_size) { + buffer[num_read] = '\0'; + + char* line = buffer; + while (line - buffer < num_read && !closure->is_aborted()) { + // find line end (\r, \n or \r\n) + char* nextline = NULL; + char* cr = strchr(line, '\r'); + char* lf = strchr(line, '\n'); + if (cr != NULL && lf != NULL) { + char* min = MIN2(cr, lf); + *min = '\0'; + if (lf == cr + 1) { + nextline = lf + 1; + } else { + nextline = min + 1; + } + } else if (cr != NULL) { + *cr = '\0'; + nextline = cr + 1; + } else if (lf != NULL) { + *lf = '\0'; + nextline = lf + 1; + } + // trim left + while (*line == ' ' || *line == '\t') line++; + char* end = line + strlen(line); + // trim right + while (end > line && (*(end -1) == ' ' || *(end -1) == '\t')) end--; + *end = '\0'; + // skip comments and empty lines + if (*line != '#' && strlen(line) > 0) { + closure->parse_line(line); + } + if (nextline != NULL) { + line = nextline; + } else { + // File without newline at the end + break; + } + } + } + FREE_C_HEAP_ARRAY(char, buffer); + } else { + warning("Error opening file %s due to %s", path, strerror(errno)); + } + } else if (warnStatFailure) { + warning("Could not stat file %s due to %s", path, strerror(errno)); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmciRuntime.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_JVMCI_RUNTIME_HPP +#define SHARE_VM_JVMCI_JVMCI_RUNTIME_HPP + +#include "interpreter/interpreter.hpp" +#include "memory/allocation.hpp" +#include "runtime/arguments.hpp" +#include "runtime/deoptimization.hpp" + +class ParseClosure : public StackObj { + int _lineNo; + char* _filename; + bool _abort; +protected: + void abort() { _abort = true; } + void warn_and_abort(const char* message) { + warn(message); + abort(); + } + void warn(const char* message) { + warning("Error at line %d while parsing %s: %s", _lineNo, _filename == NULL ? "?" : _filename, message); + } + public: + ParseClosure() : _lineNo(0), _filename(NULL), _abort(false) {} + void parse_line(char* line) { + _lineNo++; + do_line(line); + } + virtual void do_line(char* line) = 0; + int lineNo() { return _lineNo; } + bool is_aborted() { return _abort; } + void set_filename(char* path) {_filename = path; _lineNo = 0;} +}; + +#define CHECK_ABORT THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return; \ + } \ + (void)(0 + +#define CHECK_ABORT_(result) THREAD); \ + if (HAS_PENDING_EXCEPTION) { \ + char buf[256]; \ + jio_snprintf(buf, 256, "Uncaught exception at %s:%d", __FILE__, __LINE__); \ + JVMCIRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \ + return result; \ + } \ + (void)(0 + +class JVMCIRuntime: public AllStatic { + private: + static jobject _HotSpotJVMCIRuntime_instance; + static bool _HotSpotJVMCIRuntime_initialized; + static bool _well_known_classes_initialized; + static const char* _compiler; + static int _options_count; + static SystemProperty** _options; + + static bool _shutdown_called; + + /** + * Instantiates a service object, calls its default constructor and returns it. + * + * @param name the name of a class implementing jdk.vm.ci.service.Service + */ + static Handle create_Service(const char* name, TRAPS); + + public: + + /** + * Parses *.properties files in jre/lib/jvmci/ and adds the properties to plist. + */ + static void init_system_properties(SystemProperty** plist); + + /** + * Saves the value of the "jvmci.compiler" system property for processing + * when JVMCI is initialized. + */ + static void save_compiler(const char* compiler); + + /** + * Saves the value of the system properties starting with "jvmci.option." for processing + * when JVMCI is initialized. + * + * @param props the head of the system property list + * @return JNI_ERR if a JVMCI option has a zero length value, JNI_OK otherwise + */ + static jint save_options(SystemProperty* props); + + static bool is_HotSpotJVMCIRuntime_initialized() { return _HotSpotJVMCIRuntime_initialized; } + + /** + * Gets the singleton HotSpotJVMCIRuntime instance, initializing it if necessary + */ + static Handle get_HotSpotJVMCIRuntime(TRAPS) { + initialize_JVMCI(CHECK_(Handle())); + return Handle(JNIHandles::resolve_non_null(_HotSpotJVMCIRuntime_instance)); + } + + static jobject get_HotSpotJVMCIRuntime_jobject(TRAPS) { + initialize_JVMCI(CHECK_NULL); + assert(_HotSpotJVMCIRuntime_initialized, "must be"); + return _HotSpotJVMCIRuntime_instance; + } + + static Handle callStatic(const char* className, const char* methodName, const char* returnType, JavaCallArguments* args, TRAPS); + + /** + * Trigger initialization of HotSpotJVMCIRuntime through JVMCI.getRuntime() + */ + static void initialize_JVMCI(TRAPS); + + /** + * Explicitly initialize HotSpotJVMCIRuntime itself + */ + static void initialize_HotSpotJVMCIRuntime(TRAPS); + + static void initialize_well_known_classes(TRAPS); + + static void metadata_do(void f(Metadata*)); + + static void shutdown(); + + static bool shutdown_called() { + return _shutdown_called; + } + + static void parse_lines(char* path, ParseClosure* closure, bool warnStatFailure); + + /** + * Aborts the VM due to an unexpected exception. + */ + static void abort_on_pending_exception(Handle exception, const char* message, bool dump_core = false); + + /** + * Calls Throwable.printStackTrace() on a given exception. + */ + static void call_printStackTrace(Handle exception, Thread* thread); + + static BasicType kindToBasicType(jchar ch); + + // The following routines are all called from compiled JVMCI code + + static void new_instance(JavaThread* thread, Klass* klass); + static void new_array(JavaThread* thread, Klass* klass, jint length); + static void new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims); + static void dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length); + static void dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror); + static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupted); + static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3); + static jint identity_hash_code(JavaThread* thread, oopDesc* obj); + static address exception_handler_for_pc(JavaThread* thread); + static void monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock); + static void create_null_exception(JavaThread* thread); + static void create_out_of_bounds_exception(JavaThread* thread, jint index); + static void vm_error(JavaThread* thread, jlong where, jlong format, jlong value); + static oopDesc* load_and_clear_exception(JavaThread* thread); + static void log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3); + static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline); + // Note: Must be kept in sync with constants in com.oracle.graal.replacements.Log + enum { + LOG_OBJECT_NEWLINE = 0x01, + LOG_OBJECT_STRING = 0x02, + LOG_OBJECT_ADDRESS = 0x04 + }; + static void log_object(JavaThread* thread, oopDesc* msg, jint flags); + static void write_barrier_pre(JavaThread* thread, oopDesc* obj); + static void write_barrier_post(JavaThread* thread, void* card); + static jboolean validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child); + static void new_store_pre_barrier(JavaThread* thread); + + // Test only function + static int test_deoptimize_call_int(JavaThread* thread, int value); +}; + +// Tracing macros. + +#define IF_TRACE_jvmci_1 if (!(JVMCITraceLevel >= 1)) ; else +#define IF_TRACE_jvmci_2 if (!(JVMCITraceLevel >= 2)) ; else +#define IF_TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3)) ; else +#define IF_TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4)) ; else +#define IF_TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5)) ; else + +#define TRACE_jvmci_1 if (!(JVMCITraceLevel >= 1 && (tty->print("JVMCITrace-1: "), true))) ; else tty->print_cr +#define TRACE_jvmci_2 if (!(JVMCITraceLevel >= 2 && (tty->print(" JVMCITrace-2: "), true))) ; else tty->print_cr +#define TRACE_jvmci_3 if (!(JVMCITraceLevel >= 3 && (tty->print(" JVMCITrace-3: "), true))) ; else tty->print_cr +#define TRACE_jvmci_4 if (!(JVMCITraceLevel >= 4 && (tty->print(" JVMCITrace-4: "), true))) ; else tty->print_cr +#define TRACE_jvmci_5 if (!(JVMCITraceLevel >= 5 && (tty->print(" JVMCITrace-5: "), true))) ; else tty->print_cr + +#endif // SHARE_VM_JVMCI_JVMCI_RUNTIME_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmci_globals.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "jvmci/jvmci_globals.hpp" + +JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ + MATERIALIZE_PD_DEVELOPER_FLAG, \ + MATERIALIZE_PRODUCT_FLAG, \ + MATERIALIZE_PD_PRODUCT_FLAG, \ + MATERIALIZE_DIAGNOSTIC_FLAG, \ + MATERIALIZE_EXPERIMENTAL_FLAG, \ + MATERIALIZE_NOTPRODUCT_FLAG, + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/jvmci_globals.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_JVMCIGLOBALS_HPP +#define SHARE_VM_JVMCI_JVMCIGLOBALS_HPP + +#include "runtime/globals.hpp" + +// +// Defines all global flags used by the JVMCI compiler. Only flags that need +// to be accessible to the JVMCI C++ code should be defined here. All other +// JVMCI flags should be defined in JVMCIOptions.java. +// +#define JVMCI_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, range, constraint) \ + \ + experimental(bool, EnableJVMCI, false, \ + "Enable JVMCI") \ + \ + experimental(bool, UseJVMCICompiler, false, \ + "Use JVMCI as the default compiler") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, BootstrapJVMCI, false, \ + "Bootstrap JVMCI before running Java main method") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, PrintBootstrap, true, \ + "Print JVMCI bootstrap progress and summary") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCIThreads, 1, \ + "Force number of JVMCI compiler threads to use") \ + range(1, max_jint) \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCIHostThreads, 1, \ + "Force number of compiler threads for JVMCI host compiler") \ + range(1, max_jint) \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, CodeInstallSafepointChecks, true, \ + "Perform explicit safepoint checks while installing code") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + NOT_COMPILER2(product(intx, MaxVectorSize, 64, \ + "Max vector size in bytes, " \ + "actual size could be less depending on elements type")) \ + \ + NOT_COMPILER2(product(bool, ReduceInitialCardMarks, true, \ + "Defer write barriers of young objects")) \ + \ + experimental(intx, JVMCITraceLevel, 0, \ + "Trace level for JVMCI: " \ + "1 means emit a message for each CompilerToVM call," \ + "levels greater than 1 provide progressively greater detail") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCICounterSize, 0, \ + "Reserved size for benchmark counters") \ + range(0, max_jint) \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(bool, JVMCICountersExcludeCompiler, true, \ + "Exclude JVMCI compiler threads from benchmark counters") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + develop(bool, JVMCIUseFastLocking, true, \ + "Use fast inlined locking code") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + experimental(intx, JVMCINMethodSizeLimit, (80*K)*wordSize, \ + "Maximum size of a compiled method.") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + \ + develop(bool, TraceUncollectedSpeculations, false, \ + "Print message when a failed speculation was not collected") \ + constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + + +// Read default values for JVMCI globals + +JVMCI_FLAGS(DECLARE_DEVELOPER_FLAG, \ + DECLARE_PD_DEVELOPER_FLAG, \ + DECLARE_PRODUCT_FLAG, \ + DECLARE_PD_PRODUCT_FLAG, \ + DECLARE_DIAGNOSTIC_FLAG, \ + DECLARE_EXPERIMENTAL_FLAG, \ + DECLARE_NOTPRODUCT_FLAG, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + +#endif // SHARE_VM_JVMCI_JVMCIGLOBALS_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/systemDictionary_jvmci.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/systemDictionary_jvmci.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP +#define SHARE_VM_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP + +#if !INCLUDE_JVMCI +#define JVMCI_WK_KLASSES_DO(do_klass) +#else +#define JVMCI_WK_KLASSES_DO(do_klass) \ + /* JVMCI classes. These are loaded on-demand. */ \ + do_klass(HotSpotCompiledCode_klass, jdk_vm_ci_hotspot_HotSpotCompiledCode, Jvmci) \ + do_klass(HotSpotCompiledCode_Comment_klass, jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment, Jvmci) \ + do_klass(HotSpotCompiledNmethod_klass, jdk_vm_ci_hotspot_HotSpotCompiledNmethod, Jvmci) \ + do_klass(HotSpotForeignCallTarget_klass, jdk_vm_ci_hotspot_HotSpotForeignCallTarget, Jvmci) \ + do_klass(HotSpotReferenceMap_klass, jdk_vm_ci_hotspot_HotSpotReferenceMap, Jvmci) \ + do_klass(HotSpotInstalledCode_klass, jdk_vm_ci_hotspot_HotSpotInstalledCode, Jvmci) \ + do_klass(HotSpotNmethod_klass, jdk_vm_ci_hotspot_HotSpotNmethod, Jvmci) \ + do_klass(HotSpotResolvedJavaMethodImpl_klass, jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl, Jvmci) \ + do_klass(HotSpotResolvedObjectTypeImpl_klass, jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl, Jvmci) \ + do_klass(HotSpotCompressedNullConstant_klass, jdk_vm_ci_hotspot_HotSpotCompressedNullConstant, Jvmci) \ + do_klass(HotSpotObjectConstantImpl_klass, jdk_vm_ci_hotspot_HotSpotObjectConstantImpl, Jvmci) \ + do_klass(HotSpotMetaspaceConstantImpl_klass, jdk_vm_ci_hotspot_HotSpotMetaspaceConstantImpl, Jvmci) \ + do_klass(HotSpotSentinelConstant_klass, jdk_vm_ci_hotspot_HotSpotSentinelConstant, Jvmci) \ + do_klass(HotSpotStackFrameReference_klass, jdk_vm_ci_hotspot_HotSpotStackFrameReference, Jvmci) \ + do_klass(HotSpotMetaData_klass, jdk_vm_ci_hotspot_HotSpotMetaData, Jvmci) \ + do_klass(HotSpotOopMap_klass, jdk_vm_ci_hotspot_HotSpotOopMap, Jvmci) \ + do_klass(HotSpotConstantPool_klass, jdk_vm_ci_hotspot_HotSpotConstantPool, Jvmci) \ + do_klass(HotSpotJVMCIMetaAccessContext_klass, jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext, Jvmci) \ + do_klass(Assumptions_ConcreteMethod_klass, jdk_vm_ci_meta_Assumptions_ConcreteMethod, Jvmci) \ + do_klass(Assumptions_NoFinalizableSubclass_klass, jdk_vm_ci_meta_Assumptions_NoFinalizableSubclass, Jvmci) \ + do_klass(Assumptions_ConcreteSubtype_klass, jdk_vm_ci_meta_Assumptions_ConcreteSubtype, Jvmci) \ + do_klass(Assumptions_LeafType_klass, jdk_vm_ci_meta_Assumptions_LeafType, Jvmci) \ + do_klass(Assumptions_CallSiteTargetValue_klass, jdk_vm_ci_meta_Assumptions_CallSiteTargetValue, Jvmci) \ + do_klass(Architecture_klass, jdk_vm_ci_code_Architecture, Jvmci) \ + do_klass(TargetDescription_klass, jdk_vm_ci_code_TargetDescription, Jvmci) \ + do_klass(BytecodePosition_klass, jdk_vm_ci_code_BytecodePosition, Jvmci) \ + do_klass(DebugInfo_klass, jdk_vm_ci_code_DebugInfo, Jvmci) \ + do_klass(RegisterSaveLayout_klass, jdk_vm_ci_code_RegisterSaveLayout, Jvmci) \ + do_klass(BytecodeFrame_klass, jdk_vm_ci_code_BytecodeFrame, Jvmci) \ + do_klass(CompilationResult_Call_klass, jdk_vm_ci_code_CompilationResult_Call, Jvmci) \ + do_klass(CompilationResult_ConstantReference_klass, jdk_vm_ci_code_CompilationResult_ConstantReference, Jvmci) \ + do_klass(CompilationResult_DataPatch_klass, jdk_vm_ci_code_CompilationResult_DataPatch, Jvmci) \ + do_klass(CompilationResult_DataSectionReference_klass, jdk_vm_ci_code_CompilationResult_DataSectionReference, Jvmci) \ + do_klass(CompilationResult_ExceptionHandler_klass, jdk_vm_ci_code_CompilationResult_ExceptionHandler, Jvmci) \ + do_klass(CompilationResult_Mark_klass, jdk_vm_ci_code_CompilationResult_Mark, Jvmci) \ + do_klass(CompilationResult_Infopoint_klass, jdk_vm_ci_code_CompilationResult_Infopoint, Jvmci) \ + do_klass(CompilationResult_Site_klass, jdk_vm_ci_code_CompilationResult_Site, Jvmci) \ + do_klass(InfopointReason_klass, jdk_vm_ci_code_InfopointReason, Jvmci) \ + do_klass(InstalledCode_klass, jdk_vm_ci_code_InstalledCode, Jvmci) \ + do_klass(code_Location_klass, jdk_vm_ci_code_Location, Jvmci) \ + do_klass(code_Register_klass, jdk_vm_ci_code_Register, Jvmci) \ + do_klass(RegisterValue_klass, jdk_vm_ci_code_RegisterValue, Jvmci) \ + do_klass(StackSlot_klass, jdk_vm_ci_code_StackSlot, Jvmci) \ + do_klass(StackLockValue_klass, jdk_vm_ci_code_StackLockValue, Jvmci) \ + do_klass(VirtualObject_klass, jdk_vm_ci_code_VirtualObject, Jvmci) \ + do_klass(SpeculationLog_klass, jdk_vm_ci_meta_SpeculationLog, Jvmci) \ + do_klass(JavaConstant_klass, jdk_vm_ci_meta_JavaConstant, Jvmci) \ + do_klass(PrimitiveConstant_klass, jdk_vm_ci_meta_PrimitiveConstant, Jvmci) \ + do_klass(RawConstant_klass, jdk_vm_ci_meta_RawConstant, Jvmci) \ + do_klass(NullConstant_klass, jdk_vm_ci_meta_NullConstant, Jvmci) \ + do_klass(ExceptionHandler_klass, jdk_vm_ci_meta_ExceptionHandler, Jvmci) \ + do_klass(JavaKind_klass, jdk_vm_ci_meta_JavaKind, Jvmci) \ + do_klass(LIRKind_klass, jdk_vm_ci_meta_LIRKind, Jvmci) \ + do_klass(Value_klass, jdk_vm_ci_meta_Value, Jvmci) +#endif + +#endif // SHARE_VM_JVMCI_SYSTEMDICTIONARY_JVMCI_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP +#define SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP + +#include "compiler/abstractCompiler.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciRuntime.hpp" + +#define VM_STRUCTS_JVMCI(nonstatic_field, static_field) \ + nonstatic_field(JavaThread, _pending_deoptimization, int) \ + nonstatic_field(JavaThread, _pending_failed_speculation, oop) \ + nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \ + nonstatic_field(JavaThread, _jvmci_counters, jlong*) \ + nonstatic_field(MethodData, _jvmci_ir_size, int) \ + nonstatic_field(JVMCIEnv, _task, CompileTask*) \ + nonstatic_field(JVMCIEnv, _jvmti_can_hotswap_or_post_breakpoint, bool) \ + nonstatic_field(DeoptimizationBlob, _uncommon_trap_offset, int) \ + \ + static_field(CompilerToVM, _supports_inline_contig_alloc, bool) \ + static_field(CompilerToVM, _heap_end_addr, HeapWord**) \ + static_field(CompilerToVM, _heap_top_addr, HeapWord**) + +#define VM_TYPES_JVMCI(declare_type, declare_toplevel_type) \ + declare_toplevel_type(CompilerToVM) \ + declare_toplevel_type(JVMCIEnv) \ + +#define VM_INT_CONSTANTS_JVMCI(declare_constant, declare_preprocessor_constant) \ + declare_constant(Deoptimization::Reason_unreached0) \ + declare_constant(Deoptimization::Reason_type_checked_inlining) \ + declare_constant(Deoptimization::Reason_optimized_type_check) \ + declare_constant(Deoptimization::Reason_aliasing) \ + declare_constant(Deoptimization::Reason_transfer_to_interpreter) \ + declare_constant(Deoptimization::Reason_not_compiled_exception_handler) \ + declare_constant(Deoptimization::Reason_unresolved) \ + declare_constant(Deoptimization::Reason_jsr_mismatch) \ + declare_constant(JVMCIEnv::ok) \ + declare_constant(JVMCIEnv::dependencies_failed) \ + declare_constant(JVMCIEnv::dependencies_invalid) \ + declare_constant(JVMCIEnv::cache_full) \ + declare_constant(JVMCIEnv::code_too_large) \ + \ + declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ + declare_preprocessor_constant("JVM_RECOGNIZED_FIELD_MODIFIERS", JVM_RECOGNIZED_FIELD_MODIFIERS) \ + \ + declare_constant(CompilerToVM::KLASS_TAG) \ + declare_constant(CompilerToVM::SYMBOL_TAG) \ + \ + declare_constant(CodeInstaller::VERIFIED_ENTRY) \ + declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ + declare_constant(CodeInstaller::OSR_ENTRY) \ + declare_constant(CodeInstaller::EXCEPTION_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::DEOPT_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::INVOKEINTERFACE) \ + declare_constant(CodeInstaller::INVOKEVIRTUAL) \ + declare_constant(CodeInstaller::INVOKESTATIC) \ + declare_constant(CodeInstaller::INVOKESPECIAL) \ + declare_constant(CodeInstaller::INLINE_INVOKE) \ + declare_constant(CodeInstaller::POLL_NEAR) \ + declare_constant(CodeInstaller::POLL_RETURN_NEAR) \ + declare_constant(CodeInstaller::POLL_FAR) \ + declare_constant(CodeInstaller::POLL_RETURN_FAR) \ + declare_constant(CodeInstaller::CARD_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ + declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ + declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::INVOKE_INVALID) \ + \ + declare_constant(Method::invalid_vtable_index) \ + +#define VM_ADDRESSES_JVMCI(declare_address, declare_preprocessor_address, declare_function) \ + declare_function(JVMCIRuntime::new_instance) \ + declare_function(JVMCIRuntime::new_array) \ + declare_function(JVMCIRuntime::new_multi_array) \ + declare_function(JVMCIRuntime::dynamic_new_array) \ + declare_function(JVMCIRuntime::dynamic_new_instance) \ + \ + declare_function(JVMCIRuntime::thread_is_interrupted) \ + declare_function(JVMCIRuntime::vm_message) \ + declare_function(JVMCIRuntime::identity_hash_code) \ + declare_function(JVMCIRuntime::exception_handler_for_pc) \ + declare_function(JVMCIRuntime::monitorenter) \ + declare_function(JVMCIRuntime::monitorexit) \ + declare_function(JVMCIRuntime::create_null_exception) \ + declare_function(JVMCIRuntime::create_out_of_bounds_exception) \ + declare_function(JVMCIRuntime::log_primitive) \ + declare_function(JVMCIRuntime::log_object) \ + declare_function(JVMCIRuntime::log_printf) \ + declare_function(JVMCIRuntime::vm_error) \ + declare_function(JVMCIRuntime::load_and_clear_exception) \ + declare_function(JVMCIRuntime::write_barrier_pre) \ + declare_function(JVMCIRuntime::write_barrier_post) \ + declare_function(JVMCIRuntime::validate_object) \ + \ + declare_function(JVMCIRuntime::test_deoptimize_call_int) + +#endif // SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/jvmci/vmSymbols_jvmci.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/jvmci/vmSymbols_jvmci.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_VM_JVMCI_VMSYMBOLS_JVMCI_HPP +#define SHARE_VM_JVMCI_VMSYMBOLS_JVMCI_HPP + + +#if !INCLUDE_JVMCI +#define JVMCI_VM_SYMBOLS_DO(template, do_alias) +#else +#define JVMCI_VM_SYMBOLS_DO(template, do_alias) \ + template(jdk_vm_ci_hotspot_HotSpotCompiledCode, "jdk/vm/ci/hotspot/HotSpotCompiledCode") \ + template(jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment, "jdk/vm/ci/hotspot/HotSpotCompiledCode$Comment") \ + template(jdk_vm_ci_hotspot_HotSpotCompiledNmethod, "jdk/vm/ci/hotspot/HotSpotCompiledNmethod") \ + template(jdk_vm_ci_hotspot_HotSpotForeignCallTarget, "jdk/vm/ci/hotspot/HotSpotForeignCallTarget") \ + template(jdk_vm_ci_hotspot_HotSpotReferenceMap, "jdk/vm/ci/hotspot/HotSpotReferenceMap") \ + template(jdk_vm_ci_hotspot_CompilerToVM, "jdk/vm/ci/hotspot/CompilerToVM") \ + template(jdk_vm_ci_hotspot_HotSpotInstalledCode, "jdk/vm/ci/hotspot/HotSpotInstalledCode") \ + template(jdk_vm_ci_hotspot_HotSpotNmethod, "jdk/vm/ci/hotspot/HotSpotNmethod") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl, "jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl") \ + template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl, "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl") \ + template(jdk_vm_ci_hotspot_HotSpotCompressedNullConstant, "jdk/vm/ci/hotspot/HotSpotCompressedNullConstant") \ + template(jdk_vm_ci_hotspot_HotSpotObjectConstantImpl, "jdk/vm/ci/hotspot/HotSpotObjectConstantImpl") \ + template(jdk_vm_ci_hotspot_HotSpotMetaspaceConstantImpl, "jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl") \ + template(jdk_vm_ci_hotspot_HotSpotSentinelConstant, "jdk/vm/ci/hotspot/HotSpotSentinelConstant") \ + template(jdk_vm_ci_hotspot_HotSpotStackFrameReference, "jdk/vm/ci/hotspot/HotSpotStackFrameReference") \ + template(jdk_vm_ci_hotspot_HotSpotMetaData, "jdk/vm/ci/hotspot/HotSpotMetaData") \ + template(jdk_vm_ci_hotspot_HotSpotOopMap, "jdk/vm/ci/hotspot/HotSpotOopMap") \ + template(jdk_vm_ci_hotspot_HotSpotConstantPool, "jdk/vm/ci/hotspot/HotSpotConstantPool") \ + template(jdk_vm_ci_hotspot_HotSpotJVMCIMetaAccessContext, "jdk/vm/ci/hotspot/HotSpotJVMCIMetaAccessContext") \ + template(jdk_vm_ci_meta_JavaConstant, "jdk/vm/ci/meta/JavaConstant") \ + template(jdk_vm_ci_meta_PrimitiveConstant, "jdk/vm/ci/meta/PrimitiveConstant") \ + template(jdk_vm_ci_meta_RawConstant, "jdk/vm/ci/meta/RawConstant") \ + template(jdk_vm_ci_meta_NullConstant, "jdk/vm/ci/meta/NullConstant") \ + template(jdk_vm_ci_meta_ExceptionHandler, "jdk/vm/ci/meta/ExceptionHandler") \ + template(jdk_vm_ci_meta_JavaKind, "jdk/vm/ci/meta/JavaKind") \ + template(jdk_vm_ci_meta_LIRKind, "jdk/vm/ci/meta/LIRKind") \ + template(jdk_vm_ci_meta_Value, "jdk/vm/ci/meta/Value") \ + template(jdk_vm_ci_meta_Assumptions_ConcreteSubtype, "jdk/vm/ci/meta/Assumptions$ConcreteSubtype") \ + template(jdk_vm_ci_meta_Assumptions_LeafType, "jdk/vm/ci/meta/Assumptions$LeafType") \ + template(jdk_vm_ci_meta_Assumptions_NoFinalizableSubclass, "jdk/vm/ci/meta/Assumptions$NoFinalizableSubclass") \ + template(jdk_vm_ci_meta_Assumptions_ConcreteMethod, "jdk/vm/ci/meta/Assumptions$ConcreteMethod") \ + template(jdk_vm_ci_meta_Assumptions_CallSiteTargetValue, "jdk/vm/ci/meta/Assumptions$CallSiteTargetValue") \ + template(jdk_vm_ci_meta_SpeculationLog, "jdk/vm/ci/meta/SpeculationLog") \ + template(jdk_vm_ci_code_Architecture, "jdk/vm/ci/code/Architecture") \ + template(jdk_vm_ci_code_TargetDescription, "jdk/vm/ci/code/TargetDescription") \ + template(jdk_vm_ci_code_CompilationResult_Call, "jdk/vm/ci/code/CompilationResult$Call") \ + template(jdk_vm_ci_code_CompilationResult_ConstantReference, "jdk/vm/ci/code/CompilationResult$ConstantReference") \ + template(jdk_vm_ci_code_CompilationResult_DataPatch, "jdk/vm/ci/code/CompilationResult$DataPatch") \ + template(jdk_vm_ci_code_CompilationResult_DataSectionReference, "jdk/vm/ci/code/CompilationResult$DataSectionReference") \ + template(jdk_vm_ci_code_CompilationResult_ExceptionHandler, "jdk/vm/ci/code/CompilationResult$ExceptionHandler") \ + template(jdk_vm_ci_code_CompilationResult_Mark, "jdk/vm/ci/code/CompilationResult$Mark") \ + template(jdk_vm_ci_code_CompilationResult_Infopoint, "jdk/vm/ci/code/CompilationResult$Infopoint") \ + template(jdk_vm_ci_code_CompilationResult_Site, "jdk/vm/ci/code/CompilationResult$Site") \ + template(jdk_vm_ci_code_InfopointReason, "jdk/vm/ci/code/InfopointReason") \ + template(jdk_vm_ci_code_InstalledCode, "jdk/vm/ci/code/InstalledCode") \ + template(jdk_vm_ci_code_BytecodeFrame, "jdk/vm/ci/code/BytecodeFrame") \ + template(jdk_vm_ci_code_BytecodePosition, "jdk/vm/ci/code/BytecodePosition") \ + template(jdk_vm_ci_code_DebugInfo, "jdk/vm/ci/code/DebugInfo") \ + template(jdk_vm_ci_code_Location, "jdk/vm/ci/code/Location") \ + template(jdk_vm_ci_code_Register, "jdk/vm/ci/code/Register") \ + template(jdk_vm_ci_code_RegisterValue, "jdk/vm/ci/code/RegisterValue") \ + template(jdk_vm_ci_code_StackSlot, "jdk/vm/ci/code/StackSlot") \ + template(jdk_vm_ci_code_StackLockValue, "jdk/vm/ci/code/StackLockValue") \ + template(jdk_vm_ci_code_VirtualObject, "jdk/vm/ci/code/VirtualObject") \ + template(jdk_vm_ci_code_RegisterSaveLayout, "jdk/vm/ci/code/RegisterSaveLayout") \ + template(jdk_vm_ci_code_InvalidInstalledCodeException, "jdk/vm/ci/code/InvalidInstalledCodeException") \ + template(compileMethod_name, "compileMethod") \ + template(compileMethod_signature, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;IJI)V") \ + template(fromMetaspace_name, "fromMetaspace") \ + template(method_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;") \ + template(constantPool_fromMetaspace_signature, "(J)Ljdk/vm/ci/hotspot/HotSpotConstantPool;") \ + template(klass_fromMetaspace_signature, "(Ljava/lang/Class;)Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;") \ + template(jdk_vm_ci_hotspot_Stable_signature, "Ljdk/vm/ci/hotspot/Stable;") +#endif + +#endif // SHARE_VM_JVMCI_VMSYMBOLS_JVMCI_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/libadt/dict.cpp --- a/hotspot/src/share/vm/libadt/dict.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/libadt/dict.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,8 +31,6 @@ #include -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - //------------------------------data----------------------------------------- // String hash tables #define MAXID 20 @@ -288,9 +286,9 @@ // Handier print routine void Dict::print() { DictI i(this); // Moved definition in iterator here because of g++. - tty->print("Dict@0x%lx[%d] = {", this, _cnt); + tty->print("Dict@" INTPTR_FORMAT "[%d] = {", p2i(this), _cnt); for( ; i.test(); ++i ) { - tty->print("(0x%lx,0x%lx),", i._key, i._value); + tty->print("(" INTPTR_FORMAT "," INTPTR_FORMAT "),", p2i(i._key), p2i(i._value)); } tty->print_cr("}"); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/log.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/log.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOG_HPP +#define SHARE_VM_LOGGING_LOG_HPP + +#include "logging/logLevel.hpp" +#include "logging/logPrefix.hpp" +#include "logging/logTagSet.hpp" +#include "logging/logTag.hpp" +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" +#include "utilities/ostream.hpp" + +// +// Logging macros +// +// Usage: +// log_()(); +// e.g. +// log_debug(logging)("message %d", i); +// +// Note that these macros will not evaluate the arguments unless the logging is enabled. +// +#define log_error(...) (!log_is_enabled(Error, __VA_ARGS__)) ? (void)0 : Log::write +#define log_warning(...) (!log_is_enabled(Warning, __VA_ARGS__)) ? (void)0 : Log::write +#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log::write +#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log::write +#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log::write +#ifndef PRODUCT +#define log_develop(...) (!log_is_enabled(Develop, __VA_ARGS__)) ? (void)0 : Log::write +#else +#define DUMMY_ARGUMENT_CONSUMER(...) +#define log_develop(...) DUMMY_ARGUMENT_CONSUMER +#endif + +// Convenience macro to test if the logging is enabled on the specified level for given tags. +#define log_is_enabled(level, ...) (Log::is_level(LogLevel::level)) + +// +// Log class for more advanced logging scenarios. +// Has printf-style member functions for each log level (trace(), debug(), etc). +// +// Also has outputStream compatible API for the different log-levels. +// The streams are resource allocated when requested and are accessed through +// calls to _stream() functions (trace_stream(), debug_stream(), etc). +// +// Example usage: +// LogHandle(logging) log; +// if (log.is_debug()) { +// ... +// log.debug("result = %d", result).trace(" tracing info"); +// obj->print_on(log.debug_stream()); +// } +// +#define LogHandle(...) Log + +template +class Log VALUE_OBJ_CLASS_SPEC { + private: + static const size_t LogBufferSize = 512; + public: + // Make sure no more than the maximum number of tags have been given. + // The GuardTag allows this to be detected if/when it happens. If the GuardTag + // is not __NO_TAG, the number of tags given exceeds the maximum allowed. + STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); // Number of logging tags exceeds maximum supported! + + static bool is_level(LogLevelType level) { + return LogTagSetMapping::tagset().is_level(level); + } + + template + ATTRIBUTE_PRINTF(1, 2) + static void write(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vwrite(fmt, args); + va_end(args); + }; + + template + ATTRIBUTE_PRINTF(1, 0) + static void vwrite(const char* fmt, va_list args) { + char buf[LogBufferSize]; + size_t prefix_len = LogPrefix::prefix(buf, sizeof(buf)); + int ret = vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args); + assert(ret >= 0 && (size_t)ret < sizeof(buf), "Log message too long"); + puts(buf); + } + + template + static void puts(const char* string) { + LogTagSetMapping::tagset().log(Level, string); + } + +#define LOG_LEVEL(level, name) ATTRIBUTE_PRINTF(2, 0) \ + Log& v##name(const char* fmt, va_list args) { \ + vwrite(fmt, args); \ + return *this; \ + } \ + Log& name(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { \ + va_list args; \ + va_start(args, fmt); \ + vwrite(fmt, args); \ + va_end(args); \ + return *this; \ + } \ + static bool is_##name() { \ + return is_level(LogLevel::level); \ + } \ + static outputStream* name##_stream() { \ + return new logStream(write); \ + } + LOG_LEVEL_LIST +#undef LOG_LEVEL +}; + +#endif // SHARE_VM_LOGGING_LOG_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logConfiguration.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/log.hpp" +#include "logging/logConfiguration.hpp" +#include "logging/logDecorations.hpp" +#include "logging/logDecorators.hpp" +#include "logging/logDiagnosticCommand.hpp" +#include "logging/logFileOutput.hpp" +#include "logging/logOutput.hpp" +#include "logging/logTagLevelExpression.hpp" +#include "logging/logTagSet.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/os.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +LogOutput** LogConfiguration::_outputs = NULL; +size_t LogConfiguration::_n_outputs = 0; + +void LogConfiguration::post_initialize() { + assert(LogConfiguration_lock != NULL, "Lock must be initialized before post-initialization"); + LogDiagnosticCommand::registerCommand(); + LogHandle(logging) log; + log.info("Log configuration fully initialized."); + if (log.is_trace()) { + ResourceMark rm; + MutexLocker ml(LogConfiguration_lock); + describe(log.trace_stream()); + } +} + +void LogConfiguration::initialize(jlong vm_start_time) { + LogFileOutput::set_file_name_parameters(vm_start_time); + LogDecorations::set_vm_start_time_millis(vm_start_time); + + assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?"); + _outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging); + _outputs[0] = LogOutput::Stdout; + _outputs[1] = LogOutput::Stderr; + _n_outputs = 2; +} + +void LogConfiguration::finalize() { + for (size_t i = 2; i < _n_outputs; i++) { + delete _outputs[i]; + } + FREE_C_HEAP_ARRAY(LogOutput*, _outputs); +} + +size_t LogConfiguration::find_output(const char* name) { + for (size_t i = 0; i < _n_outputs; i++) { + if (strcmp(_outputs[i]->name(), name) == 0) { + return i; + } + } + return SIZE_MAX; +} + +LogOutput* LogConfiguration::new_output(char* name, const char* options) { + const char* type; + char* equals_pos = strchr(name, '='); + if (equals_pos == NULL) { + type = "file"; + } else { + *equals_pos = '\0'; + type = name; + name = equals_pos + 1; + } + + LogOutput* output; + if (strcmp(type, "file") == 0) { + output = new LogFileOutput(name); + } else { + // unsupported log output type + return NULL; + } + + bool success = output->initialize(options); + if (!success) { + delete output; + return NULL; + } + return output; +} + +size_t LogConfiguration::add_output(LogOutput* output) { + size_t idx = _n_outputs++; + _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); + _outputs[idx] = output; + return idx; +} + +void LogConfiguration::delete_output(size_t idx) { + assert(idx > 1 && idx < _n_outputs, + "idx must be in range 1 < idx < _n_outputs, but idx = " SIZE_FORMAT + " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs); + LogOutput* output = _outputs[idx]; + // Swap places with the last output and shrink the array + _outputs[idx] = _outputs[--_n_outputs]; + _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); + delete output; +} + +void LogConfiguration::configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators) { + assert(idx < _n_outputs, "Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs); + LogOutput* output = _outputs[idx]; + output->set_decorators(decorators); + output->set_config_string(tag_level_expression.to_string()); + bool enabled = false; + for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { + LogLevelType level = tag_level_expression.level_for(*ts); + if (level != LogLevel::Off) { + enabled = true; + } + ts->update_decorators(decorators); + ts->set_output_level(output, level); + } + + // If the output is not used by any tagset it should be removed, unless it is stdout/stderr. + if (!enabled && idx > 1) { + delete_output(idx); + } +} + +void LogConfiguration::disable_output(size_t idx) { + LogOutput* out = _outputs[idx]; + LogDecorators empty_decorators; + empty_decorators.clear(); + + // Remove the output from all tagsets. + for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { + ts->set_output_level(out, LogLevel::Off); + ts->update_decorators(empty_decorators); + } + + // Delete the output unless stdout/stderr + if (out != LogOutput::Stderr && out != LogOutput::Stdout) { + delete_output(find_output(out->name())); + } else { + out->set_config_string("all=off"); + } +} + +void LogConfiguration::disable_logging() { + assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), + "LogConfiguration lock must be held when calling this function"); + for (size_t i = 0; i < _n_outputs; i++) { + disable_output(i); + } +} + +bool LogConfiguration::parse_command_line_arguments(const char* opts) { + char* copy = os::strdup_check_oom(opts, mtLogging); + + // Split the option string to its colon separated components. + char* what = NULL; + char* output_str = NULL; + char* decorators_str = NULL; + char* output_options = NULL; + + what = copy; + char* colon = strchr(what, ':'); + if (colon != NULL) { + *colon = '\0'; + output_str = colon + 1; + colon = strchr(output_str, ':'); + if (colon != NULL) { + *colon = '\0'; + decorators_str = colon + 1; + colon = strchr(decorators_str, ':'); + if (colon != NULL) { + *colon = '\0'; + output_options = colon + 1; + } + } + } + + // Parse each argument + char errbuf[512]; + stringStream ss(errbuf, sizeof(errbuf)); + bool success = parse_log_arguments(output_str, what, decorators_str, output_options, &ss); + if (!success) { + errbuf[strlen(errbuf) - 1] = '\0'; // Strip trailing newline. + log_error(logging)("%s", errbuf); + } + + os::free(copy); + return success; +} + +bool LogConfiguration::parse_log_arguments(const char* outputstr, + const char* what, + const char* decoratorstr, + const char* output_options, + outputStream* errstream) { + assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), + "LogConfiguration lock must be held when calling this function"); + if (outputstr == NULL || strlen(outputstr) == 0) { + outputstr = "stdout"; + } + + size_t idx; + if (outputstr[0] == '#') { + int ret = sscanf(outputstr+1, SIZE_FORMAT, &idx); + if (ret != 1 || idx >= _n_outputs) { + errstream->print_cr("Invalid output index '%s'", outputstr); + return false; + } + } else { + idx = find_output(outputstr); + if (idx == SIZE_MAX) { + char* tmp = os::strdup_check_oom(outputstr, mtLogging); + LogOutput* output = new_output(tmp, output_options); + os::free(tmp); + if (output == NULL) { + errstream->print("Unable to add output '%s'", outputstr); + if (output_options != NULL && strlen(output_options) > 0) { + errstream->print(" with options '%s'", output_options); + } + errstream->cr(); + return false; + } + idx = add_output(output); + } else if (output_options != NULL && strlen(output_options) > 0) { + errstream->print_cr("Output options for existing outputs are ignored."); + } + } + + LogTagLevelExpression expr; + if (!expr.parse(what, errstream)) { + return false; + } + + LogDecorators decorators; + if (!decorators.parse(decoratorstr, errstream)) { + return false; + } + + configure_output(idx, expr, decorators); + return true; +} + +void LogConfiguration::describe(outputStream* out) { + assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(), + "LogConfiguration lock must be held when calling this function"); + + out->print("Available log levels:"); + for (size_t i = 0; i < LogLevel::Count; i++) { + out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast(i))); + } + out->cr(); + + out->print("Available log decorators:"); + for (size_t i = 0; i < LogDecorators::Count; i++) { + LogDecorators::Decorator d = static_cast(i); + out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d)); + } + out->cr(); + + out->print("Available log tags:"); + for (size_t i = 1; i < LogTag::Count; i++) { + out->print("%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast(i))); + } + out->cr(); + + out->print_cr("Log output configuration:"); + for (size_t i = 0; i < _n_outputs; i++) { + out->print("#" SIZE_FORMAT ": %s %s ", i, _outputs[i]->name(), _outputs[i]->config_string()); + for (size_t d = 0; d < LogDecorators::Count; d++) { + LogDecorators::Decorator decorator = static_cast(d); + if (_outputs[i]->decorators().is_decorator(decorator)) { + out->print("%s,", LogDecorators::name(decorator)); + } + } + out->cr(); + } +} + +void LogConfiguration::print_command_line_help(FILE* out) { + jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n" + "\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n" + "\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n"); + + jio_fprintf(out, "Available log levels:\n"); + for (size_t i = 0; i < LogLevel::Count; i++) { + jio_fprintf(out, "%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast(i))); + } + + jio_fprintf(out, "\n\nAvailable log decorators: \n"); + for (size_t i = 0; i < LogDecorators::Count; i++) { + LogDecorators::Decorator d = static_cast(i); + jio_fprintf(out, "%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d)); + } + jio_fprintf(out, "\n Decorators can also be specified as 'none' for no decoration.\n\n"); + + jio_fprintf(out, "Available log tags:\n"); + for (size_t i = 1; i < LogTag::Count; i++) { + jio_fprintf(out, "%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast(i))); + } + jio_fprintf(out, "\n Specifying 'all' instead of a tag combination matches all tag combinations.\n\n"); + + jio_fprintf(out, "Available log outputs:\n" + " stdout, stderr, file=\n" + " Specifying %%p and/or %%t in the filename will expand to the JVM's PID and startup timestamp, respectively.\n\n" + + "Some examples:\n" + " -Xlog\n" + "\t Log all messages using 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.\n" + "\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).\n\n" + + " -Xlog:gc\n" + "\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n" + + " -Xlog:gc=debug:file=gc.txt:none\n" + "\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n" + + " -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1024\n" + "\t Log messages tagged with 'gc' tag using 'trace' level to a rotating fileset of 5 files of size 1MB,\n" + "\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.\n\n" + + " -Xlog:gc::uptime,tid\n" + "\t Log messages tagged with 'gc' tag using 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.\n\n" + + " -Xlog:gc*=info,rt*=off\n" + "\t Log messages tagged with at least 'gc' using 'info' level, but turn off logging of messages tagged with 'rt'.\n" + "\t (Messages tagged with both 'gc' and 'rt' will not be logged.)\n\n" + + " -Xlog:disable -Xlog:rt=trace:rttrace.txt\n" + "\t Turn off all logging, including warnings and errors,\n" + "\t and then enable messages tagged with 'rt' using 'trace' level to file 'rttrace.txt'.\n"); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logConfiguration.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logConfiguration.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGCONFIGURATION_HPP +#define SHARE_VM_LOGGING_LOGCONFIGURATION_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogOutput; +class LogDecorators; +class LogTagLevelExpression; + +// Global configuration of logging. Handles parsing and configuration of the logging framework, +// and manages the list of configured log outputs. The actual tag and level configuration is +// kept implicitly in the LogTagSets and their LogOutputLists. During configuration the tagsets +// are iterated over and updated accordingly. +class LogConfiguration : public AllStatic { + private: + static LogOutput** _outputs; + static size_t _n_outputs; + + // Create a new output. Returns NULL if failed. + static LogOutput* new_output(char* name, const char* options = NULL); + + // Add an output to the list of configured outputs. Returns the assigned index. + static size_t add_output(LogOutput* out); + + // Delete a configured output. The stderr/stdout outputs can not be removed. + // Output should be completely disabled before it is deleted. + static void delete_output(size_t idx); + + // Disable all logging to the specified output and then delete it (unless it is stdout/stderr). + static void disable_output(size_t idx); + + // Get output index by name. Returns SIZE_MAX if output not found. + static size_t find_output(const char* name); + + // Configure output (add or update existing configuration) to log on tag-level combination using specified decorators. + static void configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators); + + public: + // Initialization and finalization of log configuration, to be run at vm startup and shutdown respectively. + static void initialize(jlong vm_start_time); + static void finalize(); + + // Perform necessary post-initialization after VM startup. Enables reconfiguration of logging. + static void post_initialize(); + + // Disable all logging, equivalent to -Xlog:disable. + static void disable_logging(); + + // Parse command line configuration. Parameter 'opts' is the string immediately following the -Xlog: argument ("gc" for -Xlog:gc). + static bool parse_command_line_arguments(const char* opts = "all"); + + // Parse separated configuration arguments (from JCmd/MBean and command line). + static bool parse_log_arguments(const char* outputstr, + const char* what, + const char* decoratorstr, + const char* output_options, + outputStream* errstream); + + // Prints log configuration to outputStream, used by JCmd/MBean. + static void describe(outputStream* out); + + // Prints usage help for command line log configuration. + static void print_command_line_help(FILE* out); +}; + +#endif // SHARE_VM_LOGGING_LOGCONFIGURATION_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logDecorations.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logDecorations.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logConfiguration.hpp" +#include "logging/logDecorations.hpp" +#include "runtime/os.inline.hpp" +#include "runtime/thread.inline.hpp" +#include "services/management.hpp" + +jlong LogDecorations::_vm_start_time_millis = 0; + +LogDecorations::LogDecorations(LogLevelType level, const LogTagSet &tagset, const LogDecorators &decorators) + : _level(level), _tagset(tagset), _millis(-1) { + create_decorations(decorators); +} + +void LogDecorations::create_decorations(const LogDecorators &decorators) { + char* position = _decorations_buffer; + #define DECORATOR(full_name, abbr) \ + if (decorators.is_decorator(LogDecorators::full_name##_decorator)) { \ + _decoration_offset[LogDecorators::full_name##_decorator] = position; \ + position = create_##full_name##_decoration(position) + 1; \ + } + DECORATOR_LIST +#undef DECORATOR +} + +jlong LogDecorations::java_millis() { + if (_millis < 0) { + _millis = os::javaTimeMillis(); + } + return _millis; +} + +#define ASSERT_AND_RETURN(written, pos) \ + assert(written >= 0, "Decorations buffer overflow"); \ + return pos + written; + +char* LogDecorations::create_time_decoration(char* pos) { + char* buf = os::iso8601_time(pos, 29); + int written = buf == NULL ? -1 : 29; + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_uptime_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%.3fs", os::elapsedTime()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_timemillis_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ms", java_millis()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_uptimemillis_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), + INT64_FORMAT "ms", java_millis() - _vm_start_time_millis); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_timenanos_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ns", os::javaTimeNanos()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_uptimenanos_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ns", os::elapsed_counter()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_pid_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%d", os::current_process_id()); + ASSERT_AND_RETURN(written, pos) +} + +char * LogDecorations::create_tid_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), + INTX_FORMAT, Thread::current()->osthread()->thread_id()); + ASSERT_AND_RETURN(written, pos) +} + +char* LogDecorations::create_level_decoration(char* pos) { + int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%s", LogLevel::name(_level)); + ASSERT_AND_RETURN(written, pos) +} + +char* LogDecorations::create_tags_decoration(char* pos) { + int written = _tagset.label(pos, DecorationsBufferSize - (pos - _decorations_buffer)); + ASSERT_AND_RETURN(written, pos) +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logDecorations.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logDecorations.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGDECORATIONS_HPP +#define SHARE_VM_LOGGING_LOGDECORATIONS_HPP + +#include "logging/logDecorators.hpp" +#include "logging/logTagSet.hpp" +#include "memory/allocation.hpp" + +// Temporary object containing the necessary data for a log call's decorations (timestamps, etc). +class LogDecorations VALUE_OBJ_CLASS_SPEC { + public: + static const int DecorationsBufferSize = 256; + private: + char _decorations_buffer[DecorationsBufferSize]; + char* _decoration_offset[LogDecorators::Count]; + LogLevelType _level; + LogTagSet _tagset; + jlong _millis; + static jlong _vm_start_time_millis; + + jlong java_millis(); + void create_decorations(const LogDecorators& decorators); + +#define DECORATOR(name, abbr) char* create_##name##_decoration(char* pos); + DECORATOR_LIST +#undef DECORATOR + + public: + LogDecorations(LogLevelType level, const LogTagSet& tagset, const LogDecorators& decorators); + + const char* decoration(LogDecorators::Decorator decorator) const { + return _decoration_offset[decorator]; + } + + static void set_vm_start_time_millis(jlong start_time) { + _vm_start_time_millis = start_time; + } +}; + +#endif // SHARE_VM_LOGGING_LOGDECORATIONS_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logDecorators.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logDecorators.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logDecorators.hpp" +#include "runtime/os.inline.hpp" + +const char* LogDecorators::_name[][2] = { +#define DECORATOR(n, a) {#n, #a}, + DECORATOR_LIST +#undef DECORATOR +}; + +LogDecorators::Decorator LogDecorators::from_string(const char* str) { + for (size_t i = 0; i < Count; i++) { + Decorator d = static_cast(i); + if (strcasecmp(str, name(d)) == 0 || strcasecmp(str, abbreviation(d)) == 0) { + return d; + } + } + return Invalid; +} + +bool LogDecorators::parse(const char* decorator_args, outputStream* errstream) { + if (decorator_args == NULL || strlen(decorator_args) == 0) { + _decorators = DefaultDecoratorsMask; + return true; + } + + if (strcasecmp(decorator_args, "none") == 0 ) { + _decorators = 0; + return true; + } + + bool result = true; + uint tmp_decorators = 0; + char* args_copy = os::strdup_check_oom(decorator_args, mtLogging); + char* token = args_copy; + char* comma_pos; + do { + comma_pos = strchr(token, ','); + if (comma_pos != NULL) { + *comma_pos = '\0'; + } + Decorator d = from_string(token); + if (d == Invalid) { + if (errstream != NULL) { + errstream->print_cr("Invalid decorator '%s'.", token); + } + result = false; + break; + } + tmp_decorators |= mask(d); + token = comma_pos + 1; + } while (comma_pos != NULL); + os::free(args_copy); + if (result) { + _decorators = tmp_decorators; + } + return result; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logDecorators.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logDecorators.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGDECORATORS_HPP +#define SHARE_VM_LOGGING_LOGDECORATORS_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +// The list of available decorators: +// time - Current time and date in ISO-8601 format +// uptime - Time since the start of the JVM in seconds and milliseconds (e.g., 6.567s) +// timemillis - The same value as generated by System.currentTimeMillis() +// uptimemillis - Milliseconds since the JVM started +// timenanos - The same value as generated by System.nanoTime() +// uptimenanos - Nanoseconds since the JVM started +// pid - The process identifier +// tid - The thread identifier +// level - The level associated with the log message +// tags - The tag-set associated with the log message +#define DECORATOR_LIST \ + DECORATOR(time, t) \ + DECORATOR(uptime, u) \ + DECORATOR(timemillis, tm) \ + DECORATOR(uptimemillis, um) \ + DECORATOR(timenanos, tn) \ + DECORATOR(uptimenanos, un) \ + DECORATOR(pid, p) \ + DECORATOR(tid, ti) \ + DECORATOR(level, l) \ + DECORATOR(tags, tg) + +// LogDecorators represents a selection of decorators that should be prepended to +// each log message for a given output. Decorators are always prepended in the order +// declared above. For example, logging with 'uptime, level, tags' decorators results in: +// [0,943s][info ][logging] message. +class LogDecorators VALUE_OBJ_CLASS_SPEC { + public: + enum Decorator { +#define DECORATOR(name, abbr) name##_decorator, + DECORATOR_LIST +#undef DECORATOR + Count, + Invalid + }; + + private: + uint _decorators; + static const char* _name[][2]; + static const uint DefaultDecoratorsMask = (1 << uptime_decorator) | (1 << level_decorator) | (1 << tags_decorator); + + static uint mask(LogDecorators::Decorator decorator) { + return 1 << decorator; + } + + public: + LogDecorators() : _decorators(DefaultDecoratorsMask) { + }; + + void clear() { + _decorators = 0; + } + + static const char* name(LogDecorators::Decorator decorator) { + return _name[decorator][0]; + } + + static const char* abbreviation(LogDecorators::Decorator decorator) { + return _name[decorator][1]; + } + + static LogDecorators::Decorator from_string(const char* str); + + void combine_with(const LogDecorators &source) { + _decorators |= source._decorators; + } + + bool is_decorator(LogDecorators::Decorator decorator) const { + return (_decorators & mask(decorator)) != 0; + } + + bool parse(const char* decorator_args, outputStream* errstream = NULL); +}; + +#endif // SHARE_VM_LOGGING_LOGDECORATORS_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logDiagnosticCommand.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logConfiguration.hpp" +#include "logging/logDiagnosticCommand.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/mutexLocker.hpp" +#include "utilities/globalDefinitions.hpp" + +LogDiagnosticCommand::LogDiagnosticCommand(outputStream* output, bool heap_allocated) + : DCmdWithParser(output, heap_allocated), + _output("output", "The name or index (#) of output to configure.", "STRING", false), + _output_options("output_options", "Options for the output.", "STRING", false), + _what("what", "Configures what tags to log.", "STRING", false), + _decorators("decorators", "Configures which decorators to use. Use 'none' or an empty value to remove all.", "STRING", false), + _disable("disable", "Turns off all logging and clears the log configuration.", "BOOLEAN", false), + _list("list", "Lists current log configuration.", "BOOLEAN", false) { + _dcmdparser.add_dcmd_option(&_output); + _dcmdparser.add_dcmd_option(&_output_options); + _dcmdparser.add_dcmd_option(&_what); + _dcmdparser.add_dcmd_option(&_decorators); + _dcmdparser.add_dcmd_option(&_disable); + _dcmdparser.add_dcmd_option(&_list); +} + +int LogDiagnosticCommand::num_arguments() { + ResourceMark rm; + LogDiagnosticCommand* dcmd = new LogDiagnosticCommand(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} + +void LogDiagnosticCommand::registerCommand() { + uint32_t full_visibility = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean; + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_visibility, true, false)); +} + +void LogDiagnosticCommand::execute(DCmdSource source, TRAPS) { + bool any_command = false; + if (_disable.has_value()) { + MutexLocker ml(LogConfiguration_lock); + LogConfiguration::disable_logging(); + any_command = true; + } + + if (_output.has_value() || _what.has_value() || _decorators.has_value()) { + MutexLocker ml(LogConfiguration_lock); + if (!LogConfiguration::parse_log_arguments(_output.value(), + _what.value(), + _decorators.value(), + _output_options.value(), + output())) { + return; + } + any_command = true; + } + + if (_list.has_value()) { + MutexLocker ml(LogConfiguration_lock); + LogConfiguration::describe(output()); + any_command = true; + } + + if (!any_command) { + // If no argument was provided, print usage + print_help(LogDiagnosticCommand::name()); + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logDiagnosticCommand.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP +#define SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP + +#include "services/diagnosticCommand.hpp" + +// The LogDiagnosticCommand represents the 'VM.log' DCMD +// that allows configuration of the logging at runtime. +// It can be used to view or modify the current log configuration. +// VM.log without additional arguments prints the usage description. +// The 'list' argument will list all available log tags, +// levels, decorators and currently configured log outputs. +// Specifying 'disable' will disable logging completely. +// The remaining arguments are used to set a log output to log everything +// with the specified tags and levels using the given decorators. +class LogDiagnosticCommand : public DCmdWithParser { + protected: + DCmdArgument _output; + DCmdArgument _output_options; + DCmdArgument _what; + DCmdArgument _decorators; + DCmdArgument _disable; + DCmdArgument _list; + + public: + LogDiagnosticCommand(outputStream* output, bool heap_allocated); + void execute(DCmdSource source, TRAPS); + static void registerCommand(); + static int num_arguments(); + + static const char* name() { + return "VM.log"; + } + + static const char* description() { + return "Lists, enables, disables or changes a log output configuration."; + } + + // Used by SecurityManager. This DCMD requires ManagementPermission = control. + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", "control", NULL}; + return p; + } +}; + +#endif // SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logFileOutput.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logFileOutput.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/log.hpp" +#include "logging/logConfiguration.hpp" +#include "logging/logFileOutput.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/os.inline.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/defaultStream.hpp" + +const char* LogFileOutput::FileOpenMode = "a"; +const char* LogFileOutput::PidFilenamePlaceholder = "%p"; +const char* LogFileOutput::TimestampFilenamePlaceholder = "%t"; +const char* LogFileOutput::TimestampFormat = "%Y-%m-%d_%H-%M-%S"; +const char* LogFileOutput::FileSizeOptionKey = "filesize"; +const char* LogFileOutput::FileCountOptionKey = "filecount"; +char LogFileOutput::_pid_str[PidBufferSize]; +char LogFileOutput::_vm_start_time_str[StartTimeBufferSize]; + +LogFileOutput::LogFileOutput(const char* name) + : LogFileStreamOutput(NULL), _name(os::strdup_check_oom(name, mtLogging)), + _file_name(NULL), _archive_name(NULL), _archive_name_len(0), _current_size(0), + _rotate_size(0), _current_file(1), _file_count(0), + _rotation_lock(Mutex::leaf, "LogFileOutput rotation lock", true, Mutex::_safepoint_check_sometimes) { + _file_name = make_file_name(name, _pid_str, _vm_start_time_str); +} + +void LogFileOutput::set_file_name_parameters(jlong vm_start_time) { + int res = jio_snprintf(_pid_str, sizeof(_pid_str), "%d", os::current_process_id()); + assert(res > 0, "PID buffer too small"); + + struct tm local_time; + time_t utc_time = vm_start_time / 1000; + os::localtime_pd(&utc_time, &local_time); + res = (int)strftime(_vm_start_time_str, sizeof(_vm_start_time_str), TimestampFormat, &local_time); + assert(res > 0, "VM start time buffer too small."); +} + +LogFileOutput::~LogFileOutput() { + if (_stream != NULL) { + if (_archive_name != NULL) { + archive(); + } + if (fclose(_stream) != 0) { + jio_fprintf(defaultStream::error_stream(), "Could not close log file '%s' (%s).\n", + _file_name, strerror(errno)); + } + } + os::free(_archive_name); + os::free(_file_name); + os::free(const_cast(_name)); +} + +size_t LogFileOutput::parse_value(const char* value_str) { + char* end; + unsigned long long value = strtoull(value_str, &end, 10); + if (!isdigit(*value_str) || end != value_str + strlen(value_str) || value >= SIZE_MAX) { + return SIZE_MAX; + } + return value; +} + +bool LogFileOutput::configure_rotation(const char* options) { + if (options == NULL || strlen(options) == 0) { + return true; + } + bool success = true; + char* opts = os::strdup_check_oom(options, mtLogging); + + char* comma_pos; + char* pos = opts; + do { + comma_pos = strchr(pos, ','); + if (comma_pos != NULL) { + *comma_pos = '\0'; + } + + char* equals_pos = strchr(pos, '='); + if (equals_pos == NULL) { + success = false; + break; + } + char* key = pos; + char* value_str = equals_pos + 1; + *equals_pos = '\0'; + + if (strcmp(FileCountOptionKey, key) == 0) { + size_t value = parse_value(value_str); + if (value == SIZE_MAX || value >= UINT_MAX) { + success = false; + break; + } + _file_count = static_cast(value); + _file_count_max_digits = static_cast(log10(static_cast(_file_count)) + 1); + _archive_name_len = 2 + strlen(_file_name) + _file_count_max_digits; + _archive_name = NEW_C_HEAP_ARRAY(char, _archive_name_len, mtLogging); + } else if (strcmp(FileSizeOptionKey, key) == 0) { + size_t value = parse_value(value_str); + if (value == SIZE_MAX || value > SIZE_MAX / K) { + success = false; + break; + } + _rotate_size = value * K; + } else { + success = false; + break; + } + pos = comma_pos + 1; + } while (comma_pos != NULL); + + os::free(opts); + return success; +} + +bool LogFileOutput::initialize(const char* options) { + if (!configure_rotation(options)) { + return false; + } + _stream = fopen(_file_name, FileOpenMode); + if (_stream == NULL) { + log_error(logging)("Could not open log file '%s' (%s).\n", _file_name, strerror(errno)); + return false; + } + return true; +} + +int LogFileOutput::write(const LogDecorations& decorations, const char* msg) { + if (_stream == NULL) { + // An error has occurred with this output, avoid writing to it. + return 0; + } + int written = LogFileStreamOutput::write(decorations, msg); + _current_size += written; + + if (should_rotate()) { + MutexLockerEx ml(&_rotation_lock, true /* no safepoint check */); + if (should_rotate()) { + rotate(); + } + } + + return written; +} + +void LogFileOutput::archive() { + assert(_archive_name != NULL && _archive_name_len > 0, "Rotation must be configured before using this function."); + int ret = jio_snprintf(_archive_name, _archive_name_len, "%s.%0*u", + _file_name, _file_count_max_digits, _current_file); + assert(ret >= 0, "Buffer should always be large enough"); + + // Attempt to remove possibly existing archived log file before we rename. + // Don't care if it fails, we really only care about the rename that follows. + remove(_archive_name); + + // Rename the file from ex hotspot.log to hotspot.log.2 + if (rename(_file_name, _archive_name) == -1) { + jio_fprintf(defaultStream::error_stream(), "Could not rename log file '%s' to '%s' (%s).\n", + _file_name, _archive_name, strerror(errno)); + } +} + +void LogFileOutput::rotate() { + // Archive the current log file + archive(); + + // Open the active log file using the same stream as before + _stream = freopen(_file_name, FileOpenMode, _stream); + if (_stream == NULL) { + jio_fprintf(defaultStream::error_stream(), "Could not reopen file '%s' during log rotation (%s).\n", + _file_name, strerror(errno)); + return; + } + + // Reset accumulated size, increase current file counter, and check for file count wrap-around. + _current_size = 0; + _current_file = (_current_file >= _file_count ? 1 : _current_file + 1); +} + +char* LogFileOutput::make_file_name(const char* file_name, + const char* pid_string, + const char* timestamp_string) { + char* result = NULL; + + // Lets start finding out if we have any %d and/or %t in the name. + // We will only replace the first occurrence of any placeholder + const char* pid = strstr(file_name, PidFilenamePlaceholder); + const char* timestamp = strstr(file_name, TimestampFilenamePlaceholder); + + if (pid == NULL && timestamp == NULL) { + // We found no place-holders, return the simple filename + return os::strdup_check_oom(file_name, mtLogging); + } + + // At least one of the place-holders were found in the file_name + const char* first = ""; + size_t first_pos = SIZE_MAX; + size_t first_replace_len = 0; + + const char* second = ""; + size_t second_pos = SIZE_MAX; + size_t second_replace_len = 0; + + // If we found a %p, then setup our variables accordingly + if (pid != NULL) { + if (timestamp == NULL || pid < timestamp) { + first = pid_string; + first_pos = pid - file_name; + first_replace_len = strlen(PidFilenamePlaceholder); + } else { + second = pid_string; + second_pos = pid - file_name; + second_replace_len = strlen(PidFilenamePlaceholder); + } + } + + if (timestamp != NULL) { + if (pid == NULL || timestamp < pid) { + first = timestamp_string; + first_pos = timestamp - file_name; + first_replace_len = strlen(TimestampFilenamePlaceholder); + } else { + second = timestamp_string; + second_pos = timestamp - file_name; + second_replace_len = strlen(TimestampFilenamePlaceholder); + } + } + + size_t first_len = strlen(first); + size_t second_len = strlen(second); + + // Allocate the new buffer, size it to hold all we want to put in there +1. + size_t result_len = strlen(file_name) + first_len - first_replace_len + second_len - second_replace_len; + result = NEW_C_HEAP_ARRAY(char, result_len + 1, mtLogging); + + // Assemble the strings + size_t file_name_pos = 0; + size_t i = 0; + while (i < result_len) { + if (file_name_pos == first_pos) { + // We are in the range of the first placeholder + strcpy(result + i, first); + // Bump output buffer position with length of replacing string + i += first_len; + // Bump source buffer position to skip placeholder + file_name_pos += first_replace_len; + } else if (file_name_pos == second_pos) { + // We are in the range of the second placeholder + strcpy(result + i, second); + i += second_len; + file_name_pos += second_replace_len; + } else { + // Else, copy char by char of the original file + result[i] = file_name[file_name_pos++]; + i++; + } + } + // Add terminating char + result[result_len] = '\0'; + return result; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logFileOutput.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logFileOutput.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP +#define SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP + +#include "logging/logFileStreamOutput.hpp" +#include "runtime/mutex.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogDecorations; + +// The log file output, with support for file rotation based on a target size. +class LogFileOutput : public LogFileStreamOutput { + private: + static const char* FileOpenMode; + static const char* FileCountOptionKey; + static const char* FileSizeOptionKey; + static const char* PidFilenamePlaceholder; + static const char* TimestampFilenamePlaceholder; + static const char* TimestampFormat; + static const size_t StartTimeBufferSize = 20; + static const size_t PidBufferSize = 21; + static char _pid_str[PidBufferSize]; + static char _vm_start_time_str[StartTimeBufferSize]; + + Mutex _rotation_lock; + const char* _name; + char* _file_name; + char* _archive_name; + + uint _current_file; + uint _file_count; + uint _file_count_max_digits; + + size_t _archive_name_len; + size_t _rotate_size; + size_t _current_size; + + void archive(); + void rotate(); + bool configure_rotation(const char* options); + char *make_file_name(const char* file_name, const char* pid_string, const char* timestamp_string); + static size_t parse_value(const char* value_str); + + bool should_rotate() const { + return _file_count > 0 && _rotate_size > 0 && _current_size >= _rotate_size; + } + + public: + LogFileOutput(const char *name); + virtual ~LogFileOutput(); + virtual bool initialize(const char* options); + virtual int write(const LogDecorations& decorations, const char* msg); + + virtual const char* name() const { + return _name; + } + + static void set_file_name_parameters(jlong start_time); +}; + +#endif // SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logFileStreamOutput.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logFileStreamOutput.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logDecorators.hpp" +#include "logging/logDecorations.hpp" +#include "logging/logFileStreamOutput.hpp" +#include "memory/allocation.inline.hpp" + +LogStdoutOutput LogStdoutOutput::_instance; +LogStderrOutput LogStderrOutput::_instance; + +int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) { + char decoration_buf[LogDecorations::DecorationsBufferSize]; + char* position = decoration_buf; + int total_written = 0; + + for (uint i = 0; i < LogDecorators::Count; i++) { + LogDecorators::Decorator decorator = static_cast(i); + if (!_decorators.is_decorator(decorator)) { + continue; + } + int written = jio_snprintf(position, sizeof(decoration_buf) - total_written, "[%-*s]", + _decorator_padding[decorator], + decorations.decoration(decorator)); + if (written <= 0) { + return -1; + } else if (static_cast(written - 2) > _decorator_padding[decorator]) { + _decorator_padding[decorator] = written - 2; + } + position += written; + total_written += written; + } + + if (total_written == 0) { + total_written = jio_fprintf(_stream, "%s\n", msg); + } else { + total_written = jio_fprintf(_stream, "%s %s\n", decoration_buf, msg); + } + fflush(_stream); + return total_written; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logFileStreamOutput.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logFileStreamOutput.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP +#define SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP + +#include "logging/logDecorators.hpp" +#include "logging/logOutput.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogDecorations; + +// Base class for all FileStream-based log outputs. +class LogFileStreamOutput : public LogOutput { + protected: + FILE* _stream; + size_t _decorator_padding[LogDecorators::Count]; + + LogFileStreamOutput(FILE *stream) : _stream(stream) { + for (size_t i = 0; i < LogDecorators::Count; i++) { + _decorator_padding[i] = 0; + } + _decorator_padding[LogDecorators::level_decorator] = 7; + } + + public: + virtual int write(const LogDecorations &decorations, const char* msg); +}; + +class LogStdoutOutput : public LogFileStreamOutput { + friend class LogOutput; + private: + static LogStdoutOutput _instance; + LogStdoutOutput() : LogFileStreamOutput(stdout) { + set_config_string("all=off"); + } + virtual bool initialize(const char* options) { + return false; + } + public: + virtual const char* name() const { + return "stdout"; + } +}; + +class LogStderrOutput : public LogFileStreamOutput { + friend class LogOutput; + private: + static LogStderrOutput _instance; + LogStderrOutput() : LogFileStreamOutput(stderr) { + set_config_string("all=warning"); + } + virtual bool initialize(const char* options) { + return false; + } + public: + virtual const char* name() const { + return "stderr"; + } +}; + +#endif // SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logLevel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logLevel.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logLevel.hpp" +#include "utilities/globalDefinitions.hpp" + +const char* LogLevel::_name[] = { + "off", +#define LOG_LEVEL(name, printname) #printname, + LOG_LEVEL_LIST +#undef LOG_LEVEL +}; + +LogLevelType LogLevel::from_string(const char* str) { + for (uint i = 0; i < Count; i++) { + if (strcasecmp(str, _name[i]) == 0) { + return static_cast(i); + } + } + return Invalid; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logLevel.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logLevel.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGLEVEL_HPP +#define SHARE_VM_LOGGING_LOGLEVEL_HPP + +#include "memory/allocation.hpp" +#include "utilities/macros.hpp" + +// The list of log levels: +// +// develop - A non-product level that is finer than trace. +// Should be used for really expensive and/or +// extensive logging, or logging that shouldn't +// or can't be included in a product build. +// +// trace - Finest level of logging in product builds. +// Use for extensive/noisy logging that can +// give slow-down when enabled. +// +// debug - A finer level of logging. Use for semi-noisy +// logging that is does not fit the info level. +// +// info - General level of logging. Use for significant +// events and/or informative summaries. +// +// warning - Important messages that are not strictly errors. +// +// error - Critical messages caused by errors. +// +#define LOG_LEVEL_LIST \ + NOT_PRODUCT(LOG_LEVEL(Develop, develop)) \ + LOG_LEVEL(Trace, trace) \ + LOG_LEVEL(Debug, debug) \ + LOG_LEVEL(Info, info) \ + LOG_LEVEL(Warning, warning) \ + LOG_LEVEL(Error, error) + +class LogLevel : public AllStatic { + public: + enum type { + Off, +#define LOG_LEVEL(name, printname) name, + LOG_LEVEL_LIST +#undef LOG_LEVEL + Count, + Invalid, + First = Off + 1, + Last = Error, + Default = Warning, + Unspecified = Info + }; + + static const char *name(LogLevel::type level) { + return _name[level]; + } + + static LogLevel::type from_string(const char* str); + + private: + static const char* _name[]; +}; + +typedef LogLevel::type LogLevelType; + +#endif // SHARE_VM_LOGGING_LOGLEVEL_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logOutput.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logOutput.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logFileStreamOutput.hpp" +#include "logging/logOutput.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/os.inline.hpp" + +LogOutput* const LogOutput::Stdout = &LogStdoutOutput::_instance; +LogOutput* const LogOutput::Stderr = &LogStderrOutput::_instance; + +LogOutput::~LogOutput() { + os::free(_config_string); +} + +void LogOutput::set_config_string(const char* string) { + os::free(_config_string); + _config_string = os::strdup_check_oom(string, mtLogging); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logOutput.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logOutput.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGOUTPUT_HPP +#define SHARE_VM_LOGGING_LOGOUTPUT_HPP + +#include "logging/logDecorators.hpp" +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogDecorations; + +// The base class/interface for log outputs. +// Keeps track of the latest configuration string, +// and its selected decorators. +class LogOutput : public CHeapObj { + protected: + LogDecorators _decorators; + char* _config_string; + + public: + static LogOutput* const Stdout; + static LogOutput* const Stderr; + + void set_decorators(const LogDecorators &decorators) { + _decorators = decorators; + } + + const LogDecorators& decorators() const { + return _decorators; + } + + const char* config_string() const { + return _config_string; + } + + LogOutput() : _config_string(NULL) { + } + + virtual ~LogOutput(); + void set_config_string(const char* string); + + virtual const char* name() const = 0; + virtual bool initialize(const char* options) = 0; + virtual int write(const LogDecorations &decorations, const char* msg) = 0; +}; + +#endif // SHARE_VM_LOGGING_LOGOUTPUT_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logOutputList.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logOutputList.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logLevel.hpp" +#include "logging/logOutputList.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/atomic.inline.hpp" +#include "runtime/orderAccess.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +jint LogOutputList::increase_readers() { + jint result = Atomic::add(1, &_active_readers); + assert(_active_readers > 0, "Ensure we have consistent state"); + return result; +} + +jint LogOutputList::decrease_readers() { + jint result = Atomic::add(-1, &_active_readers); + assert(result >= 0, "Ensure we have consistent state"); + return result; +} + +void LogOutputList::wait_until_no_readers() const { + OrderAccess::storeload(); + while (_active_readers != 0) { + // Busy wait + } +} + +void LogOutputList::set_output_level(LogOutput* output, LogLevelType level) { + LogOutputNode* node = find(output); + if (level == LogLevel::Off && node != NULL) { + remove_output(node); + } else if (level != LogLevel::Off && node == NULL) { + add_output(output, level); + } else if (node != NULL) { + update_output_level(node, level); + } +} + +LogOutputList::LogOutputNode* LogOutputList::find(LogOutput* output) { + for (LogOutputNode* node = _level_start[LogLevel::Last]; node != NULL; node = node->_next) { + if (output == node->_value) { + return node; + } + } + return NULL; +} + +void LogOutputList::remove_output(LogOutputList::LogOutputNode* node) { + assert(node != NULL, "Node must be non-null"); + + // Remove node from _level_start first + bool found = false; + for (uint level = LogLevel::First; level < LogLevel::Count; level++) { + if (_level_start[level] == node) { + found = true; + _level_start[level] = node->_next; + } + } + + // Now remove it from the linked list + for (LogOutputNode* cur = _level_start[LogLevel::Last]; cur != NULL; cur = cur->_next) { + if (cur->_next == node) { + found = true; + cur->_next = node->_next; + break; + } + } + assert(found, "Node to be removed should always be found"); + + wait_until_no_readers(); + delete node; +} + +void LogOutputList::add_output(LogOutput* output, LogLevelType level) { + LogOutputNode* node = new LogOutputNode(); + node->_value = output; + node->_level = level; + + // Set the next pointer to the first node of a lower level + for (node->_next = _level_start[level]; + node->_next != NULL && node->_next->_level == level; + node->_next = node->_next->_next) { + } + + // Update the _level_start index + for (int l = LogLevel::Last; l >= level; l--) { + if (_level_start[l] == NULL || _level_start[l]->_level < level) { + _level_start[l] = node; + } + } + + // Add the node the list + for (LogOutputNode* cur = _level_start[LogLevel::Last]; cur != NULL; cur = cur->_next) { + if (cur != node && cur->_next == node->_next) { + cur->_next = node; + break; + } + } +} + +void LogOutputList::update_output_level(LogOutputList::LogOutputNode* node, LogLevelType level) { + add_output(node->_value, level); + wait_until_no_readers(); + remove_output(node); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logOutputList.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logOutputList.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP +#define SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP + +#include "logging/logLevel.hpp" +#include "memory/allocation.hpp" +#include "runtime/atomic.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogOutput; + +// Data structure to keep track of log outputs for a given tagset. +// Essentially a sorted linked list going from error level outputs +// to outputs of finer levels. Keeps an index from each level to +// the first node in the list for the corresponding level. +// This allows a log message on, for example, info level to jump +// straight into the list where the first info level output can +// be found. The log message will then be printed on that output, +// as well as all outputs in nodes that follow in the list (which +// can be additional info level outputs and/or debug and trace outputs). +// +// Each instance keeps track of the number of current readers of the list. +// To remove a node from the list the node must first be unlinked, +// and the memory for that node can be freed whenever the removing +// thread observes an active reader count of 0 (after unlinking it). +class LogOutputList VALUE_OBJ_CLASS_SPEC { + private: + struct LogOutputNode : public CHeapObj { + LogOutput* _value; + LogOutputNode* _next; + LogLevelType _level; + }; + + LogOutputNode* _level_start[LogLevel::Count]; + volatile jint _active_readers; + + LogOutputNode* find(LogOutput* output); + void remove_output(LogOutputNode* node); + void add_output(LogOutput* output, LogLevelType level); + void update_output_level(LogOutputNode* node, LogLevelType level); + + public: + LogOutputList() : _active_readers(0) { + for (size_t i = 0; i < LogLevel::Count; i++) { + _level_start[i] = NULL; + } + } + + // Test if the outputlist has an output for the given level. + bool is_level(LogLevelType level) { + return _level_start[level] != NULL; + } + + // Set (add/update/remove) the output to the specified level. + void set_output_level(LogOutput* output, LogLevelType level); + + // Bookkeeping functions to keep track of number of active readers/iterators for the list. + jint increase_readers(); + jint decrease_readers(); + void wait_until_no_readers() const; + + class Iterator VALUE_OBJ_CLASS_SPEC { + friend class LogOutputList; + private: + LogOutputNode* _current; + LogOutputList* _list; + Iterator(LogOutputList* list, LogOutputNode* start) : _current(start), _list(list) { + } + + public: + ~Iterator() { + _list->decrease_readers(); + } + + LogOutput* operator*() { + return _current->_value; + } + + void operator++(int) { + _current = _current->_next; + } + + bool operator!=(const LogOutputNode *ref) const { + return _current != ref; + } + }; + + Iterator iterator(LogLevelType level = LogLevel::Last) { + increase_readers(); + return Iterator(this, _level_start[level]); + } + + LogOutputNode* end() const { + return NULL; + } +}; + +#endif // SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logPrefix.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logPrefix.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGPREFIX_HPP +#define SHARE_VM_LOGGING_LOGPREFIX_HPP + +#include "gc/shared/gcId.hpp" +#include "logging/logTag.hpp" + +// Prefixes prepend each log message for a specified tagset with the given prefix. +// A prefix consists of a format string and a value or callback. Prefixes are added +// after the decorations but before the log message. +// +// List of prefixes for specific tags and/or tagsets. +// Syntax: LOG_PREFIX(, , LOG_TAGS()) +#define LOG_PREFIX_LIST // Currently unused/empty + +// The empty prefix, used when there's no prefix defined. +template +struct LogPrefix : public AllStatic { + STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); + static size_t prefix(char* buf, size_t len) { + return 0; + } +}; + +#define LOG_PREFIX(fmt, fn, ...) \ +template <> struct LogPrefix<__VA_ARGS__> { \ + static size_t prefix(char* buf, size_t len) { \ + int ret = jio_snprintf(buf, len, fmt, fn); \ + assert(ret >= 0, \ + "Failed to prefix log message using prefix ('%s', '%s'), log buffer too small?", fmt, #fn); \ + return ret; \ + } \ +}; +LOG_PREFIX_LIST +#undef LOG_PREFIX + +#endif // SHARE_VM_LOGGING_LOGPREFIX_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logTag.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logTag.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logTag.hpp" +#include "utilities/globalDefinitions.hpp" + +const char* LogTag::_name[] = { + "", // __NO_TAG +#define LOG_TAG(name) #name, + LOG_TAG_LIST +#undef LOG_TAG +}; + +LogTagType LogTag::from_string(const char* str) { + for (uint i = 0; i < LogTag::Count; i++) { + if (strcasecmp(str, _name[i]) == 0) { + return static_cast(i); + } + } + return __NO_TAG; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logTag.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logTag.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGTAG_HPP +#define SHARE_VM_LOGGING_LOGTAG_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" + +// List of available logging tags. New tags should be added here. +// (The tags 'all', 'disable' and 'help' are special tags that can +// not be used in log calls, and should not be listed below.) +#define LOG_TAG_LIST \ + LOG_TAG(logging) + +#define PREFIX_LOG_TAG(T) (LogTag::T) + +// Expand a set of log tags to their prefixed names. +// For error detection purposes, the macro passes one more tag than what is supported. +// If too many tags are given, a static assert in the log class will fail. +#define LOG_TAGS_EXPANDED(T0, T1, T2, T3, T4, T5, ...) PREFIX_LOG_TAG(T0), PREFIX_LOG_TAG(T1), PREFIX_LOG_TAG(T2), \ + PREFIX_LOG_TAG(T3), PREFIX_LOG_TAG(T4), PREFIX_LOG_TAG(T5) +// The EXPAND_VARARGS macro is required for MSVC, or it will resolve the LOG_TAGS_EXPANDED macro incorrectly. +#define EXPAND_VARARGS(x) x +#define LOG_TAGS(...) EXPAND_VARARGS(LOG_TAGS_EXPANDED(__VA_ARGS__, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG)) + +// Log tags are used to classify log messages. +// Each log message can be assigned between 1 to LogTag::MaxTags number of tags. +// Specifying multiple tags for a log message means that only outputs configured +// for those exact tags, or a subset of the tags with a wildcard, will see the logging. +// Multiple tags should be comma separated, e.g. log_error(tag1, tag2)("msg"). +class LogTag : public AllStatic { + public: + // The maximum number of tags that a single log message can have. + // E.g. there might be hundreds of different tags available, + // but a specific log message can only be tagged with up to MaxTags of those. + static const size_t MaxTags = 5; + + enum type { + __NO_TAG, +#define LOG_TAG(name) name, + LOG_TAG_LIST +#undef LOG_TAG + Count + }; + + static const char* name(LogTag::type tag) { + return _name[tag]; + } + + static LogTag::type from_string(const char *str); + + private: + static const char* _name[]; +}; + +typedef LogTag::type LogTagType; + +#endif // SHARE_VM_LOGGING_LOGTAG_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logTagLevelExpression.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logTagLevelExpression.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logTagLevelExpression.hpp" +#include "logging/logTagSet.hpp" +#include "runtime/arguments.hpp" +#include "runtime/os.inline.hpp" + +const char* LogTagLevelExpression::DefaultExpressionString = "all"; + +LogTagLevelExpression::~LogTagLevelExpression() { + os::free(_string); +} + +void LogTagLevelExpression::clear() { + _ntags = 0; + _ncombinations = 0; + for (size_t combination = 0; combination < MaxCombinations; combination++) { + _level[combination] = LogLevel::Invalid; + _allow_other_tags[combination] = false; + for (size_t tag = 0; tag < LogTag::MaxTags; tag++) { + _tags[combination][tag] = LogTag::__NO_TAG; + } + } + os::free(_string); + _string = NULL; +} + +bool LogTagLevelExpression::parse(const char* str, outputStream* errstream) { + bool success = true; + clear(); + if (str == NULL || strcmp(str, "") == 0) { + str = DefaultExpressionString; + } + char* copy = os::strdup_check_oom(str, mtLogging); + // Split string on commas + for (char *comma_pos = copy, *cur = copy; success && comma_pos != NULL; cur = comma_pos + 1) { + if (_ncombinations == MaxCombinations) { + if (errstream != NULL) { + errstream->print_cr("Can not have more than " SIZE_FORMAT " tag combinations in a what-expression.", + MaxCombinations); + } + success = false; + break; + } + + comma_pos = strchr(cur, ','); + if (comma_pos != NULL) { + *comma_pos = '\0'; + } + + // Parse the level, if specified + LogLevelType level = LogLevel::Unspecified; + char* equals = strchr(cur, '='); + if (equals != NULL) { + level = LogLevel::from_string(equals + 1); + if (level == LogLevel::Invalid) { + if (errstream != NULL) { + errstream->print_cr("Invalid level '%s' in what-expression.", equals + 1); + } + success = false; + break; + } + *equals = '\0'; // now ignore "=level" part of substr + } + set_level(level); + + // Parse special tags such as 'all' + if (strcmp(cur, "all") == 0) { + set_allow_other_tags(); + new_combination(); + continue; + } + + // Check for '*' suffix + char* asterisk_pos = strchr(cur, '*'); + if (asterisk_pos != NULL && asterisk_pos[1] == '\0') { + set_allow_other_tags(); + *asterisk_pos = '\0'; + } + + // Parse the tag expression (t1+t2+...+tn) + char* plus_pos; + char* cur_tag = cur; + do { + plus_pos = strchr(cur_tag, '+'); + if (plus_pos != NULL) { + *plus_pos = '\0'; + } + LogTagType tag = LogTag::from_string(cur_tag); + if (tag == LogTag::__NO_TAG) { + if (errstream != NULL) { + errstream->print_cr("Invalid tag '%s' in what-expression.", cur_tag); + } + success = false; + break; + } + if (_ntags == LogTag::MaxTags) { + if (errstream != NULL) { + errstream->print_cr("Tag combination exceeds the maximum of " SIZE_FORMAT " tags.", + LogTag::MaxTags); + } + success = false; + break; + } + add_tag(tag); + cur_tag = plus_pos + 1; + } while (plus_pos != NULL); + + new_combination(); + } + + // Save the (unmodified) string for printing purposes. + _string = copy; + strcpy(_string, str); + + return success; +} + +LogLevelType LogTagLevelExpression::level_for(const LogTagSet& ts) const { + LogLevelType level = LogLevel::Off; + for (size_t combination = 0; combination < _ncombinations; combination++) { + bool contains_all = true; + size_t tag_idx; + for (tag_idx = 0; tag_idx < LogTag::MaxTags && _tags[combination][tag_idx] != LogTag::__NO_TAG; tag_idx++) { + if (!ts.contains(_tags[combination][tag_idx])) { + contains_all = false; + break; + } + } + // All tags in the expression must be part of the tagset, + // and either the expression allows other tags (has a wildcard), + // or the number of tags in the expression and tagset must match. + if (contains_all && (_allow_other_tags[combination] || tag_idx == ts.ntags())) { + level = _level[combination]; + } + } + return level; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logTagLevelExpression.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logTagLevelExpression.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP +#define SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP + +#include "logging/logLevel.hpp" +#include "logging/logTag.hpp" +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +class LogTagSet; + +// Class used to temporary encode a 'what'-expression during log configuration. +// Consists of a combination of tags and levels, e.g. "tag1+tag2=level1,tag3*=level2". +class LogTagLevelExpression : public StackObj { + private: + static const size_t MaxCombinations = 32; + static const char* DefaultExpressionString; + + size_t _ntags, _ncombinations; + LogTagType _tags[MaxCombinations][LogTag::MaxTags]; + LogLevelType _level[MaxCombinations]; + bool _allow_other_tags[MaxCombinations]; + char* _string; + + void new_combination() { + _ncombinations++; + _ntags = 0; + } + + void add_tag(LogTagType tag) { + assert(_ntags < LogTag::MaxTags, "Can't have more tags than MaxTags!"); + _tags[_ncombinations][_ntags++] = tag; + } + + void set_level(LogLevelType level) { + _level[_ncombinations] = level; + } + + void set_allow_other_tags() { + _allow_other_tags[_ncombinations] = true; + } + + void clear(); + + public: + LogTagLevelExpression() : _ntags(0), _ncombinations(0), _string(NULL) { + } + + const char* to_string() const { + return _string; + } + + ~LogTagLevelExpression(); + bool parse(const char* str, outputStream* errstream = NULL); + LogLevelType level_for(const LogTagSet& ts) const; +}; + +#endif // SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logTagSet.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logTagSet.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" +#include "logging/logDecorations.hpp" +#include "logging/logLevel.hpp" +#include "logging/logOutput.hpp" +#include "logging/logTag.hpp" +#include "logging/logTagSet.hpp" + +LogTagSet* LogTagSet::_list = NULL; +size_t LogTagSet::_ntagsets = 0; + +// This constructor is called only during static initialization. +// See the declaration in logTagSet.hpp for more information. +LogTagSet::LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4) + : _next(_list) { + _tag[0] = t0; + _tag[1] = t1; + _tag[2] = t2; + _tag[3] = t3; + _tag[4] = t4; + for (_ntags = 0; _ntags < LogTag::MaxTags && _tag[_ntags] != LogTag::__NO_TAG; _ntags++) { + } + _list = this; + _ntagsets++; + + // Set the default output to warning and error level for all new tagsets. + _output_list.set_output_level(LogOutput::Stderr, LogLevel::Default); +} + +bool LogTagSet::is_level(LogLevelType level) { + return _output_list.is_level(level); +} + +void LogTagSet::update_decorators(const LogDecorators& decorator) { + LogDecorators new_decorators = decorator; + for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) { + new_decorators.combine_with((*it)->decorators()); + } + _decorators = new_decorators; +} + +bool LogTagSet::has_output(const LogOutput* output) { + for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) { + if (*it == output) { + return true; + } + } + return false; +} + +void LogTagSet::log(LogLevelType level, const char* msg) { + LogDecorations decorations(level, *this, _decorators); + for (LogOutputList::Iterator it = _output_list.iterator(level); it != _output_list.end(); it++) { + (*it)->write(decorations, msg); + } +} + +int LogTagSet::label(char* buf, size_t len) { + int tot_written = 0; + for (size_t i = 0; i < _ntags; i++) { + int written = jio_snprintf(buf + tot_written, len - tot_written, "%s%s", + (i == 0 ? "" : ","), + LogTag::name(_tag[i])); + if (written < 0) { + return -1; + } + tot_written += written; + } + return tot_written; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/logging/logTagSet.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/logging/logTagSet.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#ifndef SHARE_VM_LOGGING_LOGTAGSET_HPP +#define SHARE_VM_LOGGING_LOGTAGSET_HPP + +#include "logging/logDecorators.hpp" +#include "logging/logLevel.hpp" +#include "logging/logOutputList.hpp" +#include "logging/logTag.hpp" +#include "utilities/globalDefinitions.hpp" + +// The tagset represents a combination of tags that occur in a log call somewhere. +// Tagsets are created automatically by the LogTagSetMappings and should never be +// instantiated directly somewhere else. +class LogTagSet VALUE_OBJ_CLASS_SPEC { + private: + static LogTagSet* _list; + static size_t _ntagsets; + + LogTagSet* const _next; + size_t _ntags; + LogTagType _tag[LogTag::MaxTags]; + + LogOutputList _output_list; + LogDecorators _decorators; + + // Keep constructor private to prevent incorrect instantiations of this class. + // Only LogTagSetMappings can create/contain instances of this class. + // The constructor links all tagsets together in a global list of tagsets. + // This list is used during configuration to be able to update all tagsets + // and their configurations to reflect the new global log configuration. + LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4); + + template + friend class LogTagSetMapping; + + public: + static LogTagSet* first() { + return _list; + } + + LogTagSet* next() { + return _next; + } + + size_t ntags() const { + return _ntags; + } + + bool contains(LogTagType tag) const { + for (size_t i = 0; _tag[i] != LogTag::__NO_TAG; i++) { + if (tag == _tag[i]) { + return true; + } + } + return false; + } + + void set_output_level(LogOutput* output, LogLevelType level) { + _output_list.set_output_level(output, level); + } + + // Refresh the decorators for this tagset to contain the decorators for all + // of its current outputs combined with the given decorators. + void update_decorators(const LogDecorators& decorator); + + int label(char *buf, size_t len); + bool has_output(const LogOutput* output); + bool is_level(LogLevelType level); + void log(LogLevelType level, const char* msg); +}; + +template +class LogTagSetMapping : public AllStatic { +private: + static LogTagSet _tagset; + +public: + static LogTagSet& tagset() { + return _tagset; + } +}; + +// Instantiate the static field _tagset for all tagsets that are used for logging somewhere. +// (This must be done here rather than the .cpp file because it's a template.) +// Each combination of tags used as template arguments to the Log class somewhere (via macro or not) +// will instantiate the LogTagSetMapping template, which in turn creates the static field for that +// tagset. This _tagset contains the configuration for those tags. +template +LogTagSet LogTagSetMapping::_tagset(T0, T1, T2, T3, T4); + +#endif // SHARE_VM_LOGGING_LOGTAGSET_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/allocation.cpp --- a/hotspot/src/share/vm/memory/allocation.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/allocation.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -125,7 +125,7 @@ void ResourceObj::set_allocation_type(address res, allocation_type type) { // Set allocation type in the resource object uintptr_t allocation = (uintptr_t)res; - assert((allocation & allocation_mask) == 0, err_msg("address should be aligned to 4 bytes at least: " INTPTR_FORMAT, p2i(res))); + assert((allocation & allocation_mask) == 0, "address should be aligned to 4 bytes at least: " INTPTR_FORMAT, p2i(res)); assert(type <= allocation_mask, "incorrect allocation type"); ResourceObj* resobj = (ResourceObj *)res; resobj->_allocation_t[0] = ~(allocation + type); @@ -161,8 +161,8 @@ } else if (is_type_set()) { // Operator new() was called and type was set. assert(!allocated_on_stack(), - err_msg("not embedded or stack, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", - p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1])); + "not embedded or stack, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", + p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1]); } else { // Operator new() was not called. // Assume that it is embedded or stack object. @@ -175,8 +175,8 @@ // Used in ClassFileParser::parse_constant_pool_entries() for ClassFileStream. // Note: garbage may resembles valid value. assert(~(_allocation_t[0] | allocation_mask) != (uintptr_t)this || !is_type_set(), - err_msg("embedded or stack only, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", - p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1])); + "embedded or stack only, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", + p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1]); set_allocation_type((address)this, STACK_OR_EMBEDDED); _allocation_t[1] = 0; // Zap verification value } @@ -184,8 +184,8 @@ ResourceObj& ResourceObj::operator=(const ResourceObj& r) { // default copy assignment // Used in InlineTree::ok_to_inline() for WarmCallInfo. assert(allocated_on_stack(), - err_msg("copy only into local, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", - p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1])); + "copy only into local, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", + p2i(this), get_allocation_type(), _allocation_t[0], _allocation_t[1]); // Keep current _allocation_t value; return *this; } @@ -533,7 +533,7 @@ } void Arena::signal_out_of_memory(size_t sz, const char* whence) const { - vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, whence); + vm_exit_out_of_memory(sz, OOM_MALLOC_ERROR, "%s", whence); } // Grow a new Chunk diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/allocation.hpp --- a/hotspot/src/share/vm/memory/allocation.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/allocation.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -154,8 +154,9 @@ mtChunk = 0x0C, // chunk that holds content of arenas mtTest = 0x0D, // Test type for verifying NMT mtTracing = 0x0E, // memory used for Tracing - mtNone = 0x0F, // undefined - mt_number_of_types = 0x10 // number of memory types (mtDontTrack + mtLogging = 0x0F, // memory for logging + mtNone = 0x10, // undefined + mt_number_of_types = 0x11 // number of memory types (mtDontTrack // is not included as validate type) }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/binaryTreeDictionary.cpp --- a/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/binaryTreeDictionary.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -708,8 +708,8 @@ size_t size = fc->size(); assert((size >= min_size()), - err_msg(SIZE_FORMAT " is too small to be a TreeChunk " SIZE_FORMAT, - size, min_size())); + SIZE_FORMAT " is too small to be a TreeChunk " SIZE_FORMAT, + size, min_size()); if (FLSVerifyDictionary) { verify_tree(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/filemap.cpp --- a/hotspot/src/share/vm/memory/filemap.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/filemap.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -50,7 +50,6 @@ #define O_BINARY 0 // otherwise do nothing. #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC extern address JVM_FunctionAtStart(); extern address JVM_FunctionAtEnd(); @@ -443,8 +442,8 @@ if (_file_open) { guarantee(si->_file_offset == _file_offset, "file offset mismatch."); if (PrintSharedSpaces) { - tty->print_cr("Shared file region %d: 0x%6x bytes, addr " INTPTR_FORMAT - " file offset 0x%6x", region, size, base, _file_offset); + tty->print_cr("Shared file region %d: " SIZE_FORMAT_HEX_W(6) " bytes, addr " INTPTR_FORMAT + " file offset " SIZE_FORMAT_HEX_W(6), region, size, p2i(base), _file_offset); } } else { si->_file_offset = _file_offset; @@ -602,7 +601,8 @@ // other reserved memory (like the code cache). ReservedSpace rs(size, os::vm_allocation_granularity(), false, requested_addr); if (!rs.is_reserved()) { - fail_continue("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr); + fail_continue("Unable to reserve shared space at required address " + INTPTR_FORMAT, p2i(requested_addr)); return rs; } // the reserved virtual memory is for mapping class data sharing archive @@ -659,7 +659,7 @@ tty->print_cr("Shared string data from the CDS archive is being ignored. " "The current CompressedOops/CompressedClassPointers encoding differs from " "that archived due to heap size change. The archive was dumped using max heap " - "size %dM.", max_heap_size()/M); + "size " UINTX_FORMAT "M.", max_heap_size()/M); } } else { string_ranges = new MemRegion[MetaspaceShared::max_strings]; @@ -896,7 +896,7 @@ } if (_obj_alignment != ObjectAlignmentInBytes) { FileMapInfo::fail_continue("The shared archive file's ObjectAlignmentInBytes of %d" - " does not equal the current ObjectAlignmentInBytes of %d.", + " does not equal the current ObjectAlignmentInBytes of " INTX_FORMAT ".", _obj_alignment, ObjectAlignmentInBytes); return false; } @@ -951,7 +951,7 @@ char *base = _header->region_addr(i); gclog_or_tty->print(" %s " INTPTR_FORMAT "-" INTPTR_FORMAT, shared_region_name[i], - base, base + si->_used); + p2i(base), p2i(base + si->_used)); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/iterator.inline.hpp --- a/hotspot/src/share/vm/memory/iterator.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/iterator.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -58,7 +58,7 @@ if (!oopDesc::is_null(heap_oop)) { oop o = oopDesc::decode_heap_oop_not_null(heap_oop); assert(Universe::heap()->is_in_closed_subset(o), - err_msg("should be in closed *p " PTR_FORMAT " " PTR_FORMAT, p2i(p), p2i(o))); + "should be in closed *p " PTR_FORMAT " " PTR_FORMAT, p2i(p), p2i(o)); } } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/metaspace.cpp --- a/hotspot/src/share/vm/memory/metaspace.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/metaspace.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -189,7 +189,7 @@ assert(index == SpecializedIndex || \ index == SmallIndex || \ index == MediumIndex || \ - index == HumongousIndex, err_msg("Bad index: %d", (int) index)) + index == HumongousIndex, "Bad index: %d", (int) index) size_t num_free_chunks(ChunkIndex index) const { index_bounds_check(index); @@ -378,13 +378,13 @@ #define assert_is_ptr_aligned(ptr, alignment) \ assert(is_ptr_aligned(ptr, alignment), \ - err_msg(PTR_FORMAT " is not aligned to " \ - SIZE_FORMAT, p2i(ptr), alignment)) + PTR_FORMAT " is not aligned to " \ + SIZE_FORMAT, p2i(ptr), alignment) #define assert_is_size_aligned(size, alignment) \ assert(is_size_aligned(size, alignment), \ - err_msg(SIZE_FORMAT " is not aligned to " \ - SIZE_FORMAT, size, alignment)) + SIZE_FORMAT " is not aligned to " \ + SIZE_FORMAT, size, alignment) // Decide if large pages should be committed when the memory is reserved. @@ -801,8 +801,8 @@ #ifdef ASSERT void VirtualSpaceNode::verify_container_count() { assert(_container_count == container_count_slow(), - err_msg("Inconsistency in container_count _container_count " UINTX_FORMAT - " container_count_slow() " UINTX_FORMAT, _container_count, container_count_slow())); + "Inconsistency in container_count _container_count " UINTX_FORMAT + " container_count_slow() " UINTX_FORMAT, _container_count, container_count_slow()); } #endif @@ -965,12 +965,12 @@ (HeapWord*)(_rs.base() + _rs.size()))); assert(reserved()->start() == (HeapWord*) _rs.base(), - err_msg("Reserved start was not set properly " PTR_FORMAT - " != " PTR_FORMAT, p2i(reserved()->start()), p2i(_rs.base()))); + "Reserved start was not set properly " PTR_FORMAT + " != " PTR_FORMAT, p2i(reserved()->start()), p2i(_rs.base())); assert(reserved()->word_size() == _rs.size() / BytesPerWord, - err_msg("Reserved size was not set properly " SIZE_FORMAT - " != " SIZE_FORMAT, reserved()->word_size(), - _rs.size() / BytesPerWord)); + "Reserved size was not set properly " SIZE_FORMAT + " != " SIZE_FORMAT, reserved()->word_size(), + _rs.size() / BytesPerWord); } return result; @@ -1016,11 +1016,11 @@ _reserved_words = _reserved_words - v; } -#define assert_committed_below_limit() \ - assert(MetaspaceAux::committed_bytes() <= MaxMetaspaceSize, \ - err_msg("Too much committed memory. Committed: " SIZE_FORMAT \ - " limit (MaxMetaspaceSize): " SIZE_FORMAT, \ - MetaspaceAux::committed_bytes(), MaxMetaspaceSize)); +#define assert_committed_below_limit() \ + assert(MetaspaceAux::committed_bytes() <= MaxMetaspaceSize, \ + "Too much committed memory. Committed: " SIZE_FORMAT \ + " limit (MaxMetaspaceSize): " SIZE_FORMAT, \ + MetaspaceAux::committed_bytes(), MaxMetaspaceSize); void VirtualSpaceList::inc_committed_words(size_t v) { assert_lock_strong(SpaceManager::expand_lock()); @@ -1461,8 +1461,8 @@ size_t capacity_until_gc = capacity_until_GC(); assert(capacity_until_gc >= committed_bytes, - err_msg("capacity_until_gc: " SIZE_FORMAT " < committed_bytes: " SIZE_FORMAT, - capacity_until_gc, committed_bytes)); + "capacity_until_gc: " SIZE_FORMAT " < committed_bytes: " SIZE_FORMAT, + capacity_until_gc, committed_bytes); size_t left_until_max = MaxMetaspaceSize - committed_bytes; size_t left_until_GC = capacity_until_gc - committed_bytes; @@ -1543,8 +1543,8 @@ // No expansion, now see if we want to shrink // We would never want to shrink more than this assert(capacity_until_GC >= minimum_desired_capacity, - err_msg(SIZE_FORMAT " >= " SIZE_FORMAT, - capacity_until_GC, minimum_desired_capacity)); + SIZE_FORMAT " >= " SIZE_FORMAT, + capacity_until_GC, minimum_desired_capacity); size_t max_shrink_bytes = capacity_until_GC - minimum_desired_capacity; // Should shrinking be considered? @@ -1585,8 +1585,8 @@ shrink_bytes = align_size_down(shrink_bytes, Metaspace::commit_alignment()); assert(shrink_bytes <= max_shrink_bytes, - err_msg("invalid shrink size " SIZE_FORMAT " not <= " SIZE_FORMAT, - shrink_bytes, max_shrink_bytes)); + "invalid shrink size " SIZE_FORMAT " not <= " SIZE_FORMAT, + shrink_bytes, max_shrink_bytes); if (current_shrink_factor == 0) { _shrink_factor = 10; } else { @@ -1676,9 +1676,9 @@ void ChunkManager::locked_verify_free_chunks_total() { assert_lock_strong(SpaceManager::expand_lock()); assert(sum_free_chunks() == _free_chunks_total, - err_msg("_free_chunks_total " SIZE_FORMAT " is not the" - " same as sum " SIZE_FORMAT, _free_chunks_total, - sum_free_chunks())); + "_free_chunks_total " SIZE_FORMAT " is not the" + " same as sum " SIZE_FORMAT, _free_chunks_total, + sum_free_chunks()); } void ChunkManager::verify_free_chunks_total() { @@ -1690,9 +1690,9 @@ void ChunkManager::locked_verify_free_chunks_count() { assert_lock_strong(SpaceManager::expand_lock()); assert(sum_free_chunks_count() == _free_chunks_count, - err_msg("_free_chunks_count " SIZE_FORMAT " is not the" - " same as sum " SIZE_FORMAT, _free_chunks_count, - sum_free_chunks_count())); + "_free_chunks_count " SIZE_FORMAT " is not the" + " same as sum " SIZE_FORMAT, _free_chunks_count, + sum_free_chunks_count()); } void ChunkManager::verify_free_chunks_count() { @@ -1891,9 +1891,9 @@ break; } assert(*chunk_word_size != 0 && *class_chunk_word_size != 0, - err_msg("Initial chunks sizes bad: data " SIZE_FORMAT - " class " SIZE_FORMAT, - *chunk_word_size, *class_chunk_word_size)); + "Initial chunks sizes bad: data " SIZE_FORMAT + " class " SIZE_FORMAT, + *chunk_word_size, *class_chunk_word_size); } size_t SpaceManager::sum_free_in_chunks_in_use() const { @@ -2036,9 +2036,9 @@ assert(!SpaceManager::is_humongous(word_size) || chunk_word_size == if_humongous_sized_chunk, - err_msg("Size calculation is wrong, word_size " SIZE_FORMAT - " chunk_word_size " SIZE_FORMAT, - word_size, chunk_word_size)); + "Size calculation is wrong, word_size " SIZE_FORMAT + " chunk_word_size " SIZE_FORMAT, + word_size, chunk_word_size); if (TraceMetadataHumongousAllocation && SpaceManager::is_humongous(word_size)) { gclog_or_tty->print_cr("Metadata humongous allocation:"); @@ -2202,9 +2202,9 @@ SpaceManager::~SpaceManager() { // This call this->_lock which can't be done while holding expand_lock() assert(sum_capacity_in_chunks_in_use() == allocated_chunks_words(), - err_msg("sum_capacity_in_chunks_in_use() " SIZE_FORMAT - " allocated_chunks_words() " SIZE_FORMAT, - sum_capacity_in_chunks_in_use(), allocated_chunks_words())); + "sum_capacity_in_chunks_in_use() " SIZE_FORMAT + " allocated_chunks_words() " SIZE_FORMAT, + sum_capacity_in_chunks_in_use(), allocated_chunks_words()); MutexLockerEx fcl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); @@ -2275,9 +2275,9 @@ assert(humongous_chunks->word_size() == (size_t) align_size_up(humongous_chunks->word_size(), smallest_chunk_size()), - err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT - " granularity " SIZE_FORMAT, - humongous_chunks->word_size(), smallest_chunk_size())); + "Humongous chunk size is wrong: word size " SIZE_FORMAT + " granularity " SIZE_FORMAT, + humongous_chunks->word_size(), smallest_chunk_size()); Metachunk* next_humongous_chunks = humongous_chunks->next(); humongous_chunks->container()->dec_container_count(); chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks); @@ -2331,7 +2331,7 @@ size_t raw_word_size = get_raw_word_size(word_size); size_t min_size = TreeChunk >::min_size(); assert(raw_word_size >= min_size, - err_msg("Should not deallocate dark matter " SIZE_FORMAT "<" SIZE_FORMAT, word_size, min_size)); + "Should not deallocate dark matter " SIZE_FORMAT "<" SIZE_FORMAT, word_size, min_size); block_freelists()->return_block(p, raw_word_size); } @@ -2541,9 +2541,9 @@ assert(SafepointSynchronize::is_at_safepoint() || !Universe::is_fully_initialized(), "Verification can fail if the applications is running"); assert(allocated_blocks_words() == sum_used_in_chunks_in_use(), - err_msg("allocation total is not consistent " SIZE_FORMAT - " vs " SIZE_FORMAT, - allocated_blocks_words(), sum_used_in_chunks_in_use())); + "allocation total is not consistent " SIZE_FORMAT + " vs " SIZE_FORMAT, + allocated_blocks_words(), sum_used_in_chunks_in_use()); } #endif @@ -2616,9 +2616,9 @@ void MetaspaceAux::dec_capacity(Metaspace::MetadataType mdtype, size_t words) { assert_lock_strong(SpaceManager::expand_lock()); assert(words <= capacity_words(mdtype), - err_msg("About to decrement below 0: words " SIZE_FORMAT - " is greater than _capacity_words[%u] " SIZE_FORMAT, - words, mdtype, capacity_words(mdtype))); + "About to decrement below 0: words " SIZE_FORMAT + " is greater than _capacity_words[%u] " SIZE_FORMAT, + words, mdtype, capacity_words(mdtype)); _capacity_words[mdtype] -= words; } @@ -2630,9 +2630,9 @@ void MetaspaceAux::dec_used(Metaspace::MetadataType mdtype, size_t words) { assert(words <= used_words(mdtype), - err_msg("About to decrement below 0: words " SIZE_FORMAT - " is greater than _used_words[%u] " SIZE_FORMAT, - words, mdtype, used_words(mdtype))); + "About to decrement below 0: words " SIZE_FORMAT + " is greater than _used_words[%u] " SIZE_FORMAT, + words, mdtype, used_words(mdtype)); // For CMS deallocation of the Metaspaces occurs during the // sweep which is a concurrent phase. Protection by the expand_lock() // is not enough since allocation is on a per Metaspace basis @@ -2699,11 +2699,11 @@ size_t class_capacity = capacity_bytes_slow(Metaspace::ClassType); size_t non_class_capacity = capacity_bytes_slow(Metaspace::NonClassType); assert(capacity_bytes() == class_capacity + non_class_capacity, - err_msg("bad accounting: capacity_bytes() " SIZE_FORMAT - " class_capacity + non_class_capacity " SIZE_FORMAT - " class_capacity " SIZE_FORMAT " non_class_capacity " SIZE_FORMAT, - capacity_bytes(), class_capacity + non_class_capacity, - class_capacity, non_class_capacity)); + "bad accounting: capacity_bytes() " SIZE_FORMAT + " class_capacity + non_class_capacity " SIZE_FORMAT + " class_capacity " SIZE_FORMAT " non_class_capacity " SIZE_FORMAT, + capacity_bytes(), class_capacity + non_class_capacity, + class_capacity, non_class_capacity); return class_capacity + non_class_capacity; } @@ -2904,17 +2904,17 @@ // For purposes of the running sum of capacity, verify against capacity size_t capacity_in_use_bytes = capacity_bytes_slow(); assert(running_sum_capacity_bytes == capacity_in_use_bytes, - err_msg("capacity_words() * BytesPerWord " SIZE_FORMAT - " capacity_bytes_slow()" SIZE_FORMAT, - running_sum_capacity_bytes, capacity_in_use_bytes)); + "capacity_words() * BytesPerWord " SIZE_FORMAT + " capacity_bytes_slow()" SIZE_FORMAT, + running_sum_capacity_bytes, capacity_in_use_bytes); for (Metaspace::MetadataType i = Metaspace::ClassType; i < Metaspace:: MetadataTypeCount; i = (Metaspace::MetadataType)(i + 1)) { size_t capacity_in_use_bytes = capacity_bytes_slow(i); assert(capacity_bytes(i) == capacity_in_use_bytes, - err_msg("capacity_bytes(%u) " SIZE_FORMAT - " capacity_bytes_slow(%u)" SIZE_FORMAT, - i, capacity_bytes(i), i, capacity_in_use_bytes)); + "capacity_bytes(%u) " SIZE_FORMAT + " capacity_bytes_slow(%u)" SIZE_FORMAT, + i, capacity_bytes(i), i, capacity_in_use_bytes); } #endif } @@ -2925,17 +2925,17 @@ // For purposes of the running sum of used, verify against used size_t used_in_use_bytes = used_bytes_slow(); assert(used_bytes() == used_in_use_bytes, - err_msg("used_bytes() " SIZE_FORMAT - " used_bytes_slow()" SIZE_FORMAT, - used_bytes(), used_in_use_bytes)); + "used_bytes() " SIZE_FORMAT + " used_bytes_slow()" SIZE_FORMAT, + used_bytes(), used_in_use_bytes); for (Metaspace::MetadataType i = Metaspace::ClassType; i < Metaspace:: MetadataTypeCount; i = (Metaspace::MetadataType)(i + 1)) { size_t used_in_use_bytes = used_bytes_slow(i); assert(used_bytes(i) == used_in_use_bytes, - err_msg("used_bytes(%u) " SIZE_FORMAT - " used_bytes_slow(%u)" SIZE_FORMAT, - i, used_bytes(i), i, used_in_use_bytes)); + "used_bytes(%u) " SIZE_FORMAT + " used_bytes_slow(%u)" SIZE_FORMAT, + i, used_bytes(i), i, used_in_use_bytes); } #endif } @@ -3157,7 +3157,7 @@ void Metaspace::initialize_class_space(ReservedSpace rs) { // The reserved space size may be bigger because of alignment, esp with UseLargePages assert(rs.size() >= CompressedClassSpaceSize, - err_msg(SIZE_FORMAT " != " SIZE_FORMAT, rs.size(), CompressedClassSpaceSize)); + SIZE_FORMAT " != " SIZE_FORMAT, rs.size(), CompressedClassSpaceSize); assert(using_class_space(), "Must be using class space"); _class_space_list = new VirtualSpaceList(rs); _chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk); @@ -3688,7 +3688,7 @@ case Metaspace::ClassType: return "Class"; case Metaspace::NonClassType: return "Metadata"; default: - assert(false, err_msg("Got bad mdtype: %d", (int) mdtype)); + assert(false, "Got bad mdtype: %d", (int) mdtype); return NULL; } } @@ -3970,15 +3970,15 @@ #define assert_is_available_positive(word_size) \ assert(vsn.is_available(word_size), \ - err_msg(#word_size ": " PTR_FORMAT " bytes were not available in " \ - "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \ - (uintptr_t)(word_size * BytesPerWord), p2i(vsn.bottom()), p2i(vsn.end()))); + #word_size ": " PTR_FORMAT " bytes were not available in " \ + "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \ + (uintptr_t)(word_size * BytesPerWord), p2i(vsn.bottom()), p2i(vsn.end())); #define assert_is_available_negative(word_size) \ assert(!vsn.is_available(word_size), \ - err_msg(#word_size ": " PTR_FORMAT " bytes should not be available in " \ - "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \ - (uintptr_t)(word_size * BytesPerWord), p2i(vsn.bottom()), p2i(vsn.end()))); + #word_size ": " PTR_FORMAT " bytes should not be available in " \ + "VirtualSpaceNode [" PTR_FORMAT ", " PTR_FORMAT ")", \ + (uintptr_t)(word_size * BytesPerWord), p2i(vsn.bottom()), p2i(vsn.end())); static void test_is_available_positive() { // Reserve some memory. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp --- a/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/metaspaceGCThresholdUpdater.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -43,7 +43,7 @@ case ExpandAndAllocate: return "expand_and_allocate"; default: - assert(false, err_msg("Got bad updater: %d", (int) updater)); + assert(false, "Got bad updater: %d", (int) updater); return NULL; }; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/metaspaceShared.cpp --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -44,8 +44,6 @@ #include "runtime/vm_operations.hpp" #include "utilities/hashtable.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - int MetaspaceShared::_max_alignment = 0; ReservedSpace* MetaspaceShared::_shared_rs = NULL; @@ -578,7 +576,7 @@ // Print shared spaces all the time // To make fmt_space be a syntactic constant (for format warnings), use #define. -#define fmt_space "%s space: %9d [ %4.1f%% of total] out of %9d bytes [%4.1f%% used] at " INTPTR_FORMAT +#define fmt_space "%s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%4.1f%% used] at " INTPTR_FORMAT Metaspace* ro_space = _loader_data->ro_metaspace(); Metaspace* rw_space = _loader_data->rw_metaspace(); @@ -611,12 +609,12 @@ const double mc_u_perc = mc_bytes / double(mc_alloced) * 100.0; const double total_u_perc = total_bytes / double(total_alloced) * 100.0; - tty->print_cr(fmt_space, "ro", ro_bytes, ro_t_perc, ro_alloced, ro_u_perc, ro_space->bottom()); - tty->print_cr(fmt_space, "rw", rw_bytes, rw_t_perc, rw_alloced, rw_u_perc, rw_space->bottom()); - tty->print_cr(fmt_space, "md", md_bytes, md_t_perc, md_alloced, md_u_perc, md_low); - tty->print_cr(fmt_space, "mc", mc_bytes, mc_t_perc, mc_alloced, mc_u_perc, mc_low); - tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes, 100.0, ss_low); - tty->print_cr("total : %9d [100.0%% of total] out of %9d bytes [%4.1f%% used]", + tty->print_cr(fmt_space, "ro", ro_bytes, ro_t_perc, ro_alloced, ro_u_perc, p2i(ro_space->bottom())); + tty->print_cr(fmt_space, "rw", rw_bytes, rw_t_perc, rw_alloced, rw_u_perc, p2i(rw_space->bottom())); + tty->print_cr(fmt_space, "md", md_bytes, md_t_perc, md_alloced, md_u_perc, p2i(md_low)); + tty->print_cr(fmt_space, "mc", mc_bytes, mc_t_perc, mc_alloced, mc_u_perc, p2i(mc_low)); + tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes, 100.0, p2i(ss_low)); + tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%4.1f%% used]", total_bytes, total_alloced, total_u_perc); // Update the vtable pointers in all of the Klass objects in the @@ -738,9 +736,9 @@ TraceTime timer("Dump Shared Spaces", TraceStartupTime); ResourceMark rm; - tty->print_cr("Allocated shared space: %d bytes at " PTR_FORMAT, + tty->print_cr("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT, MetaspaceShared::shared_rs()->size(), - MetaspaceShared::shared_rs()->base()); + p2i(MetaspaceShared::shared_rs()->base())); // Preload classes to be shared. // Should use some os:: method rather than fopen() here. aB. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/universe.cpp --- a/hotspot/src/share/vm/memory/universe.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/universe.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -143,6 +143,10 @@ // Heap int Universe::_verify_count = 0; +// Oop verification (see MacroAssembler::verify_oop) +uintptr_t Universe::_verify_oop_mask = 0; +uintptr_t Universe::_verify_oop_bits = (uintptr_t) -1; + int Universe::_base_vtable_size = 0; bool Universe::_bootstrapping = false; bool Universe::_fully_initialized = false; @@ -812,8 +816,8 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { assert(alignment <= Arguments::conservative_max_heap_alignment(), - err_msg("actual alignment " SIZE_FORMAT " must be within maximum heap alignment " SIZE_FORMAT, - alignment, Arguments::conservative_max_heap_alignment())); + "actual alignment " SIZE_FORMAT " must be within maximum heap alignment " SIZE_FORMAT, + alignment, Arguments::conservative_max_heap_alignment()); size_t total_reserved = align_size_up(heap_size, alignment); assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), @@ -1171,17 +1175,9 @@ _verify_in_progress = false; } -// Oop verification (see MacroAssembler::verify_oop) - -static uintptr_t _verify_oop_data[2] = {0, (uintptr_t)-1}; -static uintptr_t _verify_klass_data[2] = {0, (uintptr_t)-1}; - #ifndef PRODUCT - -static void calculate_verify_data(uintptr_t verify_data[2], - HeapWord* low_boundary, - HeapWord* high_boundary) { +void Universe::calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) { assert(low_boundary < high_boundary, "bad interval"); // decide which low-order bits we require to be clear: @@ -1206,28 +1202,25 @@ // require address alignment, too: mask |= (alignSize - 1); - if (!(verify_data[0] == 0 && verify_data[1] == (uintptr_t)-1)) { - assert(verify_data[0] == mask && verify_data[1] == bits, "mask stability"); + if (!(_verify_oop_mask == 0 && _verify_oop_bits == (uintptr_t)-1)) { + assert(_verify_oop_mask == mask && _verify_oop_bits == bits, "mask stability"); } - verify_data[0] = mask; - verify_data[1] = bits; + _verify_oop_mask = mask; + _verify_oop_bits = bits; } // Oop verification (see MacroAssembler::verify_oop) uintptr_t Universe::verify_oop_mask() { MemRegion m = heap()->reserved_region(); - calculate_verify_data(_verify_oop_data, - m.start(), - m.end()); - return _verify_oop_data[0]; + calculate_verify_data(m.start(), m.end()); + return _verify_oop_mask; } - - uintptr_t Universe::verify_oop_bits() { - verify_oop_mask(); - return _verify_oop_data[1]; + MemRegion m = heap()->reserved_region(); + calculate_verify_data(m.start(), m.end()); + return _verify_oop_bits; } uintptr_t Universe::verify_mark_mask() { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/universe.hpp --- a/hotspot/src/share/vm/memory/universe.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/universe.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -248,9 +248,14 @@ // Debugging static int _verify_count; // number of verifies done + // True during call to verify(). Should only be set/cleared in verify(). static bool _verify_in_progress; + static uintptr_t _verify_oop_mask; + static uintptr_t _verify_oop_bits; + + static void calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) PRODUCT_RETURN; static void compute_verify_oop_data(); public: @@ -269,7 +274,7 @@ } static Klass* typeArrayKlassObj(BasicType t) { - assert((uint)t < T_VOID+1, err_msg("range check for type: %s", type2name(t))); + assert((uint)t < T_VOID+1, "range check for type: %s", type2name(t)); assert(_typeArrayKlassObjs[t] != NULL, "domain check"); return _typeArrayKlassObjs[t]; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/memory/virtualspace.cpp --- a/hotspot/src/share/vm/memory/virtualspace.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/memory/virtualspace.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,8 +29,6 @@ #include "oops/oop.inline.hpp" #include "services/memTracker.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // ReservedSpace // Dummy constructor @@ -82,7 +80,7 @@ assert(UseCompressedOops, "currently requested address used only for compressed oops"); if (PrintCompressedOopsMode) { tty->cr(); - tty->print_cr("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, base, requested_address); + tty->print_cr("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, p2i(base), p2i(requested_address)); } // OS ignored requested address. Try different address. if (special) { @@ -137,9 +135,9 @@ } // Check alignment constraints. assert((uintptr_t) base % alignment == 0, - err_msg("Large pages returned a non-aligned address, base: " - PTR_FORMAT " alignment: " PTR_FORMAT, - base, (void*)(uintptr_t)alignment)); + "Large pages returned a non-aligned address, base: " + PTR_FORMAT " alignment: " SIZE_FORMAT_HEX, + p2i(base), alignment); _special = true; } else { // failed; try to reserve regular memory below @@ -291,7 +289,7 @@ if (PrintCompressedOopsMode) { tty->cr(); tty->print_cr("Protected page at the reserved heap base: " - PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix); + PTR_FORMAT " / " INTX_FORMAT " bytes", p2i(_base), _noaccess_prefix); } assert(Universe::narrow_oop_use_implicit_null_checks() == true, "not initialized?"); } else { @@ -324,8 +322,8 @@ char* base = NULL; if (PrintCompressedOopsMode && Verbose) { - tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " PTR_FORMAT ".\n", - requested_address, (address)size); + tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " SIZE_FORMAT_HEX ".\n", + p2i(requested_address), size); } if (special) { @@ -334,9 +332,9 @@ if (base != NULL) { // Check alignment constraints. assert((uintptr_t) base % alignment == 0, - err_msg("Large pages returned a non-aligned address, base: " - PTR_FORMAT " alignment: " PTR_FORMAT, - base, (void*)(uintptr_t)alignment)); + "Large pages returned a non-aligned address, base: " + PTR_FORMAT " alignment: " SIZE_FORMAT_HEX, + p2i(base), alignment); _special = true; } } @@ -561,7 +559,7 @@ // Last, desperate try without any placement. if (_base == NULL) { if (PrintCompressedOopsMode && Verbose) { - tty->print("Trying to allocate at address NULL heap of size " PTR_FORMAT ".\n", (address)size + noaccess_prefix); + tty->print("Trying to allocate at address NULL heap of size " SIZE_FORMAT_HEX ".\n", size + noaccess_prefix); } initialize(size + noaccess_prefix, alignment, large, NULL, false); } @@ -853,7 +851,7 @@ if (!os::commit_memory(lower_high(), lower_needs, _executable)) { debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT ", lower_needs=" SIZE_FORMAT ", %d) failed", - lower_high(), lower_needs, _executable);) + p2i(lower_high()), lower_needs, _executable);) return false; } else { _lower_high += lower_needs; @@ -867,7 +865,7 @@ _executable)) { debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT ", middle_needs=" SIZE_FORMAT ", " SIZE_FORMAT - ", %d) failed", middle_high(), middle_needs, + ", %d) failed", p2i(middle_high()), middle_needs, middle_alignment(), _executable);) return false; } @@ -880,7 +878,7 @@ if (!os::commit_memory(upper_high(), upper_needs, _executable)) { debug_only(warning("INFO: os::commit_memory(" PTR_FORMAT ", upper_needs=" SIZE_FORMAT ", %d) failed", - upper_high(), upper_needs, _executable);) + p2i(upper_high()), upper_needs, _executable);) return false; } else { _upper_high += upper_needs; @@ -1017,8 +1015,8 @@ out->cr(); out->print_cr(" - committed: " SIZE_FORMAT, committed_size()); out->print_cr(" - reserved: " SIZE_FORMAT, reserved_size()); - out->print_cr(" - [low, high]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low(), high()); - out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low_boundary(), high_boundary()); + out->print_cr(" - [low, high]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", p2i(low()), p2i(high())); + out->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", p2i(low_boundary()), p2i(high_boundary())); } void VirtualSpace::print() { @@ -1205,20 +1203,20 @@ TestReservedSpace::test_reserved_space(); } -#define assert_equals(actual, expected) \ - assert(actual == expected, \ - err_msg("Got " SIZE_FORMAT " expected " \ - SIZE_FORMAT, actual, expected)); +#define assert_equals(actual, expected) \ + assert(actual == expected, \ + "Got " SIZE_FORMAT " expected " \ + SIZE_FORMAT, actual, expected); #define assert_ge(value1, value2) \ assert(value1 >= value2, \ - err_msg("'" #value1 "': " SIZE_FORMAT " '" \ - #value2 "': " SIZE_FORMAT, value1, value2)); + "'" #value1 "': " SIZE_FORMAT " '" \ + #value2 "': " SIZE_FORMAT, value1, value2); #define assert_lt(value1, value2) \ assert(value1 < value2, \ - err_msg("'" #value1 "': " SIZE_FORMAT " '" \ - #value2 "': " SIZE_FORMAT, value1, value2)); + "'" #value1 "': " SIZE_FORMAT " '" \ + #value2 "': " SIZE_FORMAT, value1, value2); class TestVirtualSpace : AllStatic { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/constantPool.cpp --- a/hotspot/src/share/vm/oops/constantPool.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/constantPool.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -45,8 +45,6 @@ #include "runtime/vframe.hpp" #include "utilities/copy.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) { // Tags are RW but comment below applies to tags also. Array* tags = MetadataFactory::new_writeable_array(loader_data, length, 0, CHECK_NULL); @@ -1826,9 +1824,9 @@ // Ensure that all the patches have been used. for (int index = 0; index < cp_patches->length(); index++) { assert(cp_patches->at(index).is_null(), - err_msg("Unused constant pool patch at %d in class file %s", - index, - pool_holder()->external_name())); + "Unused constant pool patch at %d in class file %s", + index, + pool_holder()->external_name()); } #endif // ASSERT } @@ -1868,11 +1866,11 @@ st->cr(); } if (pool_holder() != NULL) { - st->print_cr(" - holder: " INTPTR_FORMAT, pool_holder()); + st->print_cr(" - holder: " INTPTR_FORMAT, p2i(pool_holder())); } - st->print_cr(" - cache: " INTPTR_FORMAT, cache()); - st->print_cr(" - resolved_references: " INTPTR_FORMAT, (void *)resolved_references()); - st->print_cr(" - reference_map: " INTPTR_FORMAT, reference_map()); + st->print_cr(" - cache: " INTPTR_FORMAT, p2i(cache())); + st->print_cr(" - resolved_references: " INTPTR_FORMAT, p2i(resolved_references())); + st->print_cr(" - reference_map: " INTPTR_FORMAT, p2i(reference_map())); for (int index = 1; index < length(); index++) { // Index 0 is unused ((ConstantPool*)this)->print_entry_on(index, st); @@ -1897,7 +1895,7 @@ { Klass* k = klass_at(index, CATCH); guarantee(k != NULL, "need klass"); k->print_value_on(st); - st->print(" {0x%lx}", (address)k); + st->print(" {" PTR_FORMAT "}", p2i(k)); } break; case JVM_CONSTANT_Fieldref : @@ -1910,7 +1908,7 @@ if (is_pseudo_string_at(index)) { oop anObj = pseudo_string_at(index); anObj->print_value_on(st); - st->print(" {0x%lx}", (address)anObj); + st->print(" {" PTR_FORMAT "}", p2i(anObj)); } else { unresolved_string_at(index)->print_value_on(st); } @@ -1987,7 +1985,7 @@ if (extra) st->print(" (extra)"); } if (cache() != NULL) { - st->print(" cache=" PTR_FORMAT, cache()); + st->print(" cache=" PTR_FORMAT, p2i(cache())); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/constantPool.hpp --- a/hotspot/src/share/vm/oops/constantPool.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/constantPool.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -662,6 +662,8 @@ int klass_ref_index_at(int which) { return impl_klass_ref_index_at(which, false); } int name_and_type_ref_index_at(int which) { return impl_name_and_type_ref_index_at(which, false); } + int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG + // Lookup for entries consisting of (name_index, signature_index) int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) @@ -783,8 +785,6 @@ int impl_klass_ref_index_at(int which, bool uncached); int impl_name_and_type_ref_index_at(int which, bool uncached); - int remap_instruction_operand_from_cache(int operand); // operand must be biased by CPCACHE_INDEX_TAG - // Used while constructing constant pool (only by ClassFileParser) jint klass_index_at(int which) { assert(tag_at(which).is_klass_index(), "Corrupted constant pool"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/cpCache.cpp --- a/hotspot/src/share/vm/oops/cpCache.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/cpCache.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,8 +36,6 @@ #include "runtime/orderAccess.inline.hpp" #include "utilities/macros.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of ConstantPoolCacheEntry void ConstantPoolCacheEntry::initialize_entry(int index) { @@ -126,7 +124,7 @@ // This routine is called only in corner cases where the CPCE is not yet initialized. // See AbstractInterpreter::deopt_continue_after_entry. assert(_flags == 0 || parameter_size() == 0 || parameter_size() == value, - err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value)); + "size must not change: parameter_size=%d, value=%d", parameter_size(), value); // Setting the parameter size by itself is only safe if the // current value of _flags is 0, otherwise another thread may have // updated it and we don't want to overwrite that value. Don't @@ -136,7 +134,7 @@ Atomic::cmpxchg_ptr((value & parameter_size_mask), &_flags, 0); } guarantee(parameter_size() == value, - err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value)); + "size must not change: parameter_size=%d, value=%d", parameter_size(), value); } void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_code, @@ -310,9 +308,9 @@ if (TraceInvokeDynamic) { tty->print_cr("set_method_handle bc=%d appendix=" PTR_FORMAT "%s method_type=" PTR_FORMAT "%s method=" PTR_FORMAT " ", invoke_code, - (void *)appendix(), (has_appendix ? "" : " (unused)"), - (void *)method_type(), (has_method_type ? "" : " (unused)"), - (intptr_t)adapter()); + p2i(appendix()), (has_appendix ? "" : " (unused)"), + p2i(method_type()), (has_method_type ? "" : " (unused)"), + p2i(adapter())); adapter->print(); if (has_appendix) appendix()->print(); } @@ -593,7 +591,7 @@ // all point to the same constant pool cache entry. for (int entry = 1; entry < ConstantPoolCacheEntry::_indy_resolved_references_entries; entry++) { const int cpci_next = invokedynamic_references_map[ref + entry]; - assert(cpci == cpci_next, err_msg_res("%d == %d", cpci, cpci_next)); + assert(cpci == cpci_next, "%d == %d", cpci, cpci_next); } #endif entry_at(cpci)->initialize_resolved_reference_index(ref); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp --- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,11 +41,10 @@ // Constructor InstanceClassLoaderKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous) - : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous) {} + : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, + InstanceKlass::_misc_kind_class_loader, rt, access_flags, is_anonymous) {} public: - virtual bool oop_is_instanceClassLoader() const { return true; } - InstanceClassLoaderKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } // GC specific object visitors diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -66,8 +66,6 @@ #include "c1/c1_Compiler.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef DTRACE_ENABLED @@ -147,8 +145,8 @@ } else { // normal class ik = new (loader_data, size, THREAD) InstanceKlass( - vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, - access_flags, is_anonymous); + vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, + InstanceKlass::_misc_kind_other, rt, access_flags, is_anonymous); } } else { // reference klass @@ -197,6 +195,7 @@ int itable_len, int static_field_size, int nonstatic_oop_map_size, + unsigned kind, ReferenceType rt, AccessFlags access_flags, bool is_anonymous) { @@ -211,6 +210,7 @@ set_nonstatic_oop_map_size(nonstatic_oop_map_size); set_access_flags(access_flags); _misc_flags = 0; // initialize to zero + set_kind(kind); set_is_anonymous(is_anonymous); assert(size() == iksize, "wrong size for object"); @@ -1028,7 +1028,7 @@ if (TraceFinalizerRegistration) { tty->print("Registered "); i->print_value_on(tty); - tty->print_cr(" (" INTPTR_FORMAT ") as finalizable", (address)i); + tty->print_cr(" (" INTPTR_FORMAT ") as finalizable", p2i(i)); } instanceHandle h_i(THREAD, i); // Pass the handle as argument, JavaCalls::call expects oop as jobjects @@ -1131,7 +1131,7 @@ if (TraceClassInitialization) { tty->print("%d Initializing ", call_class_initializer_impl_counter++); this_k->name()->print_value(); - tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", (address)this_k()); + tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", p2i(this_k())); } if (h_method() != NULL) { JavaCallArguments args; // No arguments @@ -1499,7 +1499,7 @@ // not found #ifdef ASSERT int index = (skipping_overpass || skipping_static || skipping_private) ? -1 : linear_search(methods, name, signature); - assert(index == -1, err_msg("binary search should have found entry %d", index)); + assert(index == -1, "binary search should have found entry %d", index); #endif } return -1; @@ -1915,7 +1915,7 @@ for (nmethodBucket* b = deps; b != NULL; b = b->next()) { if (nm == b->get_nmethod()) { int val = b->decrement(); - guarantee(val >= 0, err_msg("Underflow: %d", val)); + guarantee(val >= 0, "Underflow: %d", val); return (val == 0); } } @@ -1936,7 +1936,7 @@ nmethodBucket* b = first; while (b != NULL) { - assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); + assert(b->count() >= 0, "bucket count: %d", b->count()); nmethodBucket* next = b->next(); if (b->count() == 0) { if (last == NULL) { @@ -1976,7 +1976,7 @@ if (nm == b->get_nmethod()) { #ifdef ASSERT int count = b->count(); - assert(count >= 0, err_msg("count shouldn't be negative: %d", count)); + assert(count >= 0, "count shouldn't be negative: %d", count); #endif return true; } @@ -2001,7 +2001,7 @@ else { // Verification for (nmethodBucket* b = _dependencies; b != NULL; b = b->next()) { - assert(b->count() >= 0, err_msg("bucket count: %d", b->count())); + assert(b->count() >= 0, "bucket count: %d", b->count()); assert(b->count() != 0, "empty buckets need to be cleaned"); } } @@ -2797,7 +2797,7 @@ st->print(" "); } } - if (n >= MaxSubklassPrintSize) st->print("(%d more klasses...)", n - MaxSubklassPrintSize); + if (n >= MaxSubklassPrintSize) st->print("(" INTX_FORMAT " more klasses...)", n - MaxSubklassPrintSize); st->cr(); if (is_interface()) { @@ -2873,9 +2873,9 @@ } st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr(); st->print(BULLET"java mirror: "); java_mirror()->print_value_on(st); st->cr(); - st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", vtable_length(), start_of_vtable()); st->cr(); + st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", vtable_length(), p2i(start_of_vtable())); st->cr(); if (vtable_length() > 0 && (Verbose || WizardMode)) print_vtable(start_of_vtable(), vtable_length(), st); - st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", itable_length(), start_of_itable()); st->cr(); + st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", itable_length(), p2i(start_of_itable())); st->cr(); if (itable_length() > 0 && (Verbose || WizardMode)) print_vtable(start_of_itable(), itable_length(), st); st->print_cr(BULLET"---- static fields (%d words):", static_field_size()); FieldPrinter print_static_field(st); @@ -3068,7 +3068,7 @@ template void do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); if (!obj->is_oop_or_null()) { - tty->print_cr("Failed: " PTR_FORMAT " -> " PTR_FORMAT, p, (address)obj); + tty->print_cr("Failed: " PTR_FORMAT " -> " PTR_FORMAT, p2i(p), p2i(obj)); Universe::print(); guarantee(false, "boom"); } @@ -3110,7 +3110,7 @@ Klass* sib = next_sibling(); if (sib != NULL) { if (sib == this) { - fatal(err_msg("subclass points to itself " PTR_FORMAT, sib)); + fatal("subclass points to itself " PTR_FORMAT, p2i(sib)); } guarantee(sib->is_klass(), "should be klass"); @@ -3310,7 +3310,7 @@ // The previous version InstanceKlass is on the ClassLoaderData deallocate list // so will be deallocated during the next phase of class unloading. RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is dead", - pv_node)); + p2i(pv_node))); // For debugging purposes. pv_node->set_is_scratch_class(); pv_node->class_loader_data()->add_to_deallocate_list(pv_node); @@ -3321,7 +3321,7 @@ continue; } else { RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is alive", - pv_node)); + p2i(pv_node))); assert(pvcp->pool_holder() != NULL, "Constant pool with no holder"); guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack"); live_count++; @@ -3472,10 +3472,10 @@ // is never reached, but this won't be noticeable to the programmer. old_method->set_running_emcp(true); RC_TRACE(0x00000400, ("add: EMCP method %s is on_stack " INTPTR_FORMAT, - old_method->name_and_sig_as_C_string(), old_method)); + old_method->name_and_sig_as_C_string(), p2i(old_method))); } else if (!old_method->is_obsolete()) { RC_TRACE(0x00000400, ("add: EMCP method %s is NOT on_stack " INTPTR_FORMAT, - old_method->name_and_sig_as_C_string(), old_method)); + old_method->name_and_sig_as_C_string(), p2i(old_method))); } } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/instanceKlass.hpp --- a/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -117,6 +117,7 @@ int itable_len, int static_field_size, int nonstatic_oop_map_size, + unsigned kind, ReferenceType rt, AccessFlags access_flags, bool is_anonymous); @@ -199,16 +200,30 @@ bool _is_marked_dependent; // used for marking during flushing and deoptimization bool _has_unloaded_dependent; + // The low two bits of _misc_flags contains the kind field. + // This can be used to quickly discriminate among the four kinds of + // InstanceKlass. + + static const unsigned _misc_kind_field_size = 2; + static const unsigned _misc_kind_field_pos = 0; + static const unsigned _misc_kind_field_mask = (1u << _misc_kind_field_size) - 1u; + + static const unsigned _misc_kind_other = 0; // concrete InstanceKlass + static const unsigned _misc_kind_reference = 1; // InstanceRefKlass + static const unsigned _misc_kind_class_loader = 2; // InstanceClassLoaderKlass + static const unsigned _misc_kind_mirror = 3; // InstanceMirrorKlass + + // Start after _misc_kind field. enum { - _misc_rewritten = 1 << 0, // methods rewritten. - _misc_has_nonstatic_fields = 1 << 1, // for sizing with UseCompressedOops - _misc_should_verify_class = 1 << 2, // allow caching of preverification - _misc_is_anonymous = 1 << 3, // has embedded _host_klass field - _misc_is_contended = 1 << 4, // marked with contended annotation - _misc_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods - _misc_declares_default_methods = 1 << 6, // directly declares default methods (any access) - _misc_has_been_redefined = 1 << 7, // class has been redefined - _misc_is_scratch_class = 1 << 8 // class is the redefined scratch class + _misc_rewritten = 1 << 2, // methods rewritten. + _misc_has_nonstatic_fields = 1 << 3, // for sizing with UseCompressedOops + _misc_should_verify_class = 1 << 4, // allow caching of preverification + _misc_is_anonymous = 1 << 5, // has embedded _host_klass field + _misc_is_contended = 1 << 6, // marked with contended annotation + _misc_has_default_methods = 1 << 7, // class/superclass/implemented interfaces has default methods + _misc_declares_default_methods = 1 << 8, // directly declares default methods (any access) + _misc_has_been_redefined = 1 << 9, // class has been redefined + _misc_is_scratch_class = 1 << 10 // class is the redefined scratch class }; u2 _misc_flags; u2 _minor_version; // minor version number of class file @@ -667,6 +682,28 @@ _misc_flags |= _misc_is_scratch_class; } +private: + + void set_kind(unsigned kind) { + assert(kind <= _misc_kind_field_mask, "Invalid InstanceKlass kind"); + unsigned fmask = _misc_kind_field_mask << _misc_kind_field_pos; + unsigned flags = _misc_flags & ~fmask; + _misc_flags = (flags | (kind << _misc_kind_field_pos)); + } + + bool is_kind(unsigned desired) const { + unsigned kind = (_misc_flags >> _misc_kind_field_pos) & _misc_kind_field_mask; + return kind == desired; + } + +public: + + // Other is anything that is not one of the more specialized kinds of InstanceKlass. + bool is_other_instance_klass() const { return is_kind(_misc_kind_other); } + bool is_reference_instance_klass() const { return is_kind(_misc_kind_reference); } + bool is_mirror_instance_klass() const { return is_kind(_misc_kind_mirror); } + bool is_class_loader_instance_klass() const { return is_kind(_misc_kind_class_loader); } + void init_previous_versions() { _previous_versions = NULL; } @@ -885,9 +922,8 @@ // Casting from Klass* static InstanceKlass* cast(Klass* k) { - assert(k == NULL || k->is_klass(), "must be"); assert(k == NULL || k->oop_is_instance(), "cast to InstanceKlass"); - return (InstanceKlass*) k; + return static_cast(k); } InstanceKlass* java_super() const { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/instanceMirrorKlass.hpp --- a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -48,17 +48,17 @@ // Constructor InstanceMirrorKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous) - : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous) {} + : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, + InstanceKlass::_misc_kind_mirror, rt, access_flags, is_anonymous) {} public: InstanceMirrorKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } - // Type testing - bool oop_is_instanceMirror() const { return true; } // Casting from Klass* static InstanceMirrorKlass* cast(Klass* k) { - assert(k->oop_is_instanceMirror(), "cast to InstanceMirrorKlass"); - return (InstanceMirrorKlass*) k; + assert(InstanceKlass::cast(k)->is_mirror_instance_klass(), + "cast to InstanceMirrorKlass"); + return static_cast(k); } // Returns the size of the instance including the extra static fields. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/instanceRefKlass.cpp --- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -33,8 +33,6 @@ #include "utilities/macros.hpp" #include "utilities/preserveException.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) { // Clear the nonstatic oop-map entries corresponding to referent // and nextPending field. They are treated specially by the diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/instanceRefKlass.hpp --- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -51,18 +51,11 @@ // Constructor InstanceRefKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous) - : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt, access_flags, is_anonymous) {} + : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, + InstanceKlass::_misc_kind_reference, rt, access_flags, is_anonymous) {} public: InstanceRefKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } - // Type testing - bool oop_is_instanceRef() const { return true; } - - // Casting from Klass* - static InstanceRefKlass* cast(Klass* k) { - assert(k->oop_is_instanceRef(), "cast to InstanceRefKlass"); - return (InstanceRefKlass*) k; - } // GC specific object visitors // diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/klass.cpp --- a/hotspot/src/share/vm/oops/klass.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/klass.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -690,11 +690,11 @@ bool Klass::verify_vtable_index(int i) { if (oop_is_instance()) { int limit = ((InstanceKlass*)this)->vtable_length()/vtableEntry::size(); - assert(i >= 0 && i < limit, err_msg("index %d out of bounds %d", i, limit)); + assert(i >= 0 && i < limit, "index %d out of bounds %d", i, limit); } else { assert(oop_is_array(), "Must be"); int limit = ((ArrayKlass*)this)->vtable_length()/vtableEntry::size(); - assert(i >= 0 && i < limit, err_msg("index %d out of bounds %d", i, limit)); + assert(i >= 0 && i < limit, "index %d out of bounds %d", i, limit); } return true; } @@ -715,8 +715,14 @@ class TestKlass { public: static void test_oop_is_instanceClassLoader() { - assert(SystemDictionary::ClassLoader_klass()->oop_is_instanceClassLoader(), "assert"); - assert(!SystemDictionary::String_klass()->oop_is_instanceClassLoader(), "assert"); + Klass* klass = SystemDictionary::ClassLoader_klass(); + guarantee(klass->oop_is_instance(), "assert"); + guarantee(InstanceKlass::cast(klass)->is_class_loader_instance_klass(), "test failed"); + + klass = SystemDictionary::String_klass(); + guarantee(!klass->oop_is_instance() || + !InstanceKlass::cast(klass)->is_class_loader_instance_klass(), + "test failed"); } }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/klass.hpp --- a/hotspot/src/share/vm/oops/klass.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/klass.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -341,7 +341,7 @@ assert(lh < (jint)_lh_neutral_value, "must be array"); int l2esz = (lh >> _lh_log2_element_size_shift) & _lh_log2_element_size_mask; assert(l2esz <= LogBitsPerLong, - err_msg("sanity. l2esz: 0x%x for lh: 0x%x", (uint)l2esz, (uint)lh)); + "sanity. l2esz: 0x%x for lh: 0x%x", (uint)l2esz, (uint)lh); return l2esz; } static jint array_layout_helper(jint tag, int hsize, BasicType etype, int log2_esize) { @@ -480,9 +480,6 @@ virtual bool oop_is_objArray_slow() const { return false; } virtual bool oop_is_typeArray_slow() const { return false; } public: - virtual bool oop_is_instanceClassLoader() const { return false; } - virtual bool oop_is_instanceMirror() const { return false; } - virtual bool oop_is_instanceRef() const { return false; } // Fast non-virtual versions #ifndef ASSERT diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/klass.inline.hpp --- a/hotspot/src/share/vm/oops/klass.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/klass.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -63,7 +63,7 @@ assert(!is_null(v), "narrow klass value can never be zero"); int shift = Universe::narrow_klass_shift(); Klass* result = (Klass*)(void*)((uintptr_t)Universe::narrow_klass_base() + ((uintptr_t)v << shift)); - assert(check_klass_alignment(result), err_msg("address not aligned: " INTPTR_FORMAT, p2i((void*) result))); + assert(check_klass_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result)); return result; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/klassVtable.cpp --- a/hotspot/src/share/vm/oops/klassVtable.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/klassVtable.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -38,8 +38,6 @@ #include "runtime/handles.inline.hpp" #include "utilities/copy.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - inline InstanceKlass* klassVtable::ik() const { Klass* k = _klass(); assert(k->oop_is_instance(), "not an InstanceKlass"); @@ -1461,8 +1459,8 @@ oop* end_of_obj = (oop*)_klass() + _klass()->size(); oop* end_of_vtable = (oop *)&table()[_length]; if (end_of_vtable > end_of_obj) { - fatal(err_msg("klass %s: klass object too short (vtable extends beyond " - "end)", _klass->internal_name())); + fatal("klass %s: klass object too short (vtable extends beyond end)", + _klass->internal_name()); } for (int i = 0; i < _length; i++) table()[i].verify(this, st); @@ -1505,7 +1503,7 @@ #ifndef PRODUCT print(); #endif - fatal(err_msg("vtableEntry " PTR_FORMAT ": method is from subclass", this)); + fatal("vtableEntry " PTR_FORMAT ": method is from subclass", p2i(this)); } } @@ -1515,7 +1513,7 @@ ResourceMark rm; tty->print("vtableEntry %s: ", method()->name()->as_C_string()); if (Verbose) { - tty->print("m %#lx ", (address)method()); + tty->print("m " PTR_FORMAT " ", p2i(method())); } } @@ -1586,7 +1584,7 @@ void klassItable::print_statistics() { tty->print_cr("itable statistics:"); tty->print_cr("%6d classes with itables", _total_classes); - tty->print_cr("%6d K uses for itables (average by class: %d bytes)", _total_size / K, _total_size / _total_classes); + tty->print_cr("%6lu K uses for itables (average by class: %ld bytes)", _total_size / K, _total_size / _total_classes); } #endif // PRODUCT diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/markOop.cpp --- a/hotspot/src/share/vm/oops/markOop.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/markOop.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -27,8 +27,6 @@ #include "runtime/thread.inline.hpp" #include "runtime/objectMonitor.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void markOopDesc::print_on(outputStream* st) const { if (is_marked()) { st->print(" marked(" INTPTR_FORMAT ")", value()); @@ -39,7 +37,7 @@ if (mon == NULL) { st->print("NULL (this should never be seen!)"); } else { - st->print("{count=" INTPTR_FORMAT ",waiters=" INTPTR_FORMAT + st->print("{count=0x%08x,waiters=0x%08x" ",recursions=" INTPTR_FORMAT ",owner=" INTPTR_FORMAT "}", mon->count(), mon->waiters(), mon->recursions(), p2i(mon->owner())); @@ -65,7 +63,7 @@ assert(is_unlocked() || has_bias_pattern(), "just checking"); st->print("mark("); if (has_bias_pattern()) st->print("biased,"); - st->print("hash %#lx,", hash()); + st->print("hash " INTPTR_FORMAT ",", hash()); st->print("age %d)", age()); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/method.cpp --- a/hotspot/src/share/vm/oops/method.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/method.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -57,8 +57,6 @@ #include "utilities/quickSort.hpp" #include "utilities/xmlstream.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of Method Method* Method::allocate(ClassLoaderData* loader_data, @@ -220,7 +218,7 @@ Thread* myThread = Thread::current(); methodHandle h_this(myThread, this); -#ifdef ASSERT +#if defined(ASSERT) && !INCLUDE_JVMCI bool has_capability = myThread->is_VM_thread() || myThread->is_ConcurrentGC_thread() || myThread->is_GC_task_thread(); @@ -246,9 +244,11 @@ return 0; } #ifdef ASSERT - { ResourceMark rm; - assert(is_native() && bcp == code_base() || contains(bcp) || is_error_reported(), - err_msg("bcp doesn't belong to this method: bcp: " INTPTR_FORMAT ", method: %s", bcp, name_and_sig_as_C_string())); + { + ResourceMark rm; + assert(is_native() && bcp == code_base() || contains(bcp) || is_error_reported(), + "bcp doesn't belong to this method: bcp: " INTPTR_FORMAT ", method: %s", + p2i(bcp), name_and_sig_as_C_string()); } #endif return bcp - code_base(); @@ -279,7 +279,7 @@ } address Method::bcp_from(int bci) const { - assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()), err_msg("illegal bci: %d", bci)); + assert((is_native() && bci == 0) || (!is_native() && 0 <= bci && bci < code_size()), "illegal bci: %d", bci); address bcp = code_base() + bci; assert(is_native() && bcp == code_base() || contains(bcp), "bcp doesn't belong to this method"); return bcp; @@ -573,7 +573,7 @@ ResourceMark rm; bool is_nonv = (vtable_index() == nonvirtual_vtable_index); if (class_access_flags.is_interface()) { - assert(is_nonv == is_static(), err_msg("is_nonv=%s", name_and_sig_as_C_string())); + assert(is_nonv == is_static(), "is_nonv=%s", name_and_sig_as_C_string()); } #endif assert(valid_vtable_index() || valid_itable_index(), "method must be linked before we ask this question"); @@ -1373,7 +1373,7 @@ // These two methods are static since a GC may move the Method bool Method::load_signature_classes(methodHandle m, TRAPS) { - if (THREAD->is_Compiler_thread()) { + if (!THREAD->can_call_java()) { // There is nothing useful this routine can do from within the Compile thread. // Hopefully, the signature contains only well-known classes. // We could scan for this and return true/false, but the caller won't care. @@ -1491,14 +1491,20 @@ void Method::print_name(outputStream* st) { Thread *thread = Thread::current(); ResourceMark rm(thread); - SignatureTypePrinter sig(signature(), st); st->print("%s ", is_static() ? "static" : "virtual"); - sig.print_returntype(); - st->print(" %s.", method_holder()->internal_name()); - name()->print_symbol_on(st); - st->print("("); - sig.print_parameters(); - st->print(")"); + if (WizardMode) { + st->print("%s.", method_holder()->internal_name()); + name()->print_symbol_on(st); + signature()->print_symbol_on(st); + } else { + SignatureTypePrinter sig(signature(), st); + sig.print_returntype(); + st->print(" %s.", method_holder()->internal_name()); + name()->print_symbol_on(st); + st->print("("); + sig.print_parameters(); + st->print(")"); + } } #endif // !PRODUCT || INCLUDE_JVMTI @@ -1572,7 +1578,7 @@ } { ResourceMark rm; - fatal(err_msg("no original bytecode found in %s at bci %d", name_and_sig_as_C_string(), bci)); + fatal("no original bytecode found in %s at bci %d", name_and_sig_as_C_string(), bci); } return Bytecodes::_shouldnotreachhere; } @@ -2024,9 +2030,9 @@ assert(is_method(), "must be method"); st->print_cr("%s", internal_name()); // get the effect of PrintOopAddress, always, for methods: - st->print_cr(" - this oop: " INTPTR_FORMAT, (intptr_t)this); + st->print_cr(" - this oop: " INTPTR_FORMAT, p2i(this)); st->print (" - method holder: "); method_holder()->print_value_on(st); st->cr(); - st->print (" - constants: " INTPTR_FORMAT " ", (address)constants()); + st->print (" - constants: " INTPTR_FORMAT " ", p2i(constants())); constants()->print_value_on(st); st->cr(); st->print (" - access: 0x%x ", access_flags().as_int()); access_flags().print_on(st); st->cr(); st->print (" - name: "); name()->print_value_on(st); st->cr(); @@ -2040,26 +2046,26 @@ if (highest_comp_level() != CompLevel_none) st->print_cr(" - highest level: %d", highest_comp_level()); st->print_cr(" - vtable index: %d", _vtable_index); - st->print_cr(" - i2i entry: " INTPTR_FORMAT, interpreter_entry()); + st->print_cr(" - i2i entry: " INTPTR_FORMAT, p2i(interpreter_entry())); st->print( " - adapters: "); AdapterHandlerEntry* a = ((Method*)this)->adapter(); if (a == NULL) - st->print_cr(INTPTR_FORMAT, a); + st->print_cr(INTPTR_FORMAT, p2i(a)); else a->print_adapter_on(st); - st->print_cr(" - compiled entry " INTPTR_FORMAT, from_compiled_entry()); + st->print_cr(" - compiled entry " INTPTR_FORMAT, p2i(from_compiled_entry())); st->print_cr(" - code size: %d", code_size()); if (code_size() != 0) { - st->print_cr(" - code start: " INTPTR_FORMAT, code_base()); - st->print_cr(" - code end (excl): " INTPTR_FORMAT, code_base() + code_size()); + st->print_cr(" - code start: " INTPTR_FORMAT, p2i(code_base())); + st->print_cr(" - code end (excl): " INTPTR_FORMAT, p2i(code_base() + code_size())); } if (method_data() != NULL) { - st->print_cr(" - method data: " INTPTR_FORMAT, (address)method_data()); + st->print_cr(" - method data: " INTPTR_FORMAT, p2i(method_data())); } st->print_cr(" - checked ex length: %d", checked_exceptions_length()); if (checked_exceptions_length() > 0) { CheckedExceptionElement* table = checked_exceptions_start(); - st->print_cr(" - checked ex start: " INTPTR_FORMAT, table); + st->print_cr(" - checked ex start: " INTPTR_FORMAT, p2i(table)); if (Verbose) { for (int i = 0; i < checked_exceptions_length(); i++) { st->print_cr(" - throws %s", constants()->printable_name_at(table[i].class_cp_index)); @@ -2068,7 +2074,7 @@ } if (has_linenumber_table()) { u_char* table = compressed_linenumber_table(); - st->print_cr(" - linenumber start: " INTPTR_FORMAT, table); + st->print_cr(" - linenumber start: " INTPTR_FORMAT, p2i(table)); if (Verbose) { CompressedLineNumberReadStream stream(table); while (stream.read_pair()) { @@ -2079,7 +2085,7 @@ st->print_cr(" - localvar length: %d", localvariable_table_length()); if (localvariable_table_length() > 0) { LocalVariableTableElement* table = localvariable_table_start(); - st->print_cr(" - localvar start: " INTPTR_FORMAT, table); + st->print_cr(" - localvar start: " INTPTR_FORMAT, p2i(table)); if (Verbose) { for (int i = 0; i < localvariable_table_length(); i++) { int bci = table[i].start_bci; @@ -2096,8 +2102,8 @@ code()->print_value_on(st); } if (is_native()) { - st->print_cr(" - native function: " INTPTR_FORMAT, native_function()); - st->print_cr(" - signature handler: " INTPTR_FORMAT, signature_handler()); + st->print_cr(" - native function: " INTPTR_FORMAT, p2i(native_function())); + st->print_cr(" - signature handler: " INTPTR_FORMAT, p2i(signature_handler())); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/method.hpp --- a/hotspot/src/share/vm/oops/method.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/method.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -685,8 +685,10 @@ TRAPS); static Klass* check_non_bcp_klass(Klass* klass); - // How many extra stack entries for invokedynamic when it's enabled - static const int extra_stack_entries_for_jsr292 = 1; + enum { + // How many extra stack entries for invokedynamic + extra_stack_entries_for_jsr292 = 1 + }; // this operates only on invoke methods: // presize interpreter frames for extra interpreter stack entries, if needed diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/methodCounters.hpp --- a/hotspot/src/share/vm/oops/methodCounters.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/methodCounters.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -42,7 +42,7 @@ // The counter is reset by the sweeper and is decremented by some of the compiled // code. The counter values are interpreted as follows: // 1. (HotMethodDetection..INT_MAX] - initial value, no counters inserted - // 2. (1..HotMethodDetectionLimit) - the method is warm, the counter is used + // 2. [1..HotMethodDetectionLimit) - the method is warm, the counter is used // to figure out which methods can be flushed. // 3. (INT_MIN..0] - method is hot and will deopt and get // recompiled without the counters diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/methodData.cpp --- a/hotspot/src/share/vm/oops/methodData.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/methodData.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -38,8 +38,6 @@ #include "runtime/orderAccess.inline.hpp" #include "utilities/copy.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // ================================================================== // DataLayout // @@ -110,7 +108,7 @@ return ss.as_string(); break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } } return NULL; @@ -413,13 +411,39 @@ } } +#if INCLUDE_JVMCI +void VirtualCallData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) { + ReceiverTypeData::clean_weak_klass_links(is_alive_cl); + for (uint row = 0; row < method_row_limit(); row++) { + Method* p = method(row); + if (p != NULL && !p->method_holder()->is_loader_alive(is_alive_cl)) { + clear_method_row(row); + } + } +} + +void VirtualCallData::clean_weak_method_links() { + ReceiverTypeData::clean_weak_method_links(); + for (uint row = 0; row < method_row_limit(); row++) { + Method* p = method(row); + if (p != NULL && !p->on_stack()) { + clear_method_row(row); + } + } +} +#endif // INCLUDE_JVMCI + void ReceiverTypeData::print_receiver_data_on(outputStream* st) const { uint row; int entries = 0; for (row = 0; row < row_limit(); row++) { if (receiver(row) != NULL) entries++; } +#if INCLUDE_JVMCI + st->print_cr("count(%u) nonprofiled_count(%u) entries(%u)", count(), nonprofiled_count(), entries); +#else st->print_cr("count(%u) entries(%u)", count(), entries); +#endif int total = count(); for (row = 0; row < row_limit(); row++) { if (receiver(row) != NULL) { @@ -438,9 +462,36 @@ print_shared(st, "ReceiverTypeData", extra); print_receiver_data_on(st); } + +#if INCLUDE_JVMCI +void VirtualCallData::print_method_data_on(outputStream* st) const { + uint row; + int entries = 0; + for (row = 0; row < method_row_limit(); row++) { + if (method(row) != NULL) entries++; + } + tab(st); + st->print_cr("method_entries(%u)", entries); + int total = count(); + for (row = 0; row < method_row_limit(); row++) { + if (method(row) != NULL) { + total += method_count(row); + } + } + for (row = 0; row < method_row_limit(); row++) { + if (method(row) != NULL) { + tab(st); + method(row)->print_value_on(st); + st->print_cr("(%u %4.2f)", method_count(row), (float) method_count(row) / (float) total); + } + } +} +#endif // INCLUDE_JVMCI + void VirtualCallData::print_data_on(outputStream* st, const char* extra) const { print_shared(st, "VirtualCallData", extra); print_receiver_data_on(st); + print_method_data_on(st); } // ================================================================== @@ -665,7 +716,7 @@ } int MethodData::bytecode_cell_count(Bytecodes::Code code) { -#if defined(COMPILER1) && !defined(COMPILER2) +#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) return no_profile_data; #else switch (code) { @@ -797,6 +848,26 @@ } int MethodData::compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps) { +#if INCLUDE_JVMCI + if (ProfileTraps) { + // Assume that up to 30% of the possibly trapping BCIs with no MDP will need to allocate one. + int extra_data_count = MIN2(empty_bc_count, MAX2(4, (empty_bc_count * 30) / 100)); + + // Make sure we have a minimum number of extra data slots to + // allocate SpeculativeTrapData entries. We would want to have one + // entry per compilation that inlines this method and for which + // some type speculation assumption fails. So the room we need for + // the SpeculativeTrapData entries doesn't directly depend on the + // size of the method. Because it's hard to estimate, we reserve + // space for an arbitrary number of entries. + int spec_data_count = (needs_speculative_traps ? SpecTrapLimitExtraEntries : 0) * + (SpeculativeTrapData::static_cell_count() + DataLayout::header_size_in_cells()); + + return MAX2(extra_data_count, spec_data_count); + } else { + return 0; + } +#else // INCLUDE_JVMCI if (ProfileTraps) { // Assume that up to 3% of BCIs with no MDP will need to allocate one. int extra_data_count = (uint)(empty_bc_count * 3) / 128 + 1; @@ -822,6 +893,7 @@ } else { return 0; } +#endif // INCLUDE_JVMCI } // Compute the size of the MethodData* necessary to store @@ -835,7 +907,7 @@ while ((c = stream.next()) >= 0) { int size_in_bytes = compute_data_size(&stream); data_size += size_in_bytes; - if (size_in_bytes == 0) empty_bc_count += 1; + if (size_in_bytes == 0 JVMCI_ONLY(&& Bytecodes::can_trap(c))) empty_bc_count += 1; needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c); } int object_size = in_bytes(data_offset()) + data_size; @@ -869,7 +941,7 @@ // the segment in bytes. int MethodData::initialize_data(BytecodeStream* stream, int data_index) { -#if defined(COMPILER1) && !defined(COMPILER2) +#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) return 0; #else int cell_count = -1; @@ -1060,10 +1132,14 @@ MethodData::MethodData(methodHandle method, int size, TRAPS) : _extra_data_lock(Monitor::leaf, "MDO extra data lock"), _parameters_type_data_di(parameters_uninitialized) { + // Set the method back-pointer. + _method = method(); + initialize(); +} + +void MethodData::initialize() { No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC ResourceMark rm; - // Set the method back-pointer. - _method = method(); init(); set_creation_mileage(mileage_of(method())); @@ -1073,13 +1149,13 @@ int data_size = 0; int empty_bc_count = 0; // number of bytecodes lacking data _data[0] = 0; // apparently not set below. - BytecodeStream stream(method); + BytecodeStream stream(method()); Bytecodes::Code c; bool needs_speculative_traps = false; while ((c = stream.next()) >= 0) { int size_in_bytes = initialize_data(&stream, data_size); data_size += size_in_bytes; - if (size_in_bytes == 0) empty_bc_count += 1; + if (size_in_bytes == 0 JVMCI_ONLY(&& Bytecodes::can_trap(c))) empty_bc_count += 1; needs_speculative_traps = needs_speculative_traps || is_speculative_trap_bytecode(c); } _data_size = data_size; @@ -1097,7 +1173,7 @@ // the code for traps cells works. DataLayout *dp = data_layout_at(data_size + extra_size); - int arg_size = method->size_of_parameters(); + int arg_size = method()->size_of_parameters(); dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1); int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1); @@ -1126,6 +1202,7 @@ post_initialize(&stream); + assert(object_size == compute_allocation_size_in_bytes(methodHandle(_method)), "MethodData: computed size != initialized size"); set_size(object_size); } @@ -1146,6 +1223,10 @@ _num_blocks = 0; _would_profile = unknown; +#if INCLUDE_JVMCI + _jvmci_ir_size = 0; +#endif + #if INCLUDE_RTM_OPT _rtm_state = NoRTM; // No RTM lock eliding by default if (UseRTMLocking && @@ -1239,7 +1320,7 @@ nb_cells = SpeculativeTrapData::static_cell_count(); break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } return (DataLayout*)((address)dp + DataLayout::compute_size_in_bytes(nb_cells)); } @@ -1279,7 +1360,7 @@ } break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } } return NULL; @@ -1400,7 +1481,7 @@ dp = end; // ArgInfoData is at the end of extra data section. break; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } st->print("%d", dp_to_di(data->dp())); st->fill_to(6); @@ -1612,7 +1693,7 @@ clean_extra_data_helper(dp, shift, true); return; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } } } @@ -1638,7 +1719,7 @@ case DataLayout::arg_info_data_tag: return; default: - fatal(err_msg("unexpected tag %d", dp->tag())); + fatal("unexpected tag %d", dp->tag()); } } #endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/methodData.hpp --- a/hotspot/src/share/vm/oops/methodData.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/methodData.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -539,7 +539,11 @@ enum { // null_seen: // saw a null operand (cast/aastore/instanceof) - null_seen_flag = DataLayout::first_flag + 0 + null_seen_flag = DataLayout::first_flag + 0 +#if INCLUDE_JVMCI + // bytecode threw any exception + , exception_seen_flag = null_seen_flag + 1 +#endif }; enum { bit_cell_count = 0 }; // no additional data fields needed. public: @@ -563,6 +567,11 @@ bool null_seen() { return flag_at(null_seen_flag); } void set_null_seen() { set_flag_at(null_seen_flag); } +#if INCLUDE_JVMCI + // true if an exception was thrown at the specific BCI + bool exception_seen() { return flag_at(exception_seen_flag); } + void set_exception_seen() { set_flag_at(exception_seen_flag); } +#endif // Code generation support static int null_seen_byte_constant() { @@ -1166,7 +1175,22 @@ class ReceiverTypeData : public CounterData { protected: enum { +#if INCLUDE_JVMCI + // Description of the different counters + // ReceiverTypeData for instanceof/checkcast/aastore: + // C1/C2: count is incremented on type overflow and decremented for failed type checks + // JVMCI: count decremented for failed type checks and nonprofiled_count is incremented on type overflow + // TODO (chaeubl): in fact, JVMCI should also increment the count for failed type checks to mimic the C1/C2 behavior + // VirtualCallData for invokevirtual/invokeinterface: + // C1/C2: count is incremented on type overflow + // JVMCI: count is incremented on type overflow, nonprofiled_count is incremented on method overflow + + // JVMCI is interested in knowing the percentage of type checks involving a type not explicitly in the profile + nonprofiled_count_off_set = counter_cell_count, + receiver0_offset, +#else receiver0_offset = counter_cell_count, +#endif count0_offset, receiver_type_row_cell_count = (count0_offset + 1) - receiver0_offset }; @@ -1181,7 +1205,7 @@ virtual bool is_ReceiverTypeData() const { return true; } static int static_cell_count() { - return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count; + return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count JVMCI_ONLY(+ 1); } virtual int cell_count() const { @@ -1243,6 +1267,13 @@ set_count(0); set_receiver(row, NULL); set_receiver_count(row, 0); +#if INCLUDE_JVMCI + if (!this->is_VirtualCallData()) { + // if this is a ReceiverTypeData for JVMCI, the nonprofiled_count + // must also be reset (see "Description of the different counters" above) + set_nonprofiled_count(0); + } +#endif } // Code generation support @@ -1252,6 +1283,17 @@ static ByteSize receiver_count_offset(uint row) { return cell_offset(receiver_count_cell_index(row)); } +#if INCLUDE_JVMCI + static ByteSize nonprofiled_receiver_count_offset() { + return cell_offset(nonprofiled_count_off_set); + } + uint nonprofiled_count() const { + return uint_at(nonprofiled_count_off_set); + } + void set_nonprofiled_count(uint count) { + set_uint_at(nonprofiled_count_off_set, count); + } +#endif // INCLUDE_JVMCI static ByteSize receiver_type_data_size() { return cell_offset(static_cell_count()); } @@ -1316,7 +1358,7 @@ static int static_cell_count() { // At this point we could add more profile state, e.g., for arguments. // But for now it's the same size as the base record type. - return ReceiverTypeData::static_cell_count(); + return ReceiverTypeData::static_cell_count() JVMCI_ONLY(+ (uint) MethodProfileWidth * receiver_type_row_cell_count); } virtual int cell_count() const { @@ -1338,6 +1380,62 @@ } #endif // CC_INTERP +#if INCLUDE_JVMCI + static ByteSize method_offset(uint row) { + return cell_offset(method_cell_index(row)); + } + static ByteSize method_count_offset(uint row) { + return cell_offset(method_count_cell_index(row)); + } + static int method_cell_index(uint row) { + return receiver0_offset + (row + TypeProfileWidth) * receiver_type_row_cell_count; + } + static int method_count_cell_index(uint row) { + return count0_offset + (row + TypeProfileWidth) * receiver_type_row_cell_count; + } + static uint method_row_limit() { + return MethodProfileWidth; + } + + Method* method(uint row) const { + assert(row < method_row_limit(), "oob"); + + Method* method = (Method*)intptr_at(method_cell_index(row)); + assert(method == NULL || method->is_method(), "must be"); + return method; + } + + uint method_count(uint row) const { + assert(row < method_row_limit(), "oob"); + return uint_at(method_count_cell_index(row)); + } + + void set_method(uint row, Method* m) { + assert((uint)row < method_row_limit(), "oob"); + set_intptr_at(method_cell_index(row), (uintptr_t)m); + } + + void set_method_count(uint row, uint count) { + assert(row < method_row_limit(), "oob"); + set_uint_at(method_count_cell_index(row), count); + } + + void clear_method_row(uint row) { + assert(row < method_row_limit(), "oob"); + // Clear total count - indicator of polymorphic call site (see comment for clear_row() in ReceiverTypeData). + set_nonprofiled_count(0); + set_method(row, NULL); + set_method_count(row, 0); + } + + // GC support + virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure); + + // Redefinition support + virtual void clean_weak_method_links(); +#endif // INCLUDE_JVMCI + + void print_method_data_on(outputStream* st) const NOT_JVMCI_RETURN; void print_data_on(outputStream* st, const char* extra = NULL) const; }; @@ -2053,10 +2151,11 @@ MethodData() : _extra_data_lock(Monitor::leaf, "MDO extra data lock") {}; // For ciMethodData bool is_methodData() const volatile { return true; } + void initialize(); // Whole-method sticky bits and flags enum { - _trap_hist_limit = 22, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 22 JVMCI_ONLY(+5), // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values @@ -2104,6 +2203,11 @@ enum WouldProfile {unknown, no_profile, profile}; WouldProfile _would_profile; +#if INCLUDE_JVMCI + // Support for HotSpotMethodData.setCompiledIRSize(int) + int _jvmci_ir_size; +#endif + // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; @@ -2382,7 +2486,7 @@ // Return (uint)-1 for overflow. uint trap_count(int reason) const { - assert((uint)reason < _trap_hist_limit, "oob"); + assert((uint)reason < JVMCI_ONLY(2*) _trap_hist_limit, "oob"); return (int)((_trap_hist._array[reason]+1) & _trap_hist_mask) - 1; } // For loops: @@ -2391,17 +2495,13 @@ uint inc_trap_count(int reason) { // Count another trap, anywhere in this method. assert(reason >= 0, "must be single trap"); - if ((uint)reason < _trap_hist_limit) { - uint cnt1 = 1 + _trap_hist._array[reason]; - if ((cnt1 & _trap_hist_mask) != 0) { // if no counter overflow... - _trap_hist._array[reason] = cnt1; - return cnt1; - } else { - return _trap_hist_mask + (++_nof_overflow_traps); - } + assert((uint)reason < JVMCI_ONLY(2*) _trap_hist_limit, "oob"); + uint cnt1 = 1 + _trap_hist._array[reason]; + if ((cnt1 & _trap_hist_mask) != 0) { // if no counter overflow... + _trap_hist._array[reason] = cnt1; + return cnt1; } else { - // Could not represent the count in the histogram. - return (++_nof_overflow_traps); + return _trap_hist_mask + (++_nof_overflow_traps); } } @@ -2446,6 +2546,10 @@ return byte_offset_of(MethodData, _data[0]); } + static ByteSize trap_history_offset() { + return byte_offset_of(MethodData, _trap_hist._array); + } + static ByteSize invocation_counter_offset() { return byte_offset_of(MethodData, _invocation_counter); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/oop.cpp --- a/hotspot/src/share/vm/oops/oop.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/oop.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,8 +31,6 @@ #include "runtime/thread.inline.hpp" #include "utilities/copy.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - bool always_do_update_barrier = false; BarrierSet* oopDesc::_bs = NULL; @@ -47,7 +45,7 @@ void oopDesc::print_address_on(outputStream* st) const { if (PrintOopAddress) { - st->print("{" INTPTR_FORMAT "}", this); + st->print("{" INTPTR_FORMAT "}", p2i(this)); } } @@ -123,7 +121,7 @@ template void VerifyOopClosure::do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); - guarantee(obj->is_oop_or_null(), err_msg("invalid oop: " INTPTR_FORMAT, p2i((oopDesc*) obj))); + guarantee(obj->is_oop_or_null(), "invalid oop: " INTPTR_FORMAT, p2i((oopDesc*) obj)); } void VerifyOopClosure::do_oop(oop* p) { VerifyOopClosure::do_oop_work(p); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/oops/oop.inline.hpp --- a/hotspot/src/share/vm/oops/oop.inline.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/oops/oop.inline.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -126,10 +126,25 @@ inline bool oopDesc::is_a(Klass* k) const { return klass()->is_subtype_of(k); } -inline bool oopDesc::is_instance() const { return klass()->oop_is_instance(); } -inline bool oopDesc::is_instanceClassLoader() const { return klass()->oop_is_instanceClassLoader(); } -inline bool oopDesc::is_instanceMirror() const { return klass()->oop_is_instanceMirror(); } -inline bool oopDesc::is_instanceRef() const { return klass()->oop_is_instanceRef(); } +inline bool oopDesc::is_instance() const { + return klass()->oop_is_instance(); +} + +inline bool oopDesc::is_instanceClassLoader() const { + Klass* k = klass(); + return k->oop_is_instance() && InstanceKlass::cast(k)->is_class_loader_instance_klass(); +} + +inline bool oopDesc::is_instanceMirror() const { + Klass* k = klass(); + return k->oop_is_instance() && InstanceKlass::cast(k)->is_mirror_instance_klass(); +} + +inline bool oopDesc::is_instanceRef() const { + Klass* k = klass(); + return k->oop_is_instance() && InstanceKlass::cast(k)->is_reference_instance_klass(); +} + inline bool oopDesc::is_array() const { return klass()->oop_is_array(); } inline bool oopDesc::is_objArray() const { return klass()->oop_is_objArray(); } inline bool oopDesc::is_typeArray() const { return klass()->oop_is_typeArray(); } @@ -189,7 +204,7 @@ address base = Universe::narrow_oop_base(); int shift = Universe::narrow_oop_shift(); oop result = (oop)(void*)((uintptr_t)base + ((uintptr_t)v << shift)); - assert(check_obj_alignment(result), err_msg("address not aligned: " INTPTR_FORMAT, p2i((void*) result))); + assert(check_obj_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result)); return result; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/block.cpp --- a/hotspot/src/share/vm/opto/block.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/block.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -358,6 +358,8 @@ PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher) : Phase(CFG) , _block_arena(arena) +, _regalloc(NULL) +, _scheduling_for_pressure(false) , _root(root) , _matcher(matcher) , _node_to_block_mapping(arena) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/block.hpp --- a/hotspot/src/share/vm/opto/block.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/block.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -37,6 +37,7 @@ class Matcher; class RootNode; class VectorSet; +class PhaseChaitin; struct Tarjan; //------------------------------Block_Array------------------------------------ @@ -383,6 +384,12 @@ // Arena for the blocks to be stored in Arena* _block_arena; + // Info used for scheduling + PhaseChaitin* _regalloc; + + // Register pressure heuristic used? + bool _scheduling_for_pressure; + // The matcher for this compilation Matcher& _matcher; @@ -433,12 +440,14 @@ // to late. Helper for schedule_late. Block* hoist_to_cheaper_block(Block* LCA, Block* early, Node* self); - bool schedule_local(Block* block, GrowableArray& ready_cnt, VectorSet& next_call); + bool schedule_local(Block* block, GrowableArray& ready_cnt, VectorSet& next_call, intptr_t* recacl_pressure_nodes); void set_next_call(Block* block, Node* n, VectorSet& next_call); void needed_for_next_call(Block* block, Node* this_call, VectorSet& next_call); // Perform basic-block local scheduling - Node* select(Block* block, Node_List& worklist, GrowableArray& ready_cnt, VectorSet& next_call, uint sched_slot); + Node* select(Block* block, Node_List& worklist, GrowableArray& ready_cnt, VectorSet& next_call, uint sched_slot, + intptr_t* recacl_pressure_nodes); + void adjust_register_pressure(Node* n, Block* block, intptr_t *recalc_pressure_nodes, bool finalize_mode); // Schedule a call next in the block uint sched_call(Block* block, uint node_cnt, Node_List& worklist, GrowableArray& ready_cnt, MachCallNode* mcall, VectorSet& next_call); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/bytecodeInfo.cpp --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -114,7 +114,7 @@ CompileTask::print_inline_indent(inline_level()); tty->print_cr("Inlined method is hot: "); } - set_msg("force inline by CompilerOracle"); + set_msg("force inline by CompileCommand"); _forced_inline = true; return true; } @@ -223,12 +223,12 @@ // ignore heuristic controls on inlining if (callee_method->should_inline()) { - set_msg("force inline by CompilerOracle"); + set_msg("force inline by CompileCommand"); return false; } if (callee_method->should_not_inline()) { - set_msg("disallowed by CompilerOracle"); + set_msg("disallowed by CompileCommand"); return true; } @@ -470,11 +470,6 @@ } } } - // We will attempt to see if a class/field/etc got properly loaded. If it - // did not, it may attempt to throw an exception during our probing. Catch - // and ignore such exceptions and do not attempt to compile the method. - if( callee_method->should_exclude() ) return false; - return true; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/c2_globals.hpp --- a/hotspot/src/share/vm/opto/c2_globals.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/c2_globals.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -69,43 +69,32 @@ develop(bool, StressGCM, false, \ "Randomize instruction scheduling in GCM") \ \ - notproduct(intx, CompileZapFirst, 0, \ - "If +ZapDeadCompiledLocals, " \ - "skip this many before compiling in zap calls") \ - \ - notproduct(intx, CompileZapLast, -1, \ - "If +ZapDeadCompiledLocals, " \ - "compile this many after skipping (incl. skip count, -1 = all)") \ - \ - notproduct(intx, ZapDeadCompiledLocalsFirst, 0, \ - "If +ZapDeadCompiledLocals, " \ - "skip this many before really doing it") \ - \ - notproduct(intx, ZapDeadCompiledLocalsLast, -1, \ - "If +ZapDeadCompiledLocals, " \ - "do this many after skipping (incl. skip count, -1 = all)") \ - \ develop(intx, OptoPrologueNops, 0, \ "Insert this many extra nop instructions " \ "in the prologue of every nmethod") \ + range(0, 128) \ \ product_pd(intx, InteriorEntryAlignment, \ "Code alignment for interior entry points " \ "in generated code (in bytes)") \ + constraint(InteriorEntryAlignmentConstraintFunc, AfterErgo) \ \ product(intx, MaxLoopPad, (OptoLoopAlignment-1), \ "Align a loop if padding size in bytes is less or equal to this " \ "value") \ + range(0, max_jint) \ \ product(intx, MaxVectorSize, 64, \ "Max vector size in bytes, " \ "actual size could be less depending on elements type") \ + range(0, max_jint) \ \ product(bool, AlignVector, true, \ "Perform vector store/load alignment in loop") \ \ product(intx, NumberOfLoopInstrToAlign, 4, \ "Number of first instructions in a loop to align") \ + range(0, max_jint) \ \ notproduct(intx, IndexSetWatch, 0, \ "Trace all operations on this IndexSet (-1 means all, 0 none)") \ @@ -113,9 +102,11 @@ \ develop(intx, OptoNodeListSize, 4, \ "Starting allocation size of Node_List data structures") \ + range(0, max_jint) \ \ develop(intx, OptoBlockListSize, 8, \ "Starting allocation size of Block_List data structures") \ + range(0, max_jint) \ \ develop(intx, OptoPeepholeAt, -1, \ "Apply peephole optimizations to this peephole rule") \ @@ -189,9 +180,11 @@ \ product_pd(intx, LoopUnrollLimit, \ "Unroll loop bodies with node count less than this") \ + range(0, max_jint / 4) \ \ product(intx, LoopMaxUnroll, 16, \ "Maximum number of unrolls for main loop") \ + range(0, max_jint) \ \ product(bool, SuperWordLoopUnrollAnalysis, false, \ "Map number of unrolls for main loop via " \ @@ -203,16 +196,19 @@ product(intx, LoopUnrollMin, 4, \ "Minimum number of unroll loop bodies before checking progress" \ "of rounds of unroll,optimize,..") \ + range(0, max_jint) \ \ develop(intx, UnrollLimitForProfileCheck, 1, \ "Don't use profile_trip_cnt() to restrict unrolling until " \ "unrolling would push the number of unrolled iterations above " \ "UnrollLimitForProfileCheck. A higher value allows more " \ "unrolling. Zero acts as a very large value." ) \ + range(0, max_intx) \ \ product(intx, MultiArrayExpandLimit, 6, \ "Maximum number of individual allocations in an inline-expanded " \ "multianewarray instruction") \ + range(0, max_jint) \ \ notproduct(bool, TraceProfileTripCount, false, \ "Trace profile loop trip count information") \ @@ -259,6 +255,7 @@ \ product(intx, TrackedInitializationLimit, 50, \ "When initializing fields, track up to this many words") \ + range(0, 65535) \ \ product(bool, ReduceFieldZeroing, true, \ "When initializing fields, try to avoid needless zeroing") \ @@ -293,9 +290,11 @@ \ develop_pd(intx, FLOATPRESSURE, \ "Number of float LRG's that constitute high register pressure") \ + range(0, max_jint) \ \ develop_pd(intx, INTPRESSURE, \ "Number of integer LRG's that constitute high register pressure") \ + range(0, max_jint) \ \ notproduct(bool, TraceOptoPipelining, false, \ "Trace pipelining information") \ @@ -306,11 +305,15 @@ product_pd(bool, OptoScheduling, \ "Instruction Scheduling after register allocation") \ \ + product_pd(bool, OptoRegScheduling, \ + "Instruction Scheduling before register allocation for pressure") \ + \ product(bool, PartialPeelLoop, true, \ "Partial peel (rotate) loops") \ \ product(intx, PartialPeelNewPhiDelta, 0, \ "Additional phis that can be created by partial peeling") \ + range(0, max_jint) \ \ notproduct(bool, TracePartialPeeling, false, \ "Trace partial peeling (loop rotation) information") \ @@ -339,6 +342,9 @@ product(bool, SuperWordReductions, true, \ "Enable reductions support in superword.") \ \ + product(bool, DoReserveCopyInSuperWord, true, \ + "Create reserve copy of graph in SuperWord.") \ + \ notproduct(bool, TraceSuperWord, false, \ "Trace superword transforms") \ \ @@ -350,6 +356,7 @@ \ product_pd(intx, ConditionalMoveLimit, \ "Limit of ops to make speculative when using CMOVE") \ + range(0, max_jint) \ \ /* Set BranchOnRegister == false. See 4965987. */ \ product(bool, BranchOnRegister, false, \ @@ -374,6 +381,7 @@ \ develop(intx, PrintIdealGraphPort, 4444, \ "Ideal graph printer to network port") \ + range(0, SHRT_MAX) \ \ notproduct(ccstr, PrintIdealGraphAddress, "127.0.0.1", \ "IP address to connect to visualizer") \ @@ -402,50 +410,64 @@ develop(intx, ImplicitNullCheckThreshold, 3, \ "Don't do implicit null checks if NPE's in a method exceeds " \ "limit") \ + range(0, max_jint) \ \ product(intx, LoopOptsCount, 43, \ "Set level of loop optimization for tier 1 compiles") \ + range(5, 43) \ \ /* controls for heat-based inlining */ \ \ develop(intx, NodeCountInliningCutoff, 18000, \ "If parser node generation exceeds limit stop inlining") \ + range(0, max_jint) \ \ develop(intx, NodeCountInliningStep, 1000, \ "Target size of warm calls inlined between optimization passes") \ + range(0, max_jint) \ \ develop(bool, InlineWarmCalls, false, \ "Use a heat-based priority queue to govern inlining") \ \ develop(intx, HotCallCountThreshold, 999999, \ "large numbers of calls (per method invocation) force hotness") \ + range(0, max_intx) \ \ develop(intx, HotCallProfitThreshold, 999999, \ "highly profitable inlining opportunities force hotness") \ + range(0, max_intx) \ \ develop(intx, HotCallTrivialWork, -1, \ "trivial execution time (no larger than this) forces hotness") \ + range(-1, max_intx) \ \ develop(intx, HotCallTrivialSize, -1, \ "trivial methods (no larger than this) force calls to be hot") \ + range(-1, max_intx) \ \ develop(intx, WarmCallMinCount, -1, \ "number of calls (per method invocation) to enable inlining") \ + range(-1, max_intx) \ \ develop(intx, WarmCallMinProfit, -1, \ "number of calls (per method invocation) to enable inlining") \ + range(-1, max_intx) \ \ develop(intx, WarmCallMaxWork, 999999, \ "execution time of the largest inlinable method") \ + range(0, max_intx) \ \ develop(intx, WarmCallMaxSize, 999999, \ "size of the largest inlinable method") \ + range(0, max_intx) \ \ product(intx, MaxNodeLimit, 80000, \ "Maximum number of nodes") \ + range(1000, max_jint / 3) \ \ product(intx, NodeLimitFudgeFactor, 2000, \ "Fudge Factor for certain optimizations") \ + constraint(NodeLimitFudgeFactorConstraintFunc, AfterErgo) \ \ product(bool, UseJumpTables, true, \ "Use JumpTables instead of a binary search tree for switches") \ @@ -455,12 +477,15 @@ \ product_pd(intx, MinJumpTableSize, \ "Minimum number of targets in a generated jump table") \ + range(0, max_intx) \ \ product(intx, MaxJumpTableSize, 65000, \ "Maximum number of targets in a generated jump table") \ + range(0, max_intx) \ \ product(intx, MaxJumpTableSparseness, 5, \ "Maximum sparseness for jumptables") \ + range(0, max_intx / 4) \ \ product(bool, EliminateLocks, true, \ "Coarsen locks when possible") \ @@ -488,6 +513,7 @@ \ product(intx, AutoBoxCacheMax, 128, \ "Sets max value cached by the java.lang.Integer autobox cache") \ + range(0, max_jint) \ \ experimental(bool, AggressiveUnboxing, false, \ "Control optimizations for aggressive boxing elimination") \ @@ -500,6 +526,7 @@ \ product(double, EscapeAnalysisTimeout, 20. DEBUG_ONLY(+40.), \ "Abort EA when it reaches time limit (in sec)") \ + range(0, DBL_MAX) \ \ develop(bool, ExitEscapeAnalysisOnTimeout, true, \ "Exit or throw assert in EA when it reaches time limit") \ @@ -515,6 +542,7 @@ \ product(intx, EliminateAllocationArraySizeLimit, 64, \ "Array size (number of elements) limit for scalar replacement") \ + range(0, max_jint) \ \ product(bool, OptimizePtrCompare, true, \ "Use escape analysis to optimize pointers compare") \ @@ -536,12 +564,15 @@ \ product(intx, ValueSearchLimit, 1000, \ "Recursion limit in PhaseMacroExpand::value_from_mem_phi") \ + range(0, max_jint) \ \ product(intx, MaxLabelRootDepth, 1100, \ "Maximum times call Label_Root to prevent stack overflow") \ + range(100, max_jint) \ \ diagnostic(intx, DominatorSearchLimit, 1000, \ "Iterations limit in Node::dominates") \ + range(0, max_jint) \ \ product(bool, BlockLayoutByFrequency, true, \ "Use edge frequencies to drive block ordering") \ @@ -651,6 +682,7 @@ \ develop(intx, FreqCountInvocations, 1, \ "Scaling factor for branch frequencies (deprecated)") \ + range(1, max_intx) \ \ product(intx, AliasLevel, 3, \ "0 for no aliasing, 1 for oop/field/static/array split, " \ @@ -669,6 +701,7 @@ \ product(intx, LiveNodeCountInliningCutoff, 40000, \ "max number of live nodes in a method") \ + range(0, max_juint / 8) \ \ diagnostic(bool, OptimizeExpensiveOps, true, \ "Find best control for expensive operations") \ @@ -705,6 +738,7 @@ product(intx, ArrayCopyLoadStoreMaxElem, 8, \ "Maximum number of arraycopy elements inlined as a sequence of" \ "loads/stores") \ + range(0, max_intx) \ \ develop(bool, StressArrayCopyMacroNode, false, \ "Perform ArrayCopy load/store replacement during IGVN only") diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/callGenerator.cpp --- a/hotspot/src/share/vm/opto/callGenerator.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/callGenerator.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -895,7 +895,7 @@ break; default: - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); break; } return NULL; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/callnode.hpp --- a/hotspot/src/share/vm/opto/callnode.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/callnode.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -907,6 +907,18 @@ // Convenience for initialization->maybe_set_complete(phase) bool maybe_set_complete(PhaseGVN* phase); + + // Return true if allocation doesn't escape thread, its escape state + // needs be noEscape or ArgEscape. InitializeNode._does_not_escape + // is true when its allocation's escape state is noEscape or + // ArgEscape. In case allocation's InitializeNode is NULL, check + // AlllocateNode._is_non_escaping flag. + // AlllocateNode._is_non_escaping is true when its escape state is + // noEscape. + bool does_not_escape_thread() { + InitializeNode* init = NULL; + return _is_non_escaping || (((init = initialization()) != NULL) && init->does_not_escape()); + } }; //------------------------------AllocateArray--------------------------------- diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/castnode.cpp --- a/hotspot/src/share/vm/opto/castnode.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/castnode.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -129,7 +129,7 @@ } else { stringStream ss; test.dump_on(&ss); - fatal(err_msg_res("unexpected comparison %s", ss.as_string())); + fatal("unexpected comparison %s", ss.as_string()); } int lo_int = (int)lo_long; int hi_int = (int)hi_long; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/chaitin.cpp --- a/hotspot/src/share/vm/opto/chaitin.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/chaitin.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -191,7 +191,7 @@ return next; } -PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher) +PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher, bool scheduling_info_generated) : PhaseRegAlloc(unique, cfg, matcher, #ifndef PRODUCT print_chaitin_statistics @@ -205,6 +205,11 @@ , _spilled_twice(Thread::current()->resource_area()) , _lo_degree(0), _lo_stk_degree(0), _hi_degree(0), _simplified(0) , _oldphi(unique) + , _scheduling_info_generated(scheduling_info_generated) + , _sched_int_pressure(0, INTPRESSURE) + , _sched_float_pressure(0, FLOATPRESSURE) + , _scratch_int_pressure(0, INTPRESSURE) + , _scratch_float_pressure(0, FLOATPRESSURE) #ifndef PRODUCT , _trace_spilling(TraceSpilling || C->method_has_option("TraceSpilling")) #endif @@ -350,7 +355,7 @@ // all copy-related live ranges low and then using the max copy-related // live range as a cut-off for LIVE and the IFG. In other words, I can // build a subset of LIVE and IFG just for copies. - PhaseLive live(_cfg, _lrg_map.names(), &live_arena); + PhaseLive live(_cfg, _lrg_map.names(), &live_arena, false); // Need IFG for coalescing and coloring PhaseIFG ifg(&live_arena); @@ -690,6 +695,29 @@ _lrg_map.reset_uf_map(lr_counter); } +void PhaseChaitin::mark_ssa() { + // Use ssa names to populate the live range maps or if no mask + // is available, use the 0 entry. + uint max_idx = 0; + for ( uint i = 0; i < _cfg.number_of_blocks(); i++ ) { + Block* block = _cfg.get_block(i); + uint cnt = block->number_of_nodes(); + + // Handle all the normal Nodes in the block + for ( uint j = 0; j < cnt; j++ ) { + Node *n = block->get_node(j); + // Pre-color to the zero live range, or pick virtual register + const RegMask &rm = n->out_RegMask(); + _lrg_map.map(n->_idx, rm.is_NotEmpty() ? n->_idx : 0); + max_idx = (n->_idx > max_idx) ? n->_idx : max_idx; + } + } + _lrg_map.set_max_lrg_id(max_idx+1); + + // Reset the Union-Find mapping to be identity + _lrg_map.reset_uf_map(max_idx+1); +} + // Gather LiveRanGe information, including register masks. Modification of // cisc spillable in_RegMasks should not be done before AggressiveCoalesce. @@ -707,7 +735,9 @@ for (uint j = 1; j < block->number_of_nodes(); j++) { Node* n = block->get_node(j); uint input_edge_start =1; // Skip control most nodes + bool is_machine_node = false; if (n->is_Mach()) { + is_machine_node = true; input_edge_start = n->as_Mach()->oper_input_base(); } uint idx = n->is_Copy(); @@ -929,6 +959,7 @@ // Convert operand number to edge index number inp = n->as_Mach()->operand_index(inp); } + // Prepare register mask for each input for( uint k = input_edge_start; k < cnt; k++ ) { uint vreg = _lrg_map.live_range_id(n->in(k)); @@ -948,6 +979,12 @@ n->as_Mach()->use_cisc_RegMask(); } + if (is_machine_node && _scheduling_info_generated) { + MachNode* cur_node = n->as_Mach(); + // this is cleaned up by register allocation + if (k >= cur_node->num_opnds()) continue; + } + LRG &lrg = lrgs(vreg); // // Testing for floating point code shape // Node *test = n->in(k); @@ -989,7 +1026,7 @@ // double can interfere with TWO aligned pairs, or effectively // FOUR registers! #ifdef ASSERT - if (is_vect) { + if (is_vect && !_scheduling_info_generated) { if (lrg.num_regs() != 0) { assert(lrgmask.is_aligned_sets(lrg.num_regs()), "vector should be aligned"); assert(!lrg._fat_proj, "sanity"); @@ -1733,7 +1770,7 @@ // Check for AddP-related opcodes if (!derived->is_Phi()) { - assert(derived->as_Mach()->ideal_Opcode() == Op_AddP, err_msg_res("but is: %s", derived->Name())); + assert(derived->as_Mach()->ideal_Opcode() == Op_AddP, "but is: %s", derived->Name()); Node *base = derived->in(AddPNode::Base); derived_base_map[derived->_idx] = base; return base; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/chaitin.hpp --- a/hotspot/src/share/vm/opto/chaitin.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/chaitin.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -399,7 +399,6 @@ int _trip_cnt; int _alternate; - LRG &lrgs(uint idx) const { return _ifg->lrgs(idx); } PhaseLive *_live; // Liveness, used in the interference graph PhaseIFG *_ifg; // Interference graph (for original chunk) Node_List **_lrg_nodes; // Array of node; lists for lrgs which spill @@ -464,16 +463,28 @@ #endif public: - PhaseChaitin( uint unique, PhaseCFG &cfg, Matcher &matcher ); + PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher, bool track_liveout_pressure); ~PhaseChaitin() {} LiveRangeMap _lrg_map; + LRG &lrgs(uint idx) const { return _ifg->lrgs(idx); } + // Do all the real work of allocate void Register_Allocate(); float high_frequency_lrg() const { return _high_frequency_lrg; } + // Used when scheduling info generated, not in general register allocation + bool _scheduling_info_generated; + + void set_ifg(PhaseIFG &ifg) { _ifg = &ifg; } + void set_live(PhaseLive &live) { _live = &live; } + PhaseLive* get_live() { return _live; } + + // Populate the live range maps with ssa info for scheduling + void mark_ssa(); + #ifndef PRODUCT bool trace_spilling() const { return _trace_spilling; } #endif @@ -516,7 +527,11 @@ uint _final_pressure; // number of live ranges that constitute high register pressure - const uint _high_pressure_limit; + uint _high_pressure_limit; + + // initial pressure observed + uint _start_pressure; + public: // lower the register pressure and look for a low to high pressure @@ -537,6 +552,14 @@ } } + void init(int limit) { + _current_pressure = 0; + _high_pressure_index = 0; + _final_pressure = 0; + _high_pressure_limit = limit; + _start_pressure = 0; + } + uint high_pressure_index() const { return _high_pressure_index; } @@ -545,6 +568,10 @@ return _final_pressure; } + uint start_pressure() const { + return _start_pressure; + } + uint current_pressure() const { return _current_pressure; } @@ -561,6 +588,15 @@ _high_pressure_index = 0; } + void set_start_pressure(int value) { + _start_pressure = value; + _final_pressure = value; + } + + void set_current_pressure(int value) { + _current_pressure = value; + } + void check_pressure_at_fatproj(uint fatproj_location, RegMask& fatproj_mask) { // this pressure is only valid at this instruction, i.e. we don't need to lower // the register pressure since the fat proj was never live before (going backwards) @@ -577,14 +613,13 @@ } Pressure(uint high_pressure_index, uint high_pressure_limit) - : _current_pressure(0) - , _high_pressure_index(high_pressure_index) - , _high_pressure_limit(high_pressure_limit) - , _final_pressure(0) {} + : _current_pressure(0) + , _high_pressure_index(high_pressure_index) + , _final_pressure(0) + , _high_pressure_limit(high_pressure_limit) + , _start_pressure(0) {} }; - void lower_pressure(Block* b, uint location, LRG& lrg, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure); - void raise_pressure(Block* b, LRG& lrg, Pressure& int_pressure, Pressure& float_pressure); void check_for_high_pressure_transition_at_fatproj(uint& block_reg_pressure, uint location, LRG& lrg, Pressure& pressure, const int op_regtype); void add_input_to_liveout(Block* b, Node* n, IndexSet* liveout, double cost, Pressure& int_pressure, Pressure& float_pressure); void compute_initial_block_pressure(Block* b, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure, double cost); @@ -600,10 +635,25 @@ // acceptable register sets do not overlap, then they do not interfere. uint build_ifg_physical( ResourceArea *a ); +public: // Gather LiveRanGe information, including register masks and base pointer/ // derived pointer relationships. void gather_lrg_masks( bool mod_cisc_masks ); + // user visible pressure variables for scheduling + Pressure _sched_int_pressure; + Pressure _sched_float_pressure; + Pressure _scratch_int_pressure; + Pressure _scratch_float_pressure; + + // Pressure functions for user context + void lower_pressure(Block* b, uint location, LRG& lrg, IndexSet* liveout, Pressure& int_pressure, Pressure& float_pressure); + void raise_pressure(Block* b, LRG& lrg, Pressure& int_pressure, Pressure& float_pressure); + void compute_entry_block_pressure(Block* b); + void compute_exit_block_pressure(Block* b); + void print_pressure_info(Pressure& pressure, const char *str); + +private: // Force the bases of derived pointers to be alive at GC points. bool stretch_base_pointer_live_ranges( ResourceArea *a ); // Helper to stretch above; recursively discover the base Node for diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/classes.hpp --- a/hotspot/src/share/vm/opto/classes.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/classes.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -131,7 +131,6 @@ macro(EncodeISOArray) macro(EncodeP) macro(EncodePKlass) -macro(ExpD) macro(FastLock) macro(FastUnlock) macro(Goto) @@ -290,6 +289,10 @@ macro(MulReductionVD) macro(DivVF) macro(DivVD) +macro(AbsVF) +macro(AbsVD) +macro(NegVF) +macro(NegVD) macro(SqrtVD) macro(LShiftCntV) macro(RShiftCntV) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/compile.cpp --- a/hotspot/src/share/vm/opto/compile.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/compile.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -317,7 +317,7 @@ // Use breadth-first pass that records state in a Unique_Node_List, // recursive traversal is slower. void Compile::identify_useful_nodes(Unique_Node_List &useful) { - int estimated_worklist_size = unique(); + int estimated_worklist_size = live_nodes(); useful.map( estimated_worklist_size, NULL ); // preallocate space // Initialize worklist @@ -596,7 +596,7 @@ n->emit(buf, this->regalloc()); // Emitting into the scratch buffer should not fail - assert (!failing(), err_msg_res("Must not have pending failure. Reason is: %s", failure_reason())); + assert (!failing(), "Must not have pending failure. Reason is: %s", failure_reason()); if (is_branch) // Restore label. n->as_MachBranch()->label_set(saveL, save_bnum); @@ -1189,7 +1189,7 @@ * the ideal graph. */ StartNode* Compile::start() const { - assert (!failing(), err_msg_res("Must not have pending failure. Reason is: %s", failure_reason())); + assert (!failing(), "Must not have pending failure. Reason is: %s", failure_reason()); for (DUIterator_Fast imax, i = root()->fast_outs(imax); i < imax; i++) { Node* start = root()->fast_out(i); if (start->is_Start()) { @@ -2254,6 +2254,8 @@ if (failing()) return; } } + // Ensure that major progress is now clear + C->clear_major_progress(); { // Verify that all previous optimizations produced a valid graph @@ -2336,7 +2338,7 @@ debug_only( cfg.verify(); ) } - PhaseChaitin regalloc(unique(), cfg, matcher); + PhaseChaitin regalloc(unique(), cfg, matcher, false); _regalloc = ®alloc; { TracePhase tp("regalloc", &timers[_t_registerAllocation]); @@ -3314,7 +3316,7 @@ Final_Reshape_Counts frc; // Visit everybody reachable! - // Allocate stack of size C->unique()/2 to avoid frequent realloc + // Allocate stack of size C->live_nodes()/2 to avoid frequent realloc Node_Stack nstack(live_nodes() >> 1); final_graph_reshaping_walk(nstack, root(), frc); @@ -3796,7 +3798,7 @@ } assert(constant_addr, "consts section too small"); assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), - err_msg_res("must be: %d == %d", (int) (constant_addr - _masm.code()->consts()->start()), (int)(con.offset()))); + "must be: %d == %d", (int) (constant_addr - _masm.code()->consts()->start()), (int)(con.offset())); } } @@ -3842,7 +3844,7 @@ case T_OBJECT: case T_ADDRESS: value.l = (jobject) oper->constant(); break; case T_METADATA: return add((Metadata*)oper->constant()); break; - default: guarantee(false, err_msg_res("unhandled type: %s", type2name(type))); + default: guarantee(false, "unhandled type: %s", type2name(type)); } return add(n, type, value); } @@ -3864,7 +3866,7 @@ if (Compile::current()->in_scratch_emit_size()) return; assert(labels.is_nonempty(), "must be"); - assert((uint) labels.length() == n->outcnt(), err_msg_res("must be equal: %d == %d", labels.length(), n->outcnt())); + assert((uint) labels.length() == n->outcnt(), "must be equal: %d == %d", labels.length(), n->outcnt()); // Since MachConstantNode::constant_offset() also contains // table_base_offset() we need to subtract the table_base_offset() @@ -3876,7 +3878,7 @@ for (uint i = 0; i < n->outcnt(); i++) { address* constant_addr = &jump_table_base[i]; - assert(*constant_addr == (((address) n) + i), err_msg_res("all jump-table entries must contain adjusted node pointer: " INTPTR_FORMAT " == " INTPTR_FORMAT, p2i(*constant_addr), p2i(((address) n) + i))); + assert(*constant_addr == (((address) n) + i), "all jump-table entries must contain adjusted node pointer: " INTPTR_FORMAT " == " INTPTR_FORMAT, p2i(*constant_addr), p2i(((address) n) + i)); *constant_addr = cb.consts()->target(*labels.at(i), (address) constant_addr); cb.consts()->relocate((address) constant_addr, relocInfo::internal_word_type); } @@ -4135,7 +4137,7 @@ if (n1->Opcode() < n2->Opcode()) return -1; else if (n1->Opcode() > n2->Opcode()) return 1; - assert(n1->req() == n2->req(), err_msg_res("can't compare %s nodes: n1->req() = %d, n2->req() = %d", NodeClassNames[n1->Opcode()], n1->req(), n2->req())); + assert(n1->req() == n2->req(), "can't compare %s nodes: n1->req() = %d, n2->req() = %d", NodeClassNames[n1->Opcode()], n1->req(), n2->req()); for (uint i = 1; i < n1->req(); i++) { if (n1->in(i) < n2->in(i)) return -1; else if (n1->in(i) > n2->in(i)) return 1; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/compile.hpp --- a/hotspot/src/share/vm/opto/compile.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/compile.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -843,7 +843,7 @@ } uint live_nodes() const { int val = _unique - _dead_node_count; - assert (val >= 0, err_msg_res("number of tracked dead nodes %d more than created nodes %d", _unique, _dead_node_count)); + assert (val >= 0, "number of tracked dead nodes %d more than created nodes %d", _unique, _dead_node_count); return (uint) val; } #ifdef ASSERT @@ -1208,12 +1208,6 @@ // Compute the name of old_SP. See .ad for frame layout. OptoReg::Name compute_old_SP(); -#ifdef ENABLE_ZAP_DEAD_LOCALS - static bool is_node_getting_a_safepoint(Node*); - void Insert_zap_nodes(); - Node* call_zap_node(MachSafePointNode* n, int block_no); -#endif - private: // Phase control: void Init(int aliaslevel); // Prepare for a single compilation diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/doCall.cpp --- a/hotspot/src/share/vm/opto/doCall.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/doCall.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -599,9 +599,9 @@ pop_node(rt); // whatever it was, pop it } else if (rt == T_INT || is_subword_type(rt)) { // Nothing. These cases are handled in lambda form bytecode. - assert(ct == T_INT || is_subword_type(ct), err_msg_res("must match: rt=%s, ct=%s", type2name(rt), type2name(ct))); + assert(ct == T_INT || is_subword_type(ct), "must match: rt=%s, ct=%s", type2name(rt), type2name(ct)); } else if (rt == T_OBJECT || rt == T_ARRAY) { - assert(ct == T_OBJECT || ct == T_ARRAY, err_msg_res("rt=%s, ct=%s", type2name(rt), type2name(ct))); + assert(ct == T_OBJECT || ct == T_ARRAY, "rt=%s, ct=%s", type2name(rt), type2name(ct)); if (ctype->is_loaded()) { const TypeOopPtr* arg_type = TypeOopPtr::make_from_klass(rtype->as_klass()); const Type* sig_type = TypeOopPtr::make_from_klass(ctype->as_klass()); @@ -612,7 +612,7 @@ } } } else { - assert(rt == ct, err_msg_res("unexpected mismatch: rt=%s, ct=%s", type2name(rt), type2name(ct))); + assert(rt == ct, "unexpected mismatch: rt=%s, ct=%s", type2name(rt), type2name(ct)); // push a zero; it's better than getting an oop/int mismatch pop_node(rt); Node* retnode = zerocon(ct); @@ -628,7 +628,7 @@ // can appear to be "loaded" by different loaders (depending on // the accessing class). assert(!rtype->is_loaded() || !ctype->is_loaded() || rtype == ctype, - err_msg_res("mismatched return types: rtype=%s, ctype=%s", rtype->name(), ctype->name())); + "mismatched return types: rtype=%s, ctype=%s", rtype->name(), ctype->name()); } // If the return type of the method is not loaded, assert that the diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/domgraph.cpp --- a/hotspot/src/share/vm/opto/domgraph.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/domgraph.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -506,7 +506,7 @@ // Perform DFS search. Setup 'vertex' as DFS to vertex mapping. Setup // 'semi' as vertex to DFS mapping. Set 'parent' to DFS parent. int NTarjan::DFS( NTarjan *ntarjan, VectorSet &visited, PhaseIdealLoop *pil, uint *dfsorder) { - // Allocate stack of size C->unique()/8 to avoid frequent realloc + // Allocate stack of size C->live_nodes()/8 to avoid frequent realloc GrowableArray dfstack(pil->C->live_nodes() >> 3); Node *b = pil->C->root(); int dfsnum = 1; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/escape.cpp --- a/hotspot/src/share/vm/opto/escape.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/escape.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -982,7 +982,7 @@ strcmp(call->as_CallLeaf()->_name, "montgomery_square") == 0) ))) { call->dump(); - fatal(err_msg_res("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name)); + fatal("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name); } #endif // Always process arraycopy's destination object since @@ -1201,8 +1201,8 @@ C->log()->text("%s", timeout ? "time" : "iterations"); C->log()->end_elem(" limit'"); } - assert(ExitEscapeAnalysisOnTimeout, err_msg_res("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d", - time.seconds(), iterations, nodes_size(), ptnodes_worklist.length())); + assert(ExitEscapeAnalysisOnTimeout, "infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d", + time.seconds(), iterations, nodes_size(), ptnodes_worklist.length()); // Possible infinite build_connection_graph loop, // bailout (no changes to ideal graph were made). return false; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/gcm.cpp --- a/hotspot/src/share/vm/opto/gcm.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/gcm.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -34,6 +34,7 @@ #include "opto/phaseX.hpp" #include "opto/rootnode.hpp" #include "opto/runtime.hpp" +#include "opto/chaitin.hpp" #include "runtime/deoptimization.hpp" // Portions of code courtesy of Clifford Click @@ -1363,6 +1364,44 @@ } } + bool block_size_threshold_ok = false; + intptr_t *recalc_pressure_nodes = NULL; + if (OptoRegScheduling) { + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); + if (block->number_of_nodes() > 10) { + block_size_threshold_ok = true; + break; + } + } + } + + // Enabling the scheduler for register pressure plus finding blocks of size to schedule for it + // is key to enabling this feature. + PhaseChaitin regalloc(C->unique(), *this, _matcher, true); + ResourceArea live_arena; // Arena for liveness + ResourceMark rm_live(&live_arena); + PhaseLive live(*this, regalloc._lrg_map.names(), &live_arena, true); + PhaseIFG ifg(&live_arena); + if (OptoRegScheduling && block_size_threshold_ok) { + regalloc.mark_ssa(); + Compile::TracePhase tp("computeLive", &timers[_t_computeLive]); + rm_live.reset_to_mark(); // Reclaim working storage + IndexSet::reset_memory(C, &live_arena); + uint node_size = regalloc._lrg_map.max_lrg_id(); + ifg.init(node_size); // Empty IFG + regalloc.set_ifg(ifg); + regalloc.set_live(live); + regalloc.gather_lrg_masks(false); // Collect LRG masks + live.compute(node_size); // Compute liveness + + recalc_pressure_nodes = NEW_RESOURCE_ARRAY(intptr_t, node_size); + for (uint i = 0; i < node_size; i++) { + recalc_pressure_nodes[i] = 0; + } + } + _regalloc = ®alloc; + #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print("\n---- Start Local Scheduling ----\n"); @@ -1375,13 +1414,15 @@ visited.Clear(); for (uint i = 0; i < number_of_blocks(); i++) { Block* block = get_block(i); - if (!schedule_local(block, ready_cnt, visited)) { + if (!schedule_local(block, ready_cnt, visited, recalc_pressure_nodes)) { if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) { C->record_method_not_compilable("local schedule failed"); } + _regalloc = NULL; return; } } + _regalloc = NULL; // If we inserted any instructions between a Call and his CatchNode, // clone the instructions on all paths below the Catch. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1251,7 +1251,7 @@ } default: - fatal(err_msg_res("unexpected type: %s", type2name(type))); + fatal("unexpected type: %s", type2name(type)); } assert(chk != NULL, "sanity check"); chk = _gvn.transform(chk); @@ -1950,8 +1950,8 @@ // the current bytecode. int inputs, ignored_depth; if (compute_stack_effects(inputs, ignored_depth)) { - assert(sp() >= inputs, err_msg_res("must have enough JVMS stack to execute %s: sp=%d, inputs=%d", - Bytecodes::name(java_bc()), sp(), inputs)); + assert(sp() >= inputs, "must have enough JVMS stack to execute %s: sp=%d, inputs=%d", + Bytecodes::name(java_bc()), sp(), inputs); } } #endif @@ -1987,7 +1987,7 @@ case Deoptimization::Action_make_not_compilable: break; default: - fatal(err_msg_res("unknown action %d: %s", action, Deoptimization::trap_action_name(action))); + fatal("unknown action %d: %s", action, Deoptimization::trap_action_name(action)); break; #endif } @@ -2509,7 +2509,7 @@ switch(bt) { case T_INT: cmp = new CmpINode(in1, in2); break; case T_ADDRESS: cmp = new CmpPNode(in1, in2); break; - default: fatal(err_msg("unexpected comparison type %s", type2name(bt))); + default: fatal("unexpected comparison type %s", type2name(bt)); } gvn->transform(cmp); Node* bol = gvn->transform(new BoolNode(cmp, test)); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/graphKit.hpp --- a/hotspot/src/share/vm/opto/graphKit.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/graphKit.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -136,7 +136,7 @@ _bci = jvms->bci(); _method = jvms->has_method() ? jvms->method() : NULL; } void set_map(SafePointNode* m) { _map = m; debug_only(verify_map()); } - void set_sp(int sp) { assert(sp >= 0, err_msg_res("sp must be non-negative: %d", sp)); _sp = sp; } + void set_sp(int sp) { assert(sp >= 0, "sp must be non-negative: %d", sp); _sp = sp; } void clean_stack(int from_sp); // clear garbage beyond from_sp to top void inc_sp(int i) { set_sp(sp() + i); } @@ -354,12 +354,12 @@ } Node* zero_check_int(Node* value) { assert(value->bottom_type()->basic_type() == T_INT, - err_msg_res("wrong type: %s", type2name(value->bottom_type()->basic_type()))); + "wrong type: %s", type2name(value->bottom_type()->basic_type())); return null_check_common(value, T_INT); } Node* zero_check_long(Node* value) { assert(value->bottom_type()->basic_type() == T_LONG, - err_msg_res("wrong type: %s", type2name(value->bottom_type()->basic_type()))); + "wrong type: %s", type2name(value->bottom_type()->basic_type())); return null_check_common(value, T_LONG); } // Throw an uncommon trap if a given value is __not__ null. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/idealGraphPrinter.cpp --- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -157,8 +157,8 @@ } else { // It would be nice if we could shut down cleanly but it should // be an error if we can't connect to the visualizer. - fatal(err_msg_res("Couldn't connect to visualizer at %s:" INTX_FORMAT, - PrintIdealGraphAddress, PrintIdealGraphPort)); + fatal("Couldn't connect to visualizer at %s:" INTX_FORMAT, + PrintIdealGraphAddress, PrintIdealGraphPort); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/ifg.cpp --- a/hotspot/src/share/vm/opto/ifg.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/ifg.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -439,8 +439,10 @@ } } } - assert(int_pressure.current_pressure() == count_int_pressure(liveout), "the int pressure is incorrect"); - assert(float_pressure.current_pressure() == count_float_pressure(liveout), "the float pressure is incorrect"); + if (_scheduling_info_generated == false) { + assert(int_pressure.current_pressure() == count_int_pressure(liveout), "the int pressure is incorrect"); + assert(float_pressure.current_pressure() == count_float_pressure(liveout), "the float pressure is incorrect"); + } } /* Go to the first non-phi index in a block */ @@ -518,6 +520,58 @@ } /* +* Computes the entry register pressure of a block, looking at all live +* ranges in the livein. The register pressure is computed for both float +* and int/pointer registers. +*/ +void PhaseChaitin::compute_entry_block_pressure(Block* b) { + IndexSet* livein = _live->livein(b); + IndexSetIterator elements(livein); + uint lid = elements.next(); + while (lid != 0) { + LRG& lrg = lrgs(lid); + raise_pressure(b, lrg, _sched_int_pressure, _sched_float_pressure); + lid = elements.next(); + } + // Now check phis for locally defined inputs + for (uint j = 0; j < b->number_of_nodes(); j++) { + Node* n = b->get_node(j); + if (n->is_Phi()) { + for (uint k = 1; k < n->req(); k++) { + Node* phi_in = n->in(k); + // Because we are talking about phis, raise register pressure once for each + // instance of a phi to account for a single value + if (_cfg.get_block_for_node(phi_in) == b) { + LRG& lrg = lrgs(phi_in->_idx); + raise_pressure(b, lrg, _sched_int_pressure, _sched_float_pressure); + break; + } + } + } + } + _sched_int_pressure.set_start_pressure(_sched_int_pressure.current_pressure()); + _sched_float_pressure.set_start_pressure(_sched_float_pressure.current_pressure()); +} + +/* +* Computes the exit register pressure of a block, looking at all live +* ranges in the liveout. The register pressure is computed for both float +* and int/pointer registers. +*/ +void PhaseChaitin::compute_exit_block_pressure(Block* b) { + IndexSet* livein = _live->live(b); + IndexSetIterator elements(livein); + _sched_int_pressure.set_current_pressure(0); + _sched_float_pressure.set_current_pressure(0); + uint lid = elements.next(); + while (lid != 0) { + LRG& lrg = lrgs(lid); + raise_pressure(b, lrg, _sched_int_pressure, _sched_float_pressure); + lid = elements.next(); + } +} + +/* * Remove dead node if it's not used. * We only remove projection nodes if the node "defining" the projection is * dead, for example on x86, if we have a dead Add node we remove its @@ -737,6 +791,16 @@ block_hrp_index = i; } +void PhaseChaitin::print_pressure_info(Pressure& pressure, const char *str) { + if (str != NULL) { + tty->print_cr("# *** %s ***", str); + } + tty->print_cr("# start pressure is = %d", pressure.start_pressure()); + tty->print_cr("# max pressure is = %d", pressure.final_pressure()); + tty->print_cr("# end pressure is = %d", pressure.current_pressure()); + tty->print_cr("#"); +} + /* Build an interference graph: * That is, if 2 live ranges are simultaneously alive but in their acceptable * register sets do not overlap, then they do not interfere. The IFG is built diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/lcm.cpp --- a/hotspot/src/share/vm/opto/lcm.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/lcm.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,6 +31,7 @@ #include "opto/cfgnode.hpp" #include "opto/machnode.hpp" #include "opto/runtime.hpp" +#include "opto/chaitin.hpp" #include "runtime/sharedRuntime.hpp" // Optimization - Graph Style @@ -443,7 +444,13 @@ // remaining cases (most), choose the instruction with the greatest latency // (that is, the most number of pseudo-cycles required to the end of the // routine). If there is a tie, choose the instruction with the most inputs. -Node* PhaseCFG::select(Block* block, Node_List &worklist, GrowableArray &ready_cnt, VectorSet &next_call, uint sched_slot) { +Node* PhaseCFG::select( + Block* block, + Node_List &worklist, + GrowableArray &ready_cnt, + VectorSet &next_call, + uint sched_slot, + intptr_t* recalc_pressure_nodes) { // If only a single entry on the stack, use it uint cnt = worklist.size(); @@ -458,6 +465,7 @@ uint score = 0; // Bigger is better int idx = -1; // Index in worklist int cand_cnt = 0; // Candidate count + bool block_size_threshold_ok = (block->number_of_nodes() > 10) ? true : false; for( uint i=0; ireq(); // Many inputs get high score to break ties + uint n_score = n->req(); // Many inputs get high score to break ties + + if (OptoRegScheduling && block_size_threshold_ok) { + if (recalc_pressure_nodes[n->_idx] == 0x7fff7fff) { + _regalloc->_scratch_int_pressure.init(_regalloc->_sched_int_pressure.high_pressure_limit()); + _regalloc->_scratch_float_pressure.init(_regalloc->_sched_float_pressure.high_pressure_limit()); + // simulate the notion that we just picked this node to schedule + n->add_flag(Node::Flag_is_scheduled); + // now caculate its effect upon the graph if we did + adjust_register_pressure(n, block, recalc_pressure_nodes, false); + // return its state for finalize in case somebody else wins + n->remove_flag(Node::Flag_is_scheduled); + // now save the two final pressure components of register pressure, limiting pressure calcs to short size + short int_pressure = (short)_regalloc->_scratch_int_pressure.current_pressure(); + short float_pressure = (short)_regalloc->_scratch_float_pressure.current_pressure(); + recalc_pressure_nodes[n->_idx] = int_pressure; + recalc_pressure_nodes[n->_idx] |= (float_pressure << 16); + } + + if (_scheduling_for_pressure) { + latency = n_latency; + if (n_choice != 3) { + // Now evaluate each register pressure component based on threshold in the score. + // In general the defining register type will dominate the score, ergo we will not see register pressure grow on both banks + // on a single instruction, but we might see it shrink on both banks. + // For each use of register that has a register class that is over the high pressure limit, we build n_score up for + // live ranges that terminate on this instruction. + if (_regalloc->_sched_int_pressure.current_pressure() > _regalloc->_sched_int_pressure.high_pressure_limit()) { + short int_pressure = (short)recalc_pressure_nodes[n->_idx]; + n_score = (int_pressure < 0) ? ((score + n_score) - int_pressure) : (int_pressure > 0) ? 1 : n_score; + } + if (_regalloc->_sched_float_pressure.current_pressure() > _regalloc->_sched_float_pressure.high_pressure_limit()) { + short float_pressure = (short)(recalc_pressure_nodes[n->_idx] >> 16); + n_score = (float_pressure < 0) ? ((score + n_score) - float_pressure) : (float_pressure > 0) ? 1 : n_score; + } + } else { + // make sure we choose these candidates + score = 0; + } + } + } // Keep best latency found cand_cnt++; @@ -562,6 +610,100 @@ return n; } +//-------------------------adjust_register_pressure---------------------------- +void PhaseCFG::adjust_register_pressure(Node* n, Block* block, intptr_t* recalc_pressure_nodes, bool finalize_mode) { + PhaseLive* liveinfo = _regalloc->get_live(); + IndexSet* liveout = liveinfo->live(block); + // first adjust the register pressure for the sources + for (uint i = 1; i < n->req(); i++) { + bool lrg_ends = false; + Node *src_n = n->in(i); + if (src_n == NULL) continue; + if (!src_n->is_Mach()) continue; + uint src = _regalloc->_lrg_map.find(src_n); + if (src == 0) continue; + LRG& lrg_src = _regalloc->lrgs(src); + // detect if the live range ends or not + if (liveout->member(src) == false) { + lrg_ends = true; + for (DUIterator_Fast jmax, j = src_n->fast_outs(jmax); j < jmax; j++) { + Node* m = src_n->fast_out(j); // Get user + if (m == n) continue; + if (!m->is_Mach()) continue; + MachNode *mach = m->as_Mach(); + bool src_matches = false; + int iop = mach->ideal_Opcode(); + + switch (iop) { + case Op_StoreB: + case Op_StoreC: + case Op_StoreCM: + case Op_StoreD: + case Op_StoreF: + case Op_StoreI: + case Op_StoreL: + case Op_StoreP: + case Op_StoreN: + case Op_StoreVector: + case Op_StoreNKlass: + for (uint k = 1; k < m->req(); k++) { + Node *in = m->in(k); + if (in == src_n) { + src_matches = true; + break; + } + } + break; + + default: + src_matches = true; + break; + } + + // If we have a store as our use, ignore the non source operands + if (src_matches == false) continue; + + // Mark every unscheduled use which is not n with a recalculation + if ((get_block_for_node(m) == block) && (!m->is_scheduled())) { + if (finalize_mode && !m->is_Phi()) { + recalc_pressure_nodes[m->_idx] = 0x7fff7fff; + } + lrg_ends = false; + } + } + } + // if none, this live range ends and we can adjust register pressure + if (lrg_ends) { + if (finalize_mode) { + _regalloc->lower_pressure(block, 0, lrg_src, NULL, _regalloc->_sched_int_pressure, _regalloc->_sched_float_pressure); + } else { + _regalloc->lower_pressure(block, 0, lrg_src, NULL, _regalloc->_scratch_int_pressure, _regalloc->_scratch_float_pressure); + } + } + } + + // now add the register pressure from the dest and evaluate which heuristic we should use: + // 1.) The default, latency scheduling + // 2.) Register pressure scheduling based on the high pressure limit threshold for int or float register stacks + uint dst = _regalloc->_lrg_map.find(n); + if (dst != 0) { + LRG& lrg_dst = _regalloc->lrgs(dst); + if (finalize_mode) { + _regalloc->raise_pressure(block, lrg_dst, _regalloc->_sched_int_pressure, _regalloc->_sched_float_pressure); + // check to see if we fall over the register pressure cliff here + if (_regalloc->_sched_int_pressure.current_pressure() > _regalloc->_sched_int_pressure.high_pressure_limit()) { + _scheduling_for_pressure = true; + } else if (_regalloc->_sched_float_pressure.current_pressure() > _regalloc->_sched_float_pressure.high_pressure_limit()) { + _scheduling_for_pressure = true; + } else { + // restore latency scheduling mode + _scheduling_for_pressure = false; + } + } else { + _regalloc->raise_pressure(block, lrg_dst, _regalloc->_scratch_int_pressure, _regalloc->_scratch_float_pressure); + } + } +} //------------------------------set_next_call---------------------------------- void PhaseCFG::set_next_call(Block* block, Node* n, VectorSet& next_call) { @@ -644,7 +786,7 @@ continue; } if( m->is_Phi() ) continue; - int m_cnt = ready_cnt.at(m->_idx)-1; + int m_cnt = ready_cnt.at(m->_idx) - 1; ready_cnt.at_put(m->_idx, m_cnt); if( m_cnt == 0 ) worklist.push(m); @@ -711,7 +853,7 @@ //------------------------------schedule_local--------------------------------- // Topological sort within a block. Someday become a real scheduler. -bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, VectorSet& next_call) { +bool PhaseCFG::schedule_local(Block* block, GrowableArray& ready_cnt, VectorSet& next_call, intptr_t *recalc_pressure_nodes) { // Already "sorted" are the block start Node (as the first entry), and // the block-ending Node and any trailing control projections. We leave // these alone. PhiNodes and ParmNodes are made to follow the block start @@ -733,10 +875,24 @@ return true; } + bool block_size_threshold_ok = (block->number_of_nodes() > 10) ? true : false; + + // We track the uses of local definitions as input dependences so that + // we know when a given instruction is avialable to be scheduled. + uint i; + if (OptoRegScheduling && block_size_threshold_ok) { + for (i = 1; i < block->number_of_nodes(); i++) { // setup nodes for pressure calc + Node *n = block->get_node(i); + n->remove_flag(Node::Flag_is_scheduled); + if (!n->is_Phi()) { + recalc_pressure_nodes[n->_idx] = 0x7fff7fff; + } + } + } + // Move PhiNodes and ParmNodes from 1 to cnt up to the start uint node_cnt = block->end_idx(); uint phi_cnt = 1; - uint i; for( i = 1; iget_node(i); if( n->is_Phi() || // Found a PhiNode or ParmNode @@ -744,6 +900,10 @@ // Move guy at 'phi_cnt' to the end; makes a hole at phi_cnt block->map_node(block->get_node(phi_cnt), i); block->map_node(n, phi_cnt++); // swap Phi/Parm up front + if (OptoRegScheduling && block_size_threshold_ok) { + // mark n as scheduled + n->add_flag(Node::Flag_is_scheduled); + } } else { // All others // Count block-local inputs to 'n' uint cnt = n->len(); // Input count @@ -791,12 +951,18 @@ // All the prescheduled guys do not hold back internal nodes uint i3; - for(i3 = 0; i3get_node(i3); // Get pre-scheduled for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) { Node* m = n->fast_out(j); if (get_block_for_node(m) == block) { // Local-block user int m_cnt = ready_cnt.at(m->_idx)-1; + if (OptoRegScheduling && block_size_threshold_ok) { + // mark m as scheduled + if (m_cnt < 0) { + m->add_flag(Node::Flag_is_scheduled); + } + } ready_cnt.at_put(m->_idx, m_cnt); // Fix ready count } } @@ -827,6 +993,18 @@ worklist.push(d); } + if (OptoRegScheduling && block_size_threshold_ok) { + // To stage register pressure calculations we need to examine the live set variables + // breaking them up by register class to compartmentalize the calculations. + uint float_pressure = Matcher::float_pressure(FLOATPRESSURE); + _regalloc->_sched_int_pressure.init(INTPRESSURE); + _regalloc->_sched_float_pressure.init(float_pressure); + _regalloc->_scratch_int_pressure.init(INTPRESSURE); + _regalloc->_scratch_float_pressure.init(float_pressure); + + _regalloc->compute_entry_block_pressure(block); + } + // Warm up the 'next_call' heuristic bits needed_for_next_call(block, block->head(), next_call); @@ -858,9 +1036,18 @@ #endif // Select and pop a ready guy from worklist - Node* n = select(block, worklist, ready_cnt, next_call, phi_cnt); + Node* n = select(block, worklist, ready_cnt, next_call, phi_cnt, recalc_pressure_nodes); block->map_node(n, phi_cnt++); // Schedule him next + if (OptoRegScheduling && block_size_threshold_ok) { + n->add_flag(Node::Flag_is_scheduled); + + // Now adjust the resister pressure with the node we selected + if (!n->is_Phi()) { + adjust_register_pressure(n, block, recalc_pressure_nodes, true); + } + } + #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print("# select %d: %s", n->_idx, n->Name()); @@ -906,7 +1093,7 @@ assert(m->is_MachProj() && n->is_Mach() && n->as_Mach()->has_call(), "unexpected node types"); continue; } - int m_cnt = ready_cnt.at(m->_idx)-1; + int m_cnt = ready_cnt.at(m->_idx) - 1; ready_cnt.at_put(m->_idx, m_cnt); if( m_cnt == 0 ) worklist.push(m); @@ -925,6 +1112,12 @@ return false; } + if (OptoRegScheduling && block_size_threshold_ok) { + _regalloc->compute_exit_block_pressure(block); + block->_reg_pressure = _regalloc->_sched_int_pressure.final_pressure(); + block->_freg_pressure = _regalloc->_sched_float_pressure.final_pressure(); + } + #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print_cr("#"); @@ -933,11 +1126,17 @@ tty->print("# "); block->get_node(i)->fast_dump(); } + tty->print_cr("# "); + + if (OptoRegScheduling && block_size_threshold_ok) { + tty->print_cr("# pressure info : %d", block->_pre_order); + _regalloc->print_pressure_info(_regalloc->_sched_int_pressure, "int register info"); + _regalloc->print_pressure_info(_regalloc->_sched_float_pressure, "float register info"); + } tty->cr(); } #endif - return true; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/library_call.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -133,7 +133,7 @@ private: void fatal_unexpected_iid(vmIntrinsics::ID iid) { - fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); } void set_result(Node* n) { assert(_result == NULL, "only set once"); _result = n; } @@ -222,7 +222,6 @@ bool inline_math_negateExactL(); bool inline_math_subtractExactI(bool is_decrement); bool inline_math_subtractExactL(bool is_decrement); - bool inline_exp(); bool inline_pow(); Node* finish_pow_exp(Node* result, Node* x, Node* y, const TypeFunc* call_type, address funcAddr, const char* funcName); bool inline_min_max(vmIntrinsics::ID id); @@ -1535,20 +1534,6 @@ } } -//------------------------------inline_exp------------------------------------- -// Inline exp instructions, if possible. The Intel hardware only misses -// really odd corner cases (+/- Infinity). Just uncommon-trap them. -bool LibraryCallKit::inline_exp() { - Node* arg = round_double_node(argument(0)); - Node* n = _gvn.transform(new ExpDNode(C, control(), arg)); - - n = finish_pow_exp(n, arg, NULL, OptoRuntime::Math_D_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::dexp), "EXP"); - set_result(n); - - C->set_has_split_ifs(true); // Has chance for split-if optimization - return true; -} - //------------------------------inline_pow------------------------------------- // Inline power instructions, if possible. bool LibraryCallKit::inline_pow() { @@ -1776,8 +1761,10 @@ case vmIntrinsics::_dsqrt: return Matcher::match_rule_supported(Op_SqrtD) ? inline_math(id) : false; case vmIntrinsics::_dabs: return Matcher::has_match_rule(Op_AbsD) ? inline_math(id) : false; - case vmIntrinsics::_dexp: return Matcher::has_match_rule(Op_ExpD) ? inline_exp() : - runtime_math(OptoRuntime::Math_D_D_Type(), FN_PTR(SharedRuntime::dexp), "EXP"); + case vmIntrinsics::_dexp: + return StubRoutines::dexp() != NULL ? + runtime_math(OptoRuntime::Math_D_D_Type(), StubRoutines::dexp(), "dexp") : + runtime_math(OptoRuntime::Math_D_D_Type(), FN_PTR(SharedRuntime::dexp), "EXP"); case vmIntrinsics::_dpow: return Matcher::has_match_rule(Op_PowD) ? inline_pow() : runtime_math(OptoRuntime::Math_DD_D_Type(), FN_PTR(SharedRuntime::dpow), "POW"); #undef FN_PTR @@ -2466,7 +2453,7 @@ p = ConvX2UL(p); break; default: - fatal(err_msg_res("unexpected type %d: %s", type, type2name(type))); + fatal("unexpected type %d: %s", type, type2name(type)); break; } } @@ -2755,7 +2742,7 @@ } break; default: - fatal(err_msg_res("unexpected type %d: %s", type, type2name(type))); + fatal("unexpected type %d: %s", type, type2name(type)); break; } @@ -3807,7 +3794,7 @@ ciMethod* method = callee(); int vtable_index = method->vtable_index(); assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index, - err_msg_res("bad index %d", vtable_index)); + "bad index %d", vtable_index); // Get the Method* out of the appropriate vtable entry. int entry_offset = (InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size()) * wordSize + @@ -3859,7 +3846,7 @@ // No need to use the linkResolver to get it. vtable_index = method->vtable_index(); assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index, - err_msg_res("bad index %d", vtable_index)); + "bad index %d", vtable_index); } slow_call = new CallDynamicJavaNode(tf, SharedRuntime::get_resolve_virtual_call_stub(), @@ -6131,7 +6118,7 @@ } break; default: - fatal(err_msg_res("unknown SHA intrinsic predicate: %d", predicate)); + fatal("unknown SHA intrinsic predicate: %d", predicate); } if (klass_SHA_name != NULL) { // get DigestBase klass to lookup for SHA klass @@ -6236,7 +6223,7 @@ } break; default: - fatal(err_msg_res("unknown SHA intrinsic predicate: %d", predicate)); + fatal("unknown SHA intrinsic predicate: %d", predicate); } ciKlass* klass_SHA = NULL; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/live.cpp --- a/hotspot/src/share/vm/opto/live.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/live.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,7 +41,14 @@ // block is put on the worklist. // The locally live-in stuff is computed once and added to predecessor // live-out sets. This separate compilation is done in the outer loop below. -PhaseLive::PhaseLive( const PhaseCFG &cfg, const LRG_List &names, Arena *arena ) : Phase(LIVE), _cfg(cfg), _names(names), _arena(arena), _live(0) { +PhaseLive::PhaseLive(const PhaseCFG &cfg, const LRG_List &names, Arena *arena, bool keep_deltas) + : Phase(LIVE), + _cfg(cfg), + _names(names), + _arena(arena), + _live(0), + _livein(0), + _keep_deltas(keep_deltas) { } void PhaseLive::compute(uint maxlrg) { @@ -56,6 +63,13 @@ _live[i].initialize(_maxlrg); } + if (_keep_deltas) { + _livein = (IndexSet*)_arena->Amalloc(sizeof(IndexSet) * _cfg.number_of_blocks()); + for (i = 0; i < _cfg.number_of_blocks(); i++) { + _livein[i].initialize(_maxlrg); + } + } + // Init the sparse arrays for delta-sets. ResourceMark rm; // Nuke temp storage on exit @@ -124,7 +138,10 @@ // PhiNode uses go in the live-out set of prior blocks. for (uint k = i; k > 0; k--) { - add_liveout(p, _names.at(block->get_node(k-1)->in(l)->_idx), first_pass); + Node *phi = block->get_node(k - 1); + if (l < phi->req()) { + add_liveout(p, _names.at(phi->in(l)->_idx), first_pass); + } } } freeset(block); @@ -200,8 +217,11 @@ } // Free an IndexSet from a block. -void PhaseLive::freeset( const Block *p ) { +void PhaseLive::freeset( Block *p ) { IndexSet *f = _deltas[p->_pre_order-1]; + if ( _keep_deltas ) { + add_livein(p, f); + } f->set_next(_free_IndexSet); _free_IndexSet = f; // Drop onto free list _deltas[p->_pre_order-1] = NULL; @@ -249,10 +269,23 @@ } } +// Add a vector of live-in values to a given blocks live-in set. +void PhaseLive::add_livein(Block *p, IndexSet *lo) { + IndexSet *livein = &_livein[p->_pre_order-1]; + IndexSetIterator elements(lo); + uint r; + while ((r = elements.next()) != 0) { + livein->insert(r); // Then add to live-in set + } +} + #ifndef PRODUCT // Dump the live-out set for a block void PhaseLive::dump( const Block *b ) const { tty->print("Block %d: ",b->_pre_order); + if ( _keep_deltas ) { + tty->print("LiveIn: "); _livein[b->_pre_order-1].dump(); + } tty->print("LiveOut: "); _live[b->_pre_order-1].dump(); uint cnt = b->number_of_nodes(); for( uint i=0; i_pre_order-1]; } + IndexSet *livein( const Block * b ) { return &_livein[b->_pre_order - 1]; } #ifndef PRODUCT void dump( const Block *b ) const; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/loopUnswitch.cpp --- a/hotspot/src/share/vm/opto/loopUnswitch.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/loopUnswitch.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -263,3 +263,136 @@ return iffast; } + +LoopNode* PhaseIdealLoop::create_reserve_version_of_loop(IdealLoopTree *loop, CountedLoopReserveKit* lk) { + Node_List old_new; + LoopNode* head = loop->_head->as_Loop(); + bool counted_loop = head->is_CountedLoop(); + Node* entry = head->in(LoopNode::EntryControl); + _igvn.rehash_node_delayed(entry); + IdealLoopTree* outer_loop = loop->_parent; + + ConINode* const_1 = _igvn.intcon(1); + set_ctrl(const_1, C->root()); + IfNode* iff = new IfNode(entry, const_1, PROB_MAX, COUNT_UNKNOWN); + register_node(iff, outer_loop, entry, dom_depth(entry)); + ProjNode* iffast = new IfTrueNode(iff); + register_node(iffast, outer_loop, iff, dom_depth(iff)); + ProjNode* ifslow = new IfFalseNode(iff); + register_node(ifslow, outer_loop, iff, dom_depth(iff)); + + // Clone the loop body. The clone becomes the fast loop. The + // original pre-header will (illegally) have 3 control users + // (old & new loops & new if). + clone_loop(loop, old_new, dom_depth(head), iff); + assert(old_new[head->_idx]->is_Loop(), "" ); + + LoopNode* slow_head = old_new[head->_idx]->as_Loop(); + +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print_cr("PhaseIdealLoop::create_reserve_version_of_loop:"); + tty->print("\t iff = %d, ", iff->_idx); iff->dump(); + tty->print("\t iffast = %d, ", iffast->_idx); iffast->dump(); + tty->print("\t ifslow = %d, ", ifslow->_idx); ifslow->dump(); + tty->print("\t before replace_input_of: head = %d, ", head->_idx); head->dump(); + tty->print("\t before replace_input_of: slow_head = %d, ", slow_head->_idx); slow_head->dump(); + } +#endif + + // Fast (true) control + _igvn.replace_input_of(head, LoopNode::EntryControl, iffast); + // Slow (false) control + _igvn.replace_input_of(slow_head, LoopNode::EntryControl, ifslow); + + recompute_dom_depth(); + + lk->set_iff(iff); + +#ifndef PRODUCT + if (TraceLoopOpts ) { + tty->print("\t after replace_input_of: head = %d, ", head->_idx); head->dump(); + tty->print("\t after replace_input_of: slow_head = %d, ", slow_head->_idx); slow_head->dump(); + } +#endif + + return slow_head->as_Loop(); +} + +CountedLoopReserveKit::CountedLoopReserveKit(PhaseIdealLoop* phase, IdealLoopTree *loop, bool active = true) : + _phase(phase), + _lpt(loop), + _lp(NULL), + _iff(NULL), + _lp_reserved(NULL), + _has_reserved(false), + _use_new(false), + _active(active) + { + create_reserve(); + }; + +CountedLoopReserveKit::~CountedLoopReserveKit() { + if (!_active) { + return; + } + + if (_has_reserved && !_use_new) { + // intcon(0)->iff-node reverts CF to the reserved copy + ConINode* const_0 = _phase->_igvn.intcon(0); + _phase->set_ctrl(const_0, _phase->C->root()); + _iff->set_req(1, const_0); + + #ifndef PRODUCT + if (TraceLoopOpts) { + tty->print_cr("CountedLoopReserveKit::~CountedLoopReserveKit()"); + tty->print("\t discard loop %d and revert to the reserved loop clone %d: ", _lp->_idx, _lp_reserved->_idx); + _lp_reserved->dump(); + } + #endif + } +} + +bool CountedLoopReserveKit::create_reserve() { + if (!_active) { + return false; + } + + if(!_lpt->_head->is_CountedLoop()) { + NOT_PRODUCT(if(TraceLoopOpts) {tty->print_cr("CountedLoopReserveKit::create_reserve: %d not counted loop", _lpt->_head->_idx);}) + return false; + } + CountedLoopNode *cl = _lpt->_head->as_CountedLoop(); + if (!cl->is_valid_counted_loop()) { + NOT_PRODUCT(if(TraceLoopOpts) {tty->print_cr("CountedLoopReserveKit::create_reserve: %d not valid counted loop", cl->_idx);}) + return false; // skip malformed counted loop + } + if (!cl->is_main_loop()) { + NOT_PRODUCT(if(TraceLoopOpts) {tty->print_cr("CountedLoopReserveKit::create_reserve: %d not main loop", cl->_idx);}) + return false; // skip normal, pre, and post loops + } + + _lp = _lpt->_head->as_Loop(); + _lp_reserved = _phase->create_reserve_version_of_loop(_lpt, this); + + if (!_lp_reserved->is_CountedLoop()) { + return false; + } + + Node* ifslow_pred = _lp_reserved->as_CountedLoop()->in(LoopNode::EntryControl); + + if (!ifslow_pred->is_IfFalse()) { + return false; + } + + Node* iff = ifslow_pred->in(0); + if (!iff->is_If() || iff != _iff) { + return false; + } + + if (iff->in(1)->Opcode() != Op_ConI) { + return false; + } + + return _has_reserved = true; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/loopnode.hpp --- a/hotspot/src/share/vm/opto/loopnode.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/loopnode.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -38,6 +38,7 @@ class LoopNode; class Node; class PhaseIdealLoop; +class CountedLoopReserveKit; class VectorSet; class Invariance; struct small_cache; @@ -290,6 +291,7 @@ if (phi() == NULL) { return NULL; } + assert(phi()->is_Phi(), "should be PhiNode"); Node *ln = phi()->in(0); if (ln->is_CountedLoop() && ln->as_CountedLoop()->loopexit() == this) { return (CountedLoopNode*)ln; @@ -528,6 +530,8 @@ class PhaseIdealLoop : public PhaseTransform { friend class IdealLoopTree; friend class SuperWord; + friend class CountedLoopReserveKit; + // Pre-computed def-use info PhaseIterGVN &_igvn; @@ -964,6 +968,16 @@ ProjNode* create_slow_version_of_loop(IdealLoopTree *loop, Node_List &old_new); + // Clone a loop and return the clone head (clone_loop_head). + // Added nodes include int(1), int(0) - disconnected, If, IfTrue, IfFalse, + // This routine was created for usage in CountedLoopReserveKit. + // + // int(1) -> If -> IfTrue -> original_loop_head + // | + // V + // IfFalse -> clone_loop_head (returned by function pointer) + // + LoopNode* create_reserve_version_of_loop(IdealLoopTree *loop, CountedLoopReserveKit* lk); // Clone loop with an invariant test (that does not exit) and // insert a clone of the test that selects which version to // execute. @@ -1116,6 +1130,68 @@ #endif }; +// This kit may be used for making of a reserved copy of a loop before this loop +// goes under non-reversible changes. +// +// Function create_reserve() creates a reserved copy (clone) of the loop. +// The reserved copy is created by calling +// PhaseIdealLoop::create_reserve_version_of_loop - see there how +// the original and reserved loops are connected in the outer graph. +// If create_reserve succeeded, it returns 'true' and _has_reserved is set to 'true'. +// +// By default the reserved copy (clone) of the loop is created as dead code - it is +// dominated in the outer loop by this node chain: +// intcon(1)->If->IfFalse->reserved_copy. +// The original loop is dominated by the the same node chain but IfTrue projection: +// intcon(1)->If->IfTrue->original_loop. +// +// In this implementation of CountedLoopReserveKit the ctor includes create_reserve() +// and the dtor, checks _use_new value. +// If _use_new == false, it "switches" control to reserved copy of the loop +// by simple replacing of node intcon(1) with node intcon(0). +// +// Here is a proposed example of usage (see also SuperWord::output in superword.cpp). +// +// void CountedLoopReserveKit_example() +// { +// CountedLoopReserveKit lrk((phase, lpt, DoReserveCopy = true); // create local object +// if (DoReserveCopy && !lrk.has_reserved()) { +// return; //failed to create reserved loop copy +// } +// ... +// //something is wrong, switch to original loop +/// if(something_is_wrong) return; // ~CountedLoopReserveKit makes the switch +// ... +// //everything worked ok, return with the newly modified loop +// lrk.use_new(); +// return; // ~CountedLoopReserveKit does nothing once use_new() was called +// } +// +// Keep in mind, that by default if create_reserve() is not followed by use_new() +// the dtor will "switch to the original" loop. +// NOTE. You you modify outside of the original loop this class is no help. +// +class CountedLoopReserveKit { + private: + PhaseIdealLoop* _phase; + IdealLoopTree* _lpt; + LoopNode* _lp; + IfNode* _iff; + LoopNode* _lp_reserved; + bool _has_reserved; + bool _use_new; + const bool _active; //may be set to false in ctor, then the object is dummy + + public: + CountedLoopReserveKit(PhaseIdealLoop* phase, IdealLoopTree *loop, bool active); + ~CountedLoopReserveKit(); + void use_new() {_use_new = true;} + void set_iff(IfNode* x) {_iff = x;} + bool has_reserved() const { return _active && _has_reserved;} + private: + bool create_reserve(); +};// class CountedLoopReserveKit + inline Node* IdealLoopTree::tail() { // Handle lazy update of _tail field Node *n = _tail; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/loopopts.cpp --- a/hotspot/src/share/vm/opto/loopopts.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/loopopts.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -447,21 +447,21 @@ } // Replace (I1 +p (I2 + V)) with ((I1 +p I2) +p V) - if( n2_loop != n_loop && n3_loop == n_loop ) { - if( n->in(3)->Opcode() == Op_AddI ) { + if (n2_loop != n_loop && n3_loop == n_loop) { + if (n->in(3)->Opcode() == Op_AddX) { Node *V = n->in(3)->in(1); Node *I = n->in(3)->in(2); - if( is_member(n_loop,get_ctrl(V)) ) { + if (is_member(n_loop,get_ctrl(V))) { } else { Node *tmp = V; V = I; I = tmp; } - if( !is_member(n_loop,get_ctrl(I)) ) { - Node *add1 = new AddPNode( n->in(1), n->in(2), I ); + if (!is_member(n_loop,get_ctrl(I))) { + Node *add1 = new AddPNode(n->in(1), n->in(2), I); // Stuff new AddP in the loop preheader - register_new_node( add1, n_loop->_head->in(LoopNode::EntryControl) ); - Node *add2 = new AddPNode( n->in(1), add1, V ); - register_new_node( add2, n_ctrl ); - _igvn.replace_node( n, add2 ); + register_new_node(add1, n_loop->_head->in(LoopNode::EntryControl)); + Node *add2 = new AddPNode(n->in(1), add1, V); + register_new_node(add2, n_ctrl); + _igvn.replace_node(n, add2); return add2; } } @@ -653,7 +653,6 @@ return iff->in(1); } -#ifdef ASSERT static void enqueue_cfg_uses(Node* m, Unique_Node_List& wq) { for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { Node* u = m->fast_out(i); @@ -667,7 +666,6 @@ } } } -#endif // Try moving a store out of a loop, right before the loop Node* PhaseIdealLoop::try_move_store_before_loop(Node* n, Node *n_ctrl) { @@ -687,11 +685,15 @@ // written at iteration i by the second store could be overwritten // at iteration i+n by the first store: it's not safe to move the // first store out of the loop - // - nothing must observe the Phi memory: it guarantees no read - // before the store and no early exit out of the loop - // With those conditions, we are also guaranteed the store post - // dominates the loop head. Otherwise there would be extra Phi - // involved between the loop's Phi and the store. + // - nothing must observe the memory Phi: it guarantees no read + // before the store, we are also guaranteed the store post + // dominates the loop head (ignoring a possible early + // exit). Otherwise there would be extra Phi involved between the + // loop's Phi and the store. + // - there must be no early exit from the loop before the Store + // (such an exit most of the time would be an extra use of the + // memory Phi but sometimes is a bottom memory Phi that takes the + // store as input). if (!n_loop->is_member(address_loop) && !n_loop->is_member(value_loop) && @@ -699,9 +701,10 @@ mem->outcnt() == 1 && mem->in(LoopNode::LoopBackControl) == n) { -#ifdef ASSERT - // Verify that store's control does post dominate loop entry and - // that there's no early exit of the loop before the store. + assert(n_loop->_tail != NULL, "need a tail"); + assert(is_dominator(n_ctrl, n_loop->_tail), "store control must not be in a branch in the loop"); + + // Verify that there's no early exit of the loop before the store. bool ctrl_ok = false; { // Follow control from loop head until n, we exit the loop or @@ -709,7 +712,7 @@ ResourceMark rm; Unique_Node_List wq; wq.push(n_loop->_head); - assert(n_loop->_tail != NULL, "need a tail"); + for (uint next = 0; next < wq.size(); ++next) { Node *m = wq.at(next); if (m == n->in(0)) { @@ -722,24 +725,27 @@ break; } enqueue_cfg_uses(m, wq); + if (wq.size() > 10) { + ctrl_ok = false; + break; + } } } - assert(ctrl_ok, "bad control"); -#endif + if (ctrl_ok) { + // move the Store + _igvn.replace_input_of(mem, LoopNode::LoopBackControl, mem); + _igvn.replace_input_of(n, 0, n_loop->_head->in(LoopNode::EntryControl)); + _igvn.replace_input_of(n, MemNode::Memory, mem->in(LoopNode::EntryControl)); + // Disconnect the phi now. An empty phi can confuse other + // optimizations in this pass of loop opts. + _igvn.replace_node(mem, mem->in(LoopNode::EntryControl)); + n_loop->_body.yank(mem); - // move the Store - _igvn.replace_input_of(mem, LoopNode::LoopBackControl, mem); - _igvn.replace_input_of(n, 0, n_loop->_head->in(LoopNode::EntryControl)); - _igvn.replace_input_of(n, MemNode::Memory, mem->in(LoopNode::EntryControl)); - // Disconnect the phi now. An empty phi can confuse other - // optimizations in this pass of loop opts. - _igvn.replace_node(mem, mem->in(LoopNode::EntryControl)); - n_loop->_body.yank(mem); + IdealLoopTree* new_loop = get_loop(n->in(0)); + set_ctrl_and_loop(n, n->in(0)); - IdealLoopTree* new_loop = get_loop(n->in(0)); - set_ctrl_and_loop(n, n->in(0)); - - return n; + return n; + } } } return NULL; @@ -769,13 +775,15 @@ } if (u->is_Phi() && u->in(0) == n_loop->_head) { assert(_igvn.type(u) == Type::MEMORY, "bad phi"); - assert(phi == NULL, "already found"); + // multiple phis on the same slice are possible + if (phi != NULL) { + return; + } phi = u; continue; } } - phi = NULL; - break; + return; } if (phi != NULL) { // Nothing in the loop before the store (next iteration) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/macro.cpp --- a/hotspot/src/share/vm/opto/macro.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/macro.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1512,7 +1512,8 @@ // MemBarStoreStore so that stores that initialize this object // can't be reordered with a subsequent store that makes this // object accessible by other threads. - if (init == NULL || (!init->is_complete_with_arraycopy() && !init->does_not_escape())) { + if (!alloc->does_not_escape_thread() && + (init == NULL || !init->is_complete_with_arraycopy())) { if (init == NULL || init->req() < InitializeNode::RawStores) { // No InitializeNode or no stores captured by zeroing // elimination. Simply add the MemBarStoreStore after object diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/matcher.cpp --- a/hotspot/src/share/vm/opto/matcher.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/matcher.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -326,14 +326,14 @@ grow_new_node_array(C->unique()); // Reset node counter so MachNodes start with _idx at 0 - int nodes = C->unique(); // save value + int live_nodes = C->live_nodes(); C->set_unique(0); C->reset_dead_node_list(); // Recursively match trees from old space into new space. // Correct leaves of new-space Nodes; they point to old-space. _visited.Clear(); // Clear visit bits for xform call - C->set_cached_top_node(xform( C->top(), nodes )); + C->set_cached_top_node(xform( C->top(), live_nodes )); if (!C->failing()) { Node* xroot = xform( C->root(), 1 ); if (xroot == NULL) { @@ -1001,7 +1001,7 @@ Node *Matcher::transform( Node *n ) { ShouldNotCallThis(); return n; } Node *Matcher::xform( Node *n, int max_stack ) { // Use one stack to keep both: child's node/state and parent's node/index - MStack mstack(max_stack * 2 * 2); // C->unique() * 2 * 2 + MStack mstack(max_stack * 2 * 2); // usually: C->live_nodes() * 2 * 2 mstack.push(n, Visit, NULL, -1); // set NULL as parent to indicate root while (mstack.is_nonempty()) { @@ -2045,11 +2045,38 @@ // and then expanded into the inline_cache_reg and a method_oop register // defined in ad_.cpp +// Check for shift by small constant as well +static bool clone_shift(Node* shift, Matcher* matcher, MStack& mstack, VectorSet& address_visited) { + if (shift->Opcode() == Op_LShiftX && shift->in(2)->is_Con() && + shift->in(2)->get_int() <= 3 && + // Are there other uses besides address expressions? + !matcher->is_visited(shift)) { + address_visited.set(shift->_idx); // Flag as address_visited + mstack.push(shift->in(2), Visit); + Node *conv = shift->in(1); +#ifdef _LP64 + // Allow Matcher to match the rule which bypass + // ConvI2L operation for an array index on LP64 + // if the index value is positive. + if (conv->Opcode() == Op_ConvI2L && + conv->as_Type()->type()->is_long()->_lo >= 0 && + // Are there other uses besides address expressions? + !matcher->is_visited(conv)) { + address_visited.set(conv->_idx); // Flag as address_visited + mstack.push(conv->in(1), Pre_Visit); + } else +#endif + mstack.push(conv, Pre_Visit); + return true; + } + return false; +} + //------------------------------find_shared------------------------------------ // Set bits if Node is shared or otherwise a root void Matcher::find_shared( Node *n ) { - // Allocate stack of size C->unique() * 2 to avoid frequent realloc + // Allocate stack of size C->live_nodes() * 2 to avoid frequent realloc MStack mstack(C->live_nodes() * 2); // Mark nodes as address_visited if they are inputs to an address expression VectorSet address_visited(Thread::current()->resource_area()); @@ -2205,7 +2232,10 @@ #endif // Clone addressing expressions as they are "free" in memory access instructions - if( mem_op && i == MemNode::Address && mop == Op_AddP ) { + if (mem_op && i == MemNode::Address && mop == Op_AddP && + // When there are other uses besides address expressions + // put it on stack and mark as shared. + !is_visited(m)) { // Some inputs for address expression are not put on stack // to avoid marking them as shared and forcing them into register // if they are used only in address expressions. @@ -2213,10 +2243,7 @@ // besides address expressions. Node *off = m->in(AddPNode::Offset); - if( off->is_Con() && - // When there are other uses besides address expressions - // put it on stack and mark as shared. - !is_visited(m) ) { + if (off->is_Con()) { address_visited.test_set(m->_idx); // Flag as address_visited Node *adr = m->in(AddPNode::Address); @@ -2229,28 +2256,7 @@ !is_visited(adr) ) { address_visited.set(adr->_idx); // Flag as address_visited Node *shift = adr->in(AddPNode::Offset); - // Check for shift by small constant as well - if( shift->Opcode() == Op_LShiftX && shift->in(2)->is_Con() && - shift->in(2)->get_int() <= 3 && - // Are there other uses besides address expressions? - !is_visited(shift) ) { - address_visited.set(shift->_idx); // Flag as address_visited - mstack.push(shift->in(2), Visit); - Node *conv = shift->in(1); -#ifdef _LP64 - // Allow Matcher to match the rule which bypass - // ConvI2L operation for an array index on LP64 - // if the index value is positive. - if( conv->Opcode() == Op_ConvI2L && - conv->as_Type()->type()->is_long()->_lo >= 0 && - // Are there other uses besides address expressions? - !is_visited(conv) ) { - address_visited.set(conv->_idx); // Flag as address_visited - mstack.push(conv->in(1), Pre_Visit); - } else -#endif - mstack.push(conv, Pre_Visit); - } else { + if (!clone_shift(shift, this, mstack, address_visited)) { mstack.push(shift, Pre_Visit); } mstack.push(adr->in(AddPNode::Address), Pre_Visit); @@ -2263,6 +2269,12 @@ mstack.push(off, Visit); mstack.push(m->in(AddPNode::Base), Pre_Visit); continue; // for(int i = ...) + } else if (clone_shift_expressions && + clone_shift(off, this, mstack, address_visited)) { + address_visited.test_set(m->_idx); // Flag as address_visited + mstack.push(m->in(AddPNode::Address), Pre_Visit); + mstack.push(m->in(AddPNode::Base), Pre_Visit); + continue; } // if( off->is_Con() ) } // if( mem_op && mstack.push(m, Pre_Visit); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/matcher.hpp --- a/hotspot/src/share/vm/opto/matcher.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/matcher.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -269,6 +269,9 @@ // should generate this one. static const bool match_rule_supported(int opcode); + // Some uarchs have different sized float register resources + static const int float_pressure(int default_pressure_threshold); + // Used to determine if we have fast l2f conversion // USII has it, USIII doesn't static const bool convL2FSupported(void); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/mathexactnode.cpp --- a/hotspot/src/share/vm/opto/mathexactnode.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/mathexactnode.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -167,7 +167,7 @@ } const Type* OverflowNode::sub(const Type* t1, const Type* t2) const { - fatal(err_msg_res("sub() should not be called for '%s'", NodeClassNames[this->Opcode()])); + fatal("sub() should not be called for '%s'", NodeClassNames[this->Opcode()]); return TypeInt::CC; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/memnode.cpp --- a/hotspot/src/share/vm/opto/memnode.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/memnode.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1139,7 +1139,7 @@ // Only integer types have boxing cache. assert(bt == T_BOOLEAN || bt == T_CHAR || bt == T_BYTE || bt == T_SHORT || - bt == T_INT || bt == T_LONG, err_msg_res("wrong type = %s", type2name(bt))); + bt == T_INT || bt == T_LONG, "wrong type = %s", type2name(bt)); jlong cache_low = (bt == T_LONG) ? c.as_long() : c.as_int(); if (cache_low != (int)cache_low) { return NULL; // should not happen since cache is array indexed by value @@ -2394,7 +2394,7 @@ Opcode() == Op_StoreVector || phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw || (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI), // expanded ClearArrayNode - err_msg_res("no mismatched stores, except on raw memory: %s %s", NodeClassNames[Opcode()], NodeClassNames[st->Opcode()])); + "no mismatched stores, except on raw memory: %s %s", NodeClassNames[Opcode()], NodeClassNames[st->Opcode()]); if (st->in(MemNode::Address)->eqv_uncast(address) && st->as_Store()->memory_size() <= this->memory_size()) { @@ -2945,7 +2945,7 @@ // Final field stores. Node* alloc = AllocateNode::Ideal_allocation(in(MemBarNode::Precedent), phase); if ((alloc != NULL) && alloc->is_Allocate() && - alloc->as_Allocate()->_is_non_escaping) { + alloc->as_Allocate()->does_not_escape_thread()) { // The allocated object does not escape. eliminate = true; } @@ -3289,7 +3289,7 @@ // the store control then we cannot capture the store. assert(!n->is_Store(), "2 stores to same slice on same control?"); Node* base = other_adr; - assert(base->is_AddP(), err_msg_res("should be addp but is %s", base->Name())); + assert(base->is_AddP(), "should be addp but is %s", base->Name()); base = base->in(AddPNode::Base); if (base != NULL) { base = base->uncast(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/node.cpp --- a/hotspot/src/share/vm/opto/node.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/node.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -47,6 +47,10 @@ #ifndef PRODUCT extern int nodes_created; #endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" +#endif #ifdef ASSERT @@ -456,6 +460,10 @@ _in[6] = n6; if (n6 != NULL) n6->add_out((Node *)this); } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + //------------------------------clone------------------------------------------ // Clone a Node. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/node.hpp --- a/hotspot/src/share/vm/opto/node.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/node.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -353,7 +353,7 @@ #endif // Reference to the i'th input Node. Error if out of bounds. - Node* in(uint i) const { assert(i < _max, err_msg_res("oob: i=%d, _max=%d", i, _max)); return _in[i]; } + Node* in(uint i) const { assert(i < _max, "oob: i=%d, _max=%d", i, _max); return _in[i]; } // Reference to the i'th input Node. NULL if out of bounds. Node* lookup(uint i) const { return ((i < _max) ? _in[i] : NULL); } // Reference to the i'th output Node. Error if out of bounds. @@ -393,7 +393,7 @@ void ins_req( uint i, Node *n ); // Insert a NEW required input void set_req( uint i, Node *n ) { assert( is_not_dead(n), "can not use dead node"); - assert( i < _cnt, err_msg_res("oob: i=%d, _cnt=%d", i, _cnt)); + assert( i < _cnt, "oob: i=%d, _cnt=%d", i, _cnt); assert( !VerifyHashTableKeys || _hash_lock == 0, "remove node from hash table before modifying it"); Node** p = &_in[i]; // cache this._in, across the del_out call @@ -674,7 +674,8 @@ Flag_avoid_back_to_back_after = Flag_avoid_back_to_back_before << 1, Flag_has_call = Flag_avoid_back_to_back_after << 1, Flag_is_reduction = Flag_has_call << 1, - Flag_is_expensive = Flag_is_reduction << 1, + Flag_is_scheduled = Flag_is_reduction, + Flag_is_expensive = Flag_is_scheduled << 1, _max_flags = (Flag_is_expensive << 1) - 1 // allow flags combination }; @@ -861,6 +862,9 @@ // It must have the loop's phi as input and provide a def to the phi. bool is_reduction() const { return (_flags & Flag_is_reduction) != 0; } + // Used in lcm to mark nodes that have scheduled + bool is_scheduled() const { return (_flags & Flag_is_scheduled) != 0; } + //----------------- Optimization // Get the worst-case Type output for this Node. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/output.cpp --- a/hotspot/src/share/vm/opto/output.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/output.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -116,12 +116,6 @@ } } -# ifdef ENABLE_ZAP_DEAD_LOCALS - if (ZapDeadCompiledLocals) { - Insert_zap_nodes(); - } -# endif - uint* blk_starts = NEW_RESOURCE_ARRAY(uint, _cfg->number_of_blocks() + 1); blk_starts[0] = 0; @@ -184,113 +178,6 @@ return (stub_function() == NULL && has_java_calls()); } -# ifdef ENABLE_ZAP_DEAD_LOCALS - - -// In order to catch compiler oop-map bugs, we have implemented -// a debugging mode called ZapDeadCompilerLocals. -// This mode causes the compiler to insert a call to a runtime routine, -// "zap_dead_locals", right before each place in compiled code -// that could potentially be a gc-point (i.e., a safepoint or oop map point). -// The runtime routine checks that locations mapped as oops are really -// oops, that locations mapped as values do not look like oops, -// and that locations mapped as dead are not used later -// (by zapping them to an invalid address). - -int Compile::_CompiledZap_count = 0; - -void Compile::Insert_zap_nodes() { - bool skip = false; - - - // Dink with static counts because code code without the extra - // runtime calls is MUCH faster for debugging purposes - - if ( CompileZapFirst == 0 ) ; // nothing special - else if ( CompileZapFirst > CompiledZap_count() ) skip = true; - else if ( CompileZapFirst == CompiledZap_count() ) - warning("starting zap compilation after skipping"); - - if ( CompileZapLast == -1 ) ; // nothing special - else if ( CompileZapLast < CompiledZap_count() ) skip = true; - else if ( CompileZapLast == CompiledZap_count() ) - warning("about to compile last zap"); - - ++_CompiledZap_count; // counts skipped zaps, too - - if ( skip ) return; - - - if ( _method == NULL ) - return; // no safepoints/oopmaps emitted for calls in stubs,so we don't care - - // Insert call to zap runtime stub before every node with an oop map - for( uint i=0; i<_cfg->number_of_blocks(); i++ ) { - Block *b = _cfg->get_block(i); - for ( uint j = 0; j < b->number_of_nodes(); ++j ) { - Node *n = b->get_node(j); - - // Determining if we should insert a zap-a-lot node in output. - // We do that for all nodes that has oopmap info, except for calls - // to allocation. Calls to allocation passes in the old top-of-eden pointer - // and expect the C code to reset it. Hence, there can be no safepoints between - // the inlined-allocation and the call to new_Java, etc. - // We also cannot zap monitor calls, as they must hold the microlock - // during the call to Zap, which also wants to grab the microlock. - bool insert = n->is_MachSafePoint() && (n->as_MachSafePoint()->oop_map() != NULL); - if ( insert ) { // it is MachSafePoint - if ( !n->is_MachCall() ) { - insert = false; - } else if ( n->is_MachCall() ) { - MachCallNode* call = n->as_MachCall(); - if (call->entry_point() == OptoRuntime::new_instance_Java() || - call->entry_point() == OptoRuntime::new_array_Java() || - call->entry_point() == OptoRuntime::multianewarray2_Java() || - call->entry_point() == OptoRuntime::multianewarray3_Java() || - call->entry_point() == OptoRuntime::multianewarray4_Java() || - call->entry_point() == OptoRuntime::multianewarray5_Java() || - call->entry_point() == OptoRuntime::slow_arraycopy_Java() || - call->entry_point() == OptoRuntime::complete_monitor_locking_Java() - ) { - insert = false; - } - } - if (insert) { - Node *zap = call_zap_node(n->as_MachSafePoint(), i); - b->insert_node(zap, j); - _cfg->map_node_to_block(zap, b); - ++j; - } - } - } - } -} - - -Node* Compile::call_zap_node(MachSafePointNode* node_to_check, int block_no) { - const TypeFunc *tf = OptoRuntime::zap_dead_locals_Type(); - CallStaticJavaNode* ideal_node = - new CallStaticJavaNode( tf, - OptoRuntime::zap_dead_locals_stub(_method->flags().is_native()), - "call zap dead locals stub", 0, TypePtr::BOTTOM); - // We need to copy the OopMap from the site we're zapping at. - // We have to make a copy, because the zap site might not be - // a call site, and zap_dead is a call site. - OopMap* clone = node_to_check->oop_map()->deep_copy(); - - // Add the cloned OopMap to the zap node - ideal_node->set_oop_map(clone); - return _matcher->match_sfpt(ideal_node); -} - -bool Compile::is_node_getting_a_safepoint( Node* n) { - // This code duplicates the logic prior to the call of add_safepoint - // below in this file. - if( n->is_MachSafePoint() ) return true; - return false; -} - -# endif // ENABLE_ZAP_DEAD_LOCALS // Compute the size of first NumberOfLoopInstrToAlign instructions at the top // of a loop. When aligning a loop we need to provide enough instructions @@ -834,10 +721,6 @@ MachSafePointNode *sfn = mach->as_MachSafePoint(); MachCallNode *mcall; -#ifdef ENABLE_ZAP_DEAD_LOCALS - assert( is_node_getting_a_safepoint(mach), "logic does not match; false negative"); -#endif - int safepoint_pc_offset = current_offset; bool is_method_handle_invoke = false; bool return_oop = false; @@ -973,7 +856,9 @@ assert(jvms->bci() >= InvocationEntryBci && jvms->bci() <= 0x10000, "must be a valid or entry BCI"); assert(!jvms->should_reexecute() || depth == max_depth, "reexecute allowed only for the youngest"); // Now we can describe the scope. - debug_info()->describe_scope(safepoint_pc_offset, scope_method, jvms->bci(), jvms->should_reexecute(), is_method_handle_invoke, return_oop, locvals, expvals, monvals); + methodHandle null_mh; + bool rethrow_exception = false; + debug_info()->describe_scope(safepoint_pc_offset, null_mh, scope_method, jvms->bci(), jvms->should_reexecute(), rethrow_exception, is_method_handle_invoke, return_oop, locvals, expvals, monvals); } // End jvms loop // Mark the end of the scope set. @@ -1056,7 +941,8 @@ JVMState* jvms = youngest_jvms->of_depth(depth); ciMethod* method = jvms->has_method() ? jvms->method() : NULL; assert(!jvms->should_reexecute() || depth==max_depth, "reexecute allowed only for the youngest"); - debug_info->describe_scope(pc_offset, method, jvms->bci(), jvms->should_reexecute()); + methodHandle null_mh; + debug_info->describe_scope(pc_offset, null_mh, method, jvms->bci(), jvms->should_reexecute()); } // Mark the end of the scope set. @@ -1294,10 +1180,6 @@ if (Pipeline::requires_bundling() && starts_bundle(n)) cb->flush_bundle(false); - // The following logic is duplicated in the code ifdeffed for - // ENABLE_ZAP_DEAD_LOCALS which appears above in this file. It - // should be factored out. Or maybe dispersed to the nodes? - // Special handling for SafePoint/Call Nodes bool is_mcall = false; if (n->is_Mach()) { @@ -1364,9 +1246,6 @@ // !!!!! Stubs only need an oopmap right now, so bail out if (sfn->jvms()->method() == NULL) { // Write the oopmap directly to the code blob??!! -# ifdef ENABLE_ZAP_DEAD_LOCALS - assert( !is_node_getting_a_safepoint(sfn), "logic does not match; false positive"); -# endif continue; } } // End synchronization @@ -1554,9 +1433,6 @@ // !!!!! Stubs only need an oopmap right now, so bail out if (!mach->is_MachCall() && mach->as_MachSafePoint()->jvms()->method() == NULL) { // Write the oopmap directly to the code blob??!! -# ifdef ENABLE_ZAP_DEAD_LOCALS - assert( !is_node_getting_a_safepoint(mach), "logic does not match; false positive"); -# endif delay_slot = NULL; continue; } @@ -2611,7 +2487,7 @@ n->dump(); tty->print_cr("..."); prior_use->dump(); - assert(edge_from_to(prior_use,n),msg); + assert(edge_from_to(prior_use,n), "%s", msg); } _reg_node.map(def,NULL); // Kill live USEs } @@ -2649,11 +2525,11 @@ OptoReg::Name reg_lo = _regalloc->get_reg_first(def); OptoReg::Name reg_hi = _regalloc->get_reg_second(def); if( OptoReg::is_valid(reg_lo) ) { - assert(!_reg_node[reg_lo] || edge_from_to(_reg_node[reg_lo],def), msg); + assert(!_reg_node[reg_lo] || edge_from_to(_reg_node[reg_lo],def), "%s", msg); _reg_node.map(reg_lo,n); } if( OptoReg::is_valid(reg_hi) ) { - assert(!_reg_node[reg_hi] || edge_from_to(_reg_node[reg_hi],def), msg); + assert(!_reg_node[reg_hi] || edge_from_to(_reg_node[reg_hi],def), "%s", msg); _reg_node.map(reg_hi,n); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/parse.hpp diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/parse1.cpp --- a/hotspot/src/share/vm/opto/parse1.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/parse1.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1476,13 +1476,13 @@ int pre_bc_sp = sp(); int inputs, depth; bool have_se = !stopped() && compute_stack_effects(inputs, depth); - assert(!have_se || pre_bc_sp >= inputs, err_msg_res("have enough stack to execute this BC: pre_bc_sp=%d, inputs=%d", pre_bc_sp, inputs)); + assert(!have_se || pre_bc_sp >= inputs, "have enough stack to execute this BC: pre_bc_sp=%d, inputs=%d", pre_bc_sp, inputs); #endif //ASSERT do_one_bytecode(); assert(!have_se || stopped() || failing() || (sp() - pre_bc_sp) == depth, - err_msg_res("incorrect depth prediction: sp=%d, pre_bc_sp=%d, depth=%d", sp(), pre_bc_sp, depth)); + "incorrect depth prediction: sp=%d, pre_bc_sp=%d, depth=%d", sp(), pre_bc_sp, depth); do_exceptions(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/parse3.cpp --- a/hotspot/src/share/vm/opto/parse3.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/parse3.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -404,7 +404,7 @@ // The original expression was of this form: new T[length0][length1]... // It is often the case that the lengths are small (except the last). // If that happens, use the fast 1-d creator a constant number of times. - const jint expand_limit = MIN2((juint)MultiArrayExpandLimit, (juint)100); + const jint expand_limit = MIN2((jint)MultiArrayExpandLimit, 100); jint expand_count = 1; // count of allocations in the expansion jint expand_fanout = 1; // running total fanout for (j = 0; j < ndimensions-1; j++) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/runtime.cpp --- a/hotspot/src/share/vm/opto/runtime.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/runtime.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -102,11 +102,6 @@ address OptoRuntime::_slow_arraycopy_Java = NULL; address OptoRuntime::_register_finalizer_Java = NULL; -# ifdef ENABLE_ZAP_DEAD_LOCALS -address OptoRuntime::_zap_dead_Java_locals_Java = NULL; -address OptoRuntime::_zap_dead_native_locals_Java = NULL; -# endif - ExceptionBlob* OptoRuntime::_exception_blob; // This should be called in an assertion at the start of OptoRuntime routines @@ -152,10 +147,6 @@ gen(env, _slow_arraycopy_Java , slow_arraycopy_Type , SharedRuntime::slow_arraycopy_C , 0 , false, false, false); gen(env, _register_finalizer_Java , register_finalizer_Type , register_finalizer , 0 , false, false, false); -# ifdef ENABLE_ZAP_DEAD_LOCALS - gen(env, _zap_dead_Java_locals_Java , zap_dead_locals_Type , zap_dead_Java_locals_C , 0 , false, true , false ); - gen(env, _zap_dead_native_locals_Java , zap_dead_locals_Type , zap_dead_native_locals_C , 0 , false, true , false ); -# endif return true; } @@ -604,23 +595,6 @@ return TypeFunc::make(domain, range); } -# ifdef ENABLE_ZAP_DEAD_LOCALS -// Type used for stub generation for zap_dead_locals. -// No inputs or outputs -const TypeFunc *OptoRuntime::zap_dead_locals_Type() { - // create input type (domain) - const Type **fields = TypeTuple::fields(0); - const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms,fields); - - // create result type (range) - fields = TypeTuple::fields(0); - const TypeTuple *range = TypeTuple::make(TypeFunc::Parms,fields); - - return TypeFunc::make(domain,range); -} -# endif - - //----------------------------------------------------------------------------- // Monitor Handling const TypeFunc *OptoRuntime::complete_monitor_enter_Type() { @@ -1648,67 +1622,3 @@ #endif // PRODUCT - -# ifdef ENABLE_ZAP_DEAD_LOCALS -// Called from call sites in compiled code with oop maps (actually safepoints) -// Zaps dead locals in first java frame. -// Is entry because may need to lock to generate oop maps -// Currently, only used for compiler frames, but someday may be used -// for interpreter frames, too. - -int OptoRuntime::ZapDeadCompiledLocals_count = 0; - -// avoid pointers to member funcs with these helpers -static bool is_java_frame( frame* f) { return f->is_java_frame(); } -static bool is_native_frame(frame* f) { return f->is_native_frame(); } - - -void OptoRuntime::zap_dead_java_or_native_locals(JavaThread* thread, - bool (*is_this_the_right_frame_to_zap)(frame*)) { - assert(JavaThread::current() == thread, "is this needed?"); - - if ( !ZapDeadCompiledLocals ) return; - - bool skip = false; - - if ( ZapDeadCompiledLocalsFirst == 0 ) ; // nothing special - else if ( ZapDeadCompiledLocalsFirst > ZapDeadCompiledLocals_count ) skip = true; - else if ( ZapDeadCompiledLocalsFirst == ZapDeadCompiledLocals_count ) - warning("starting zapping after skipping"); - - if ( ZapDeadCompiledLocalsLast == -1 ) ; // nothing special - else if ( ZapDeadCompiledLocalsLast < ZapDeadCompiledLocals_count ) skip = true; - else if ( ZapDeadCompiledLocalsLast == ZapDeadCompiledLocals_count ) - warning("about to zap last zap"); - - ++ZapDeadCompiledLocals_count; // counts skipped zaps, too - - if ( skip ) return; - - // find java frame and zap it - - for (StackFrameStream sfs(thread); !sfs.is_done(); sfs.next()) { - if (is_this_the_right_frame_to_zap(sfs.current()) ) { - sfs.current()->zap_dead_locals(thread, sfs.register_map()); - return; - } - } - warning("no frame found to zap in zap_dead_Java_locals_C"); -} - -JRT_LEAF(void, OptoRuntime::zap_dead_Java_locals_C(JavaThread* thread)) - zap_dead_java_or_native_locals(thread, is_java_frame); -JRT_END - -// The following does not work because for one thing, the -// thread state is wrong; it expects java, but it is native. -// Also, the invariants in a native stub are different and -// I'm not sure it is safe to have a MachCalRuntimeDirectNode -// in there. -// So for now, we do not zap in native stubs. - -JRT_LEAF(void, OptoRuntime::zap_dead_native_locals_C(JavaThread* thread)) - zap_dead_java_or_native_locals(thread, is_native_frame); -JRT_END - -# endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/runtime.hpp --- a/hotspot/src/share/vm/opto/runtime.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/runtime.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -152,12 +152,6 @@ static address _slow_arraycopy_Java; static address _register_finalizer_Java; -# ifdef ENABLE_ZAP_DEAD_LOCALS - static address _zap_dead_Java_locals_Java; - static address _zap_dead_native_locals_Java; -# endif - - // // Implementation of runtime methods // ================================= @@ -212,19 +206,6 @@ static void register_finalizer(oopDesc* obj, JavaThread* thread); - // zaping dead locals, either from Java frames or from native frames -# ifdef ENABLE_ZAP_DEAD_LOCALS - static void zap_dead_Java_locals_C( JavaThread* thread); - static void zap_dead_native_locals_C( JavaThread* thread); - - static void zap_dead_java_or_native_locals( JavaThread*, bool (*)(frame*)); - - public: - static int ZapDeadCompiledLocals_count; - -# endif - - public: static bool is_callee_saved_register(MachRegisterNumbers reg); @@ -256,14 +237,6 @@ static address slow_arraycopy_Java() { return _slow_arraycopy_Java; } static address register_finalizer_Java() { return _register_finalizer_Java; } - -# ifdef ENABLE_ZAP_DEAD_LOCALS - static address zap_dead_locals_stub(bool is_native) { return is_native - ? _zap_dead_native_locals_Java - : _zap_dead_Java_locals_Java; } - static MachNode* node_to_call_zap_dead_locals(Node* n, int block_num, bool is_native); -# endif - static ExceptionBlob* exception_blob() { return _exception_blob; } // Leaf routines helping with method data update @@ -353,10 +326,6 @@ static const TypeFunc* dtrace_method_entry_exit_Type(); static const TypeFunc* dtrace_object_alloc_Type(); -# ifdef ENABLE_ZAP_DEAD_LOCALS - static const TypeFunc* zap_dead_locals_Type(); -# endif - private: static NamedCounter * volatile _named_counters; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/stringopts.cpp --- a/hotspot/src/share/vm/opto/stringopts.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/stringopts.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -773,7 +773,7 @@ return false; } } else { - assert(mem->is_Store() || mem->is_LoadStore(), err_msg_res("unexpected node type: %s", mem->Name())); + assert(mem->is_Store() || mem->is_LoadStore(), "unexpected node type: %s", mem->Name()); #ifndef PRODUCT if (PrintOptimizeStringConcat) { tty->print("fusion has incorrect memory flow (unexpected source) for "); @@ -814,7 +814,7 @@ for (SimpleDUIterator i(true_proj); i.has_next(); i.next()) { Node* use = i.get(); assert(use == ctrl || use->is_ConstraintCast(), - err_msg_res("unexpected user: %s", use->Name())); + "unexpected user: %s", use->Name()); } iff = ctrl->in(1)->in(0)->as_If(); @@ -838,7 +838,7 @@ for (SimpleDUIterator i(ctrl); i.has_next(); i.next()) { Node* use = i.get(); assert(use == copy || use == iff || use == curr || use->is_CheckCastPP() || use->is_Load(), - err_msg_res("unexpected user: %s", use->Name())); + "unexpected user: %s", use->Name()); } #endif // ASSERT } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/subnode.cpp --- a/hotspot/src/share/vm/opto/subnode.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/subnode.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1532,18 +1532,6 @@ //============================================================================= //------------------------------Value------------------------------------------ -// Compute exp -const Type *ExpDNode::Value( PhaseTransform *phase ) const { - const Type *t1 = phase->type( in(1) ); - if( t1 == Type::TOP ) return Type::TOP; - if( t1->base() != Type::DoubleCon ) return Type::DOUBLE; - double d = t1->getd(); - return TypeD::make( StubRoutines::intrinsic_exp( d ) ); -} - - -//============================================================================= -//------------------------------Value------------------------------------------ // Compute pow const Type *PowDNode::Value( PhaseTransform *phase ) const { const Type *t1 = phase->type( in(1) ); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/subnode.hpp --- a/hotspot/src/share/vm/opto/subnode.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/subnode.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -477,20 +477,6 @@ virtual const Type *Value( PhaseTransform *phase ) const; }; -//------------------------------ExpDNode--------------------------------------- -// Exponentiate a double -class ExpDNode : public Node { -public: - ExpDNode(Compile* C, Node *c, Node *in1) : Node(c, in1) { - init_flags(Flag_is_expensive); - C->add_expensive_node(this); - } - virtual int Opcode() const; - const Type *bottom_type() const { return Type::DOUBLE; } - virtual uint ideal_reg() const { return Op_RegD; } - virtual const Type *Value( PhaseTransform *phase ) const; -}; - //------------------------------LogDNode--------------------------------------- // Log_e of a double class LogDNode : public Node { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/superword.cpp --- a/hotspot/src/share/vm/opto/superword.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/superword.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -81,6 +81,10 @@ if (_phase->C->method() != NULL) { _phase->C->method()->has_option_value("VectorizeDebug", _vector_loop_debug); } + _CountedLoopReserveKit_debug = 0; + if (_phase->C->method() != NULL) { + _phase->C->method()->has_option_value("DoReserveCopyInSuperWordDebug", _CountedLoopReserveKit_debug); + } #endif } @@ -769,7 +773,7 @@ // if offset is 0. int iv_adjustment_in_bytes = (stride_sign * vw - (offset % vw)); assert(((ABS(iv_adjustment_in_bytes) % elt_size) == 0), - err_msg_res("(%d) should be divisible by (%d)", iv_adjustment_in_bytes, elt_size)); + "(%d) should be divisible by (%d)", iv_adjustment_in_bytes, elt_size); iv_adjustment = iv_adjustment_in_bytes/elt_size; } else { // This memory op is not dependent on iv (scale == 0) @@ -914,7 +918,7 @@ preds.push(n); NOT_PRODUCT(if (TraceSuperWord && Verbose) tty->print_cr("SuperWord::mem_slice_preds: added pred(%d)", n->_idx);) prev = n; - assert(n->is_Mem(), err_msg_res("unexpected node %s", n->Name())); + assert(n->is_Mem(), "unexpected node %s", n->Name()); n = n->in(MemNode::Memory); } } @@ -1763,6 +1767,22 @@ } } +#ifndef PRODUCT +void SuperWord::print_loop(bool whole) { + Node_Stack stack(_arena, _phase->C->unique() >> 2); + Node_List rpo_list; + VectorSet visited(_arena); + visited.set(lpt()->_head->_idx); + _phase->rpo(lpt()->_head, stack, visited, rpo_list); + _phase->dump(lpt(), rpo_list.size(), rpo_list ); + if(whole) { + tty->print_cr("\n Whole loop tree"); + _phase->dump(); + tty->print_cr(" End of whole loop tree\n"); + } +} +#endif + //------------------------------output--------------------------- // Convert packs into vector node operations void SuperWord::output() { @@ -1770,7 +1790,7 @@ #ifndef PRODUCT if (TraceLoopOpts) { - tty->print("SuperWord "); + tty->print("SuperWord::output "); lpt()->dump_head(); } #endif @@ -1789,6 +1809,18 @@ CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); uint max_vlen_in_bytes = 0; uint max_vlen = 0; + + NOT_PRODUCT(if(_CountedLoopReserveKit_debug > 0) {tty->print_cr("SWPointer::output: print loop before create_reserve_version_of_loop"); print_loop(true);}) + + CountedLoopReserveKit make_reversable(_phase, _lpt, DoReserveCopyInSuperWord); + + NOT_PRODUCT(if(_CountedLoopReserveKit_debug > 0) {tty->print_cr("SWPointer::output: print loop after create_reserve_version_of_loop"); print_loop(true);}) + + if (DoReserveCopyInSuperWord && !make_reversable.has_reserved()) { + NOT_PRODUCT({tty->print_cr("SWPointer::output: loop was not reserved correctly, exiting SuperWord");}) + return; + } + for (int i = 0; i < _block.length(); i++) { Node* n = _block.at(i); Node_List* p = my_pack(n); @@ -1858,8 +1890,8 @@ vn = VectorNode::make(opc, in1, in2, vlen, velt_basic_type(n)); vlen_in_bytes = vn->as_Vector()->length_in_bytes(); } - } else if (opc == Op_SqrtD) { - // Promote operand to vector (Sqrt is a 2 address instruction) + } else if (opc == Op_SqrtD || opc == Op_AbsF || opc == Op_AbsD || opc == Op_NegF || opc == Op_NegD) { + // Promote operand to vector (Sqrt/Abs/Neg are 2 address instructions) Node* in = vector_opd(p, 1); vn = VectorNode::make(opc, in, NULL, vlen, velt_basic_type(n)); vlen_in_bytes = vn->as_Vector()->length_in_bytes(); @@ -1888,6 +1920,7 @@ } } C->set_max_vector_size(max_vlen_in_bytes); + if (SuperWordLoopUnrollAnalysis) { if (cl->has_passed_slp()) { uint slp_max_unroll_factor = cl->slp_max_unroll(); @@ -1900,6 +1933,12 @@ } } } + + if (DoReserveCopyInSuperWord) { + make_reversable.use_new(); + } + NOT_PRODUCT(if(_CountedLoopReserveKit_debug > 0) {tty->print_cr("\n Final loop after SuperWord"); print_loop(true);}) + return; } //------------------------------vector_opd--------------------------- @@ -2110,7 +2149,7 @@ Node* n_tail = n->in(LoopNode::LoopBackControl); if (n_tail != n->in(LoopNode::EntryControl)) { if (!n_tail->is_Mem()) { - assert(n_tail->is_Mem(), err_msg_res("unexpected node for memory slice: %s", n_tail->Name())); + assert(n_tail->is_Mem(), "unexpected node for memory slice: %s", n_tail->Name()); return false; // Bailout } _mem_slice_head.push(n); @@ -2690,15 +2729,25 @@ //----------------------------get_pre_loop_end--------------------------- // Find pre loop end from main loop. Returns null if none. -CountedLoopEndNode* SuperWord::get_pre_loop_end(CountedLoopNode *cl) { - Node *ctrl = cl->in(LoopNode::EntryControl); +CountedLoopEndNode* SuperWord::get_pre_loop_end(CountedLoopNode* cl) { + Node* ctrl = cl->in(LoopNode::EntryControl); if (!ctrl->is_IfTrue() && !ctrl->is_IfFalse()) return NULL; - Node *iffm = ctrl->in(0); + Node* iffm = ctrl->in(0); if (!iffm->is_If()) return NULL; - Node *p_f = iffm->in(0); + Node* bolzm = iffm->in(1); + if (!bolzm->is_Bool()) return NULL; + Node* cmpzm = bolzm->in(1); + if (!cmpzm->is_Cmp()) return NULL; + Node* opqzm = cmpzm->in(2); + // Can not optimize a loop if zero-trip Opaque1 node is optimized + // away and then another round of loop opts attempted. + if (opqzm->Opcode() != Op_Opaque1) { + return NULL; + } + Node* p_f = iffm->in(0); if (!p_f->is_IfFalse()) return NULL; if (!p_f->in(0)->is_CountedLoopEnd()) return NULL; - CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd(); + CountedLoopEndNode* pre_end = p_f->in(0)->as_CountedLoopEnd(); CountedLoopNode* loop_node = pre_end->loopnode(); if (loop_node == NULL || !loop_node->is_pre_loop()) return NULL; return pre_end; @@ -3045,6 +3094,9 @@ } } if (invariant(n)) { + if (opc == Op_ConvI2L) { + n = n->in(1); + } _negate_invar = negate; _invar = n; NOT_PRODUCT(_tracer.offset_plus_k_10(n, _invar, _negate_invar, _offset);) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/superword.hpp --- a/hotspot/src/share/vm/opto/superword.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/superword.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -200,6 +200,31 @@ static const SWNodeInfo initial; }; +// JVMCI: OrderedPair is moved up to deal with compilation issues on Windows +//------------------------------OrderedPair--------------------------- +// Ordered pair of Node*. +class OrderedPair VALUE_OBJ_CLASS_SPEC { + protected: + Node* _p1; + Node* _p2; + public: + OrderedPair() : _p1(NULL), _p2(NULL) {} + OrderedPair(Node* p1, Node* p2) { + if (p1->_idx < p2->_idx) { + _p1 = p1; _p2 = p2; + } else { + _p1 = p2; _p2 = p1; + } + } + + bool operator==(const OrderedPair &rhs) { + return _p1 == rhs._p1 && _p2 == rhs._p2; + } + void print() { tty->print(" (%d, %d)", _p1->_idx, _p2->_idx); } + + static const OrderedPair initial; +}; + // -----------------------------SuperWord--------------------------------- // Transforms scalar operations into packed (superword) operations. class SuperWord : public ResourceObj { @@ -274,6 +299,7 @@ GrowableArray _ii_order; #ifndef PRODUCT uintx _vector_loop_debug; // provide more printing in debug mode + uintx _CountedLoopReserveKit_debug; // for debugging CountedLoopReserveKit #endif // Accessors @@ -350,6 +376,7 @@ // Tracing support #ifndef PRODUCT void find_adjacent_refs_trace_1(Node* best_align_to_mem_ref, int best_iv_adjustment); + void print_loop(bool whole); #endif // Find a memory reference to align the loop induction variable to. MemNode* find_align_to_ref(Node_List &memops); @@ -634,29 +661,4 @@ #endif }; - -//------------------------------OrderedPair--------------------------- -// Ordered pair of Node*. -class OrderedPair VALUE_OBJ_CLASS_SPEC { - protected: - Node* _p1; - Node* _p2; - public: - OrderedPair() : _p1(NULL), _p2(NULL) {} - OrderedPair(Node* p1, Node* p2) { - if (p1->_idx < p2->_idx) { - _p1 = p1; _p2 = p2; - } else { - _p1 = p2; _p2 = p1; - } - } - - bool operator==(const OrderedPair &rhs) { - return _p1 == rhs._p1 && _p2 == rhs._p2; - } - void print() { tty->print(" (%d, %d)", _p1->_idx, _p2->_idx); } - - static const OrderedPair initial; -}; - #endif // SHARE_VM_OPTO_SUPERWORD_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/type.cpp --- a/hotspot/src/share/vm/opto/type.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/type.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,8 +41,6 @@ #include "opto/opcodes.hpp" #include "opto/type.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Portions of code courtesy of Clifford Click // Optimization - Graph Style @@ -2784,7 +2782,7 @@ #ifndef PRODUCT void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const { if( _ptr == Constant ) - st->print(INTPTR_FORMAT, _bits); + st->print(INTPTR_FORMAT, p2i(_bits)); else st->print("rawptr:%s", ptr_msg[_ptr]); } @@ -3187,7 +3185,7 @@ void TypeOopPtr::dump2( Dict &d, uint depth, outputStream *st ) const { st->print("oopptr:%s", ptr_msg[_ptr]); if( _klass_is_exact ) st->print(":exact"); - if( const_oop() ) st->print(INTPTR_FORMAT, const_oop()); + if( const_oop() ) st->print(INTPTR_FORMAT, p2i(const_oop())); switch( _offset ) { case OffsetTop: st->print("+top"); break; case OffsetBot: st->print("+any"); break; @@ -3358,7 +3356,7 @@ case T_LONG: return TypeLong::make(constant.as_long()); default: break; } - fatal(err_msg_res("Invalid boxed value type '%s'", type2name(bt))); + fatal("Invalid boxed value type '%s'", type2name(bt)); return NULL; } @@ -4635,7 +4633,7 @@ #ifndef PRODUCT void TypeMetadataPtr::dump2( Dict &d, uint depth, outputStream *st ) const { st->print("metadataptr:%s", ptr_msg[_ptr]); - if( metadata() ) st->print(INTPTR_FORMAT, metadata()); + if( metadata() ) st->print(INTPTR_FORMAT, p2i(metadata())); switch( _offset ) { case OffsetTop: st->print("+top"); break; case OffsetBot: st->print("+any"); break; @@ -5033,7 +5031,7 @@ { const char *name = klass()->name()->as_utf8(); if( name ) { - st->print("klass %s: " INTPTR_FORMAT, name, klass()); + st->print("klass %s: " INTPTR_FORMAT, name, p2i(klass())); } else { ShouldNotReachHere(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/vectornode.cpp --- a/hotspot/src/share/vm/opto/vectornode.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/vectornode.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -92,6 +92,18 @@ case Op_DivD: assert(bt == T_DOUBLE, "must be"); return Op_DivVD; + case Op_AbsF: + assert(bt == T_FLOAT, "must be"); + return Op_AbsVF; + case Op_AbsD: + assert(bt == T_DOUBLE, "must be"); + return Op_AbsVD; + case Op_NegF: + assert(bt == T_FLOAT, "must be"); + return Op_NegVF; + case Op_NegD: + assert(bt == T_DOUBLE, "must be"); + return Op_NegVD; case Op_SqrtD: assert(bt == T_DOUBLE, "must be"); return Op_SqrtVD; @@ -255,7 +267,7 @@ const TypeVect* vt = TypeVect::make(bt, vlen); int vopc = VectorNode::opcode(opc, bt); // This method should not be called for unimplemented vectors. - guarantee(vopc > 0, err_msg_res("Vector for '%s' is not implemented", NodeClassNames[opc])); + guarantee(vopc > 0, "Vector for '%s' is not implemented", NodeClassNames[opc]); switch (vopc) { case Op_AddVB: return new AddVBNode(n1, n2, vt); case Op_AddVS: return new AddVSNode(n1, n2, vt); @@ -280,6 +292,12 @@ case Op_DivVF: return new DivVFNode(n1, n2, vt); case Op_DivVD: return new DivVDNode(n1, n2, vt); + case Op_AbsVF: return new AbsVFNode(n1, vt); + case Op_AbsVD: return new AbsVDNode(n1, vt); + + case Op_NegVF: return new NegVFNode(n1, vt); + case Op_NegVD: return new NegVDNode(n1, vt); + // Currently only supports double precision sqrt case Op_SqrtVD: return new SqrtVDNode(n1, vt); @@ -302,7 +320,7 @@ case Op_OrV: return new OrVNode (n1, n2, vt); case Op_XorV: return new XorVNode(n1, n2, vt); } - fatal(err_msg_res("Missed vector creation for '%s'", NodeClassNames[vopc])); + fatal("Missed vector creation for '%s'", NodeClassNames[vopc]); return NULL; } @@ -328,7 +346,7 @@ case T_DOUBLE: return new ReplicateDNode(s, vt); } - fatal(err_msg_res("Type '%s' is not supported for vectors", type2name(bt))); + fatal("Type '%s' is not supported for vectors", type2name(bt)); return NULL; } @@ -346,7 +364,7 @@ case Op_URShiftL: return new RShiftCntVNode(cnt, vt); } - fatal(err_msg_res("Missed vector creation for '%s'", NodeClassNames[shift->Opcode()])); + fatal("Missed vector creation for '%s'", NodeClassNames[shift->Opcode()]); return NULL; } @@ -369,7 +387,7 @@ case T_DOUBLE: return new PackDNode(s, vt); } - fatal(err_msg_res("Type '%s' is not supported for vectors", type2name(bt))); + fatal("Type '%s' is not supported for vectors", type2name(bt)); return NULL; } @@ -405,7 +423,7 @@ case T_DOUBLE: return new Pack2DNode(n1, n2, TypeVect::make(T_DOUBLE, 2)); } - fatal(err_msg_res("Type '%s' is not supported for vectors", type2name(bt))); + fatal("Type '%s' is not supported for vectors", type2name(bt)); } return NULL; } @@ -448,7 +466,7 @@ case T_DOUBLE: return new ExtractDNode(v, pos); } - fatal(err_msg_res("Type '%s' is not supported for vectors", type2name(bt))); + fatal("Type '%s' is not supported for vectors", type2name(bt)); return NULL; } @@ -500,7 +518,7 @@ int vopc = opcode(opc, bt); // This method should not be called for unimplemented vectors. - guarantee(vopc != opc, err_msg_res("Vector for '%s' is not implemented", NodeClassNames[opc])); + guarantee(vopc != opc, "Vector for '%s' is not implemented", NodeClassNames[opc]); switch (vopc) { case Op_AddReductionVI: return new AddReductionVINode(ctrl, n1, n2); @@ -512,7 +530,7 @@ case Op_MulReductionVF: return new MulReductionVFNode(ctrl, n1, n2); case Op_MulReductionVD: return new MulReductionVDNode(ctrl, n1, n2); } - fatal(err_msg_res("Missed vector creation for '%s'", NodeClassNames[vopc])); + fatal("Missed vector creation for '%s'", NodeClassNames[vopc]); return NULL; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/opto/vectornode.hpp --- a/hotspot/src/share/vm/opto/vectornode.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/opto/vectornode.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -309,6 +309,38 @@ virtual int Opcode() const; }; +//------------------------------AbsVFNode-------------------------------------- +// Vector Abs float +class AbsVFNode : public VectorNode { + public: + AbsVFNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {} + virtual int Opcode() const; +}; + +//------------------------------AbsVDNode-------------------------------------- +// Vector Abs double +class AbsVDNode : public VectorNode { + public: + AbsVDNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {} + virtual int Opcode() const; +}; + +//------------------------------NegVFNode-------------------------------------- +// Vector Neg float +class NegVFNode : public VectorNode { + public: + NegVFNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {} + virtual int Opcode() const; +}; + +//------------------------------NegVDNode-------------------------------------- +// Vector Neg double +class NegVDNode : public VectorNode { + public: + NegVDNode(Node* in, const TypeVect* vt) : VectorNode(in,vt) {} + virtual int Opcode() const; +}; + //------------------------------SqrtVDNode-------------------------------------- // Vector Sqrt double class SqrtVDNode : public VectorNode { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/precompiled/precompiled.hpp --- a/hotspot/src/share/vm/precompiled/precompiled.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -128,6 +128,7 @@ # include "interpreter/templateInterpreter.hpp" # include "interpreter/templateTable.hpp" # include "jvmtifiles/jvmti.h" +# include "logging/log.hpp" # include "memory/allocation.hpp" # include "memory/allocation.inline.hpp" # include "memory/heap.hpp" @@ -290,6 +291,9 @@ # include "c1/c1_ValueType.hpp" # include "c1/c1_globals.hpp" #endif // COMPILER1 +#if INCLUDE_JVMCI +# include "jvmci/jvmci_globals.hpp" +#endif // INCLUDE_JVMCI #if INCLUDE_ALL_GCS # include "gc/cms/compactibleFreeListSpace.hpp" # include "gc/cms/concurrentMarkSweepGeneration.hpp" diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/jni.cpp --- a/hotspot/src/share/vm/prims/jni.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/jni.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -81,6 +81,10 @@ #if INCLUDE_ALL_GCS #include "gc/g1/g1SATBCardTableModRefBS.hpp" #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif static jint CurrentVersion = JNI_VERSION_1_8; @@ -3986,6 +3990,19 @@ *vm = (JavaVM *)(&main_vm); *(JNIEnv**)penv = thread->jni_environment(); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + if (UseJVMCICompiler) { + // JVMCI is initialized on a CompilerThread + if (BootstrapJVMCI) { + JavaThread* THREAD = thread; + JVMCICompiler* compiler = JVMCICompiler::instance(CATCH); + compiler->bootstrap(); + } + } + } +#endif + // Tracks the time application was running before GC RuntimeService::record_application_start(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/jniCheck.cpp --- a/hotspot/src/share/vm/prims/jniCheck.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/jniCheck.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -102,7 +102,8 @@ #define UNCHECKED() (unchecked_jni_NativeInterface) static const char * warn_wrong_jnienv = "Using JNIEnv in the wrong thread"; -static const char * warn_bad_class_descriptor = "JNI FindClass received a bad class descriptor \"%s\". A correct class descriptor " \ +static const char * warn_bad_class_descriptor1 = "JNI FindClass received a bad class descriptor \""; +static const char * warn_bad_class_descriptor2 = "\". A correct class descriptor " \ "has no leading \"L\" or trailing \";\". Incorrect descriptors will not be accepted in future releases."; static const char * fatal_using_jnienv_in_nonjava = "FATAL ERROR in native method: Using JNIEnv in non-Java thread"; static const char * warn_other_function_in_critical = "Warning: Calling other JNI functions in the scope of " \ @@ -484,7 +485,8 @@ name[0] == JVM_SIGNATURE_CLASS && // 'L' name[len-1] == JVM_SIGNATURE_ENDCLASS ) { // ';' char msg[JVM_MAXPATHLEN]; - jio_snprintf(msg, JVM_MAXPATHLEN, warn_bad_class_descriptor, name); + jio_snprintf(msg, JVM_MAXPATHLEN, "%s%s%s", + warn_bad_class_descriptor1, name, warn_bad_class_descriptor2); ReportJNIWarning(thr, msg); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/jvm.cpp --- a/hotspot/src/share/vm/prims/jvm.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvm.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -424,6 +424,8 @@ const char* compiler_name = "HotSpot " CSIZE "Client Compiler"; #elif defined(COMPILER2) const char* compiler_name = "HotSpot " CSIZE "Server Compiler"; +#elif INCLUDE_JVMCI + #error "INCLUDE_JVMCI should imply TIERED" #else const char* compiler_name = ""; #endif // compilers diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp --- a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -266,7 +266,7 @@ address scopes_data = nm->scopes_data_begin(); for( pcd = nm->scopes_pcs_begin(); pcd < nm->scopes_pcs_end(); ++pcd ) { - ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->return_oop()); + ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->rethrow_exception(), pcd->return_oop()); ScopeDesc *sd = &sc0; while( !sd->is_top() ) { sd = sd->sender(); } int bci = sd->bci(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/jvmtiEnter.xsl --- a/hotspot/src/share/vm/prims/jvmtiEnter.xsl Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiEnter.xsl Thu Oct 22 11:13:08 2015 -0700 @@ -44,9 +44,6 @@ # include "prims/jvmtiRawMonitor.hpp" # include "prims/jvmtiUtil.hpp" -// There are known-bad format/arg pairings in the code generated by this file. -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - @@ -543,8 +540,8 @@ if (trace_flags) { - tty->print_cr("JVMTI [%s] %s %s env=%d", curr_thread_name, func_name, - JvmtiUtil::error_name(JVMTI_ERROR_INVALID_ENVIRONMENT), env); + tty->print_cr("JVMTI [%s] %s %s env=" PTR_FORMAT, curr_thread_name, func_name, + JvmtiUtil::error_name(JVMTI_ERROR_INVALID_ENVIRONMENT), p2i(env)); } @@ -760,8 +757,8 @@ JVMTI_ERROR_INVALID_MONITOR - - not a raw monitor 0x%x - , rmonitor + - not a raw monitor " PTR_FORMAT " + , p2i(rmonitor) } @@ -777,8 +774,8 @@ JVMTI_ERROR_INVALID_THREAD - - jthread resolved to NULL - jthread = 0x%x - , + - jthread resolved to NULL - jthread = " PTR_FORMAT " + , p2i() } @@ -786,8 +783,8 @@ JVMTI_ERROR_INVALID_THREAD - - oop is not a thread - jthread = 0x%x - , + - oop is not a thread - jthread = " PTR_FORMAT " + , p2i() } @@ -798,8 +795,8 @@ JVMTI_ERROR_THREAD_NOT_ALIVE - - not a Java thread - jthread = 0x%x - , + - not a Java thread - jthread = " PTR_FORMAT " + , p2i() } @@ -842,7 +839,7 @@ JVMTI_ERROR_ILLEGAL_ARGUMENT - - negative depth - jthread = 0x%x + - negative depth - jthread = " INT32_FORMAT " , @@ -861,8 +858,8 @@ JVMTI_ERROR_INVALID_CLASS - - resolved to NULL - jclass = 0x%x - , + - resolved to NULL - jclass = " PTR_FORMAT " + , p2i() } @@ -870,8 +867,8 @@ JVMTI_ERROR_INVALID_CLASS - - not a class - jclass = 0x%x - , + - not a class - jclass = " PTR_FORMAT " + , p2i() } @@ -882,8 +879,8 @@ JVMTI_ERROR_INVALID_CLASS - - is a primitive class - jclass = 0x%x - , + - is a primitive class - jclass = " PTR_FORMAT " + , p2i() } @@ -892,8 +889,8 @@ JVMTI_ERROR_INVALID_CLASS - - no Klass* - jclass = 0x%x - , + - no Klass* - jclass = " PTR_FORMAT " + , p2i() } @@ -1034,12 +1031,12 @@ - + g ='%s' - =0x%x + =" PTR_FORMAT " @@ -1047,7 +1044,15 @@ , - + + + + + + + p2i() + + @@ -1057,7 +1062,7 @@ - =0x%x + =" PTR_FORMAT " @@ -1071,7 +1076,7 @@ , - + p2i() @@ -1083,13 +1088,13 @@ - =0x%x + =" PTR_FORMAT " , - + p2i() @@ -1214,18 +1219,25 @@ - + - =%d + =" INT32_FORMAT " + + + + + + + =" INT64_FORMAT " - =%ld + =" INT64_FORMAT " diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/jvmtiEventController.cpp --- a/hotspot/src/share/vm/prims/jvmtiEventController.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiEventController.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -38,8 +38,6 @@ #include "runtime/vmThread.hpp" #include "runtime/vm_operations.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef JVMTI_TRACE #define EC_TRACE(out) do { \ if (JvmtiTrace::trace_event_controller()) { \ @@ -564,7 +562,7 @@ jlong was_any_env_thread_enabled = JvmtiEventController::_universal_global_event_enabled.get_bits(); jlong any_env_thread_enabled = 0; - EC_TRACE(("JVMTI [-] # recompute enabled - before %llx", was_any_env_thread_enabled)); + EC_TRACE(("JVMTI [-] # recompute enabled - before " UINT64_FORMAT_X, was_any_env_thread_enabled)); // compute non-thread-filters events. // This must be done separately from thread-filtered events, since some @@ -646,7 +644,7 @@ } - EC_TRACE(("JVMTI [-] # recompute enabled - after %llx", any_env_thread_enabled)); + EC_TRACE(("JVMTI [-] # recompute enabled - after " UINT64_FORMAT_X, any_env_thread_enabled)); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/jvmtiExport.cpp --- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -58,8 +58,6 @@ #include "gc/parallel/psMarkSweep.hpp" #endif // INCLUDE_ALL_GCS -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef JVMTI_TRACE #define EVT_TRACE(evt,out) if ((JvmtiTrace::event_trace_flags(evt) & JvmtiTrace::SHOW_EVENT_SENT) != 0) { SafeResourceMark rm; tty->print_cr out; } #define EVT_TRIG_TRACE(evt,out) if ((JvmtiTrace::event_trace_flags(evt) & JvmtiTrace::SHOW_EVENT_TRIGGER) != 0) { SafeResourceMark rm; tty->print_cr out; } @@ -770,7 +768,7 @@ EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD, ("JVMTI [%s] class compile method unload event sent jmethodID " PTR_FORMAT, - JvmtiTrace::safe_get_thread_name(thread), method)); + JvmtiTrace::safe_get_thread_name(thread), p2i(method))); ResourceMark rm(thread); @@ -805,7 +803,7 @@ if (!ets->breakpoint_posted() && ets->is_enabled(JVMTI_EVENT_BREAKPOINT)) { ThreadState old_os_state = thread->osthread()->get_state(); thread->osthread()->set_state(BREAKPOINTED); - EVT_TRACE(JVMTI_EVENT_BREAKPOINT, ("JVMTI [%s] Evt Breakpoint sent %s.%s @ %d", + EVT_TRACE(JVMTI_EVENT_BREAKPOINT, ("JVMTI [%s] Evt Breakpoint sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1258,7 +1256,7 @@ for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { ets->compare_and_set_current_location(mh(), location, JVMTI_EVENT_SINGLE_STEP); if (!ets->single_stepping_posted() && ets->is_enabled(JVMTI_EVENT_SINGLE_STEP)) { - EVT_TRACE(JVMTI_EVENT_SINGLE_STEP, ("JVMTI [%s] Evt Single Step sent %s.%s @ %d", + EVT_TRACE(JVMTI_EVENT_SINGLE_STEP, ("JVMTI [%s] Evt Single Step sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1298,7 +1296,7 @@ if (ets->is_enabled(JVMTI_EVENT_EXCEPTION) && (exception != NULL)) { EVT_TRACE(JVMTI_EVENT_EXCEPTION, - ("JVMTI [%s] Evt Exception thrown sent %s.%s @ %d", + ("JVMTI [%s] Evt Exception thrown sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1374,7 +1372,7 @@ return; } EVT_TRIG_TRACE(JVMTI_EVENT_EXCEPTION_CATCH, - ("JVMTI [%s] Trg unwind_due_to_exception triggered %s.%s @ %s%d - %s", + ("JVMTI [%s] Trg unwind_due_to_exception triggered %s.%s @ %s" INTX_FORMAT " - %s", JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1409,7 +1407,7 @@ for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_enabled(JVMTI_EVENT_EXCEPTION_CATCH) && (exception_handle() != NULL)) { EVT_TRACE(JVMTI_EVENT_EXCEPTION_CATCH, - ("JVMTI [%s] Evt ExceptionCatch sent %s.%s @ %d", + ("JVMTI [%s] Evt ExceptionCatch sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1503,7 +1501,7 @@ JvmtiEnvThreadStateIterator it(state); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_enabled(JVMTI_EVENT_FIELD_ACCESS)) { - EVT_TRACE(JVMTI_EVENT_FIELD_ACCESS, ("JVMTI [%s] Evt Field Access event sent %s.%s @ %d", + EVT_TRACE(JVMTI_EVENT_FIELD_ACCESS, ("JVMTI [%s] Evt Field Access event sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1667,7 +1665,7 @@ for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_enabled(JVMTI_EVENT_FIELD_MODIFICATION)) { EVT_TRACE(JVMTI_EVENT_FIELD_MODIFICATION, - ("JVMTI [%s] Evt Field Modification event sent %s.%s @ %d", + ("JVMTI [%s] Evt Field Modification event sent %s.%s @ " INTX_FORMAT, JvmtiTrace::safe_get_thread_name(thread), (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), (mh() == NULL) ? "NULL" : mh()->name()->as_C_string(), @@ -1807,7 +1805,7 @@ EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, ("JVMTI [%s] class compile method load event sent (by GenerateEvents), jmethodID=" PTR_FORMAT, - JvmtiTrace::safe_get_thread_name(thread), method)); + JvmtiTrace::safe_get_thread_name(thread), p2i(method))); JvmtiEventMark jem(thread); JvmtiJavaThreadEventTransition jet(thread); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -45,8 +45,6 @@ #include "utilities/bitMap.inline.hpp" #include "utilities/events.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - Array* VM_RedefineClasses::_old_methods = NULL; Array* VM_RedefineClasses::_new_methods = NULL; Method** VM_RedefineClasses::_matching_old_methods = NULL; @@ -1714,12 +1712,12 @@ // unless we are trying to stress ldc -> ldc_w rewriting RC_TRACE_WITH_THREAD(0x00080000, THREAD, ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c), - bcp, cp_index, new_index)); + p2i(bcp), cp_index, new_index)); *(bcp + 1) = new_index; } else { RC_TRACE_WITH_THREAD(0x00080000, THREAD, ("%s->ldc_w@" INTPTR_FORMAT " old=%d, new=%d", - Bytecodes::name(c), bcp, cp_index, new_index)); + Bytecodes::name(c), p2i(bcp), cp_index, new_index)); // the new value needs ldc_w instead of ldc u_char inst_buffer[4]; // max instruction size is 4 bytes bcp = (address)inst_buffer; @@ -1780,7 +1778,7 @@ // the original index is mapped so update w/ new value RC_TRACE_WITH_THREAD(0x00080000, THREAD, ("%s@" INTPTR_FORMAT " old=%d, new=%d", Bytecodes::name(c), - bcp, cp_index, new_index)); + p2i(bcp), cp_index, new_index)); // Rewriter::rewrite_method() uses put_native_u2() in this // situation because it is reusing the constant pool index // location for a native index into the ConstantPoolCache. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/jvmtiTagMap.cpp --- a/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/jvmtiTagMap.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -588,7 +588,7 @@ _obj_tag = (_entry == NULL) ? 0 : _entry->tag(); // get the class and the class's tag value - assert(SystemDictionary::Class_klass()->oop_is_instanceMirror(), "Is not?"); + assert(InstanceKlass::cast(SystemDictionary::Class_klass())->is_mirror_instance_klass(), "Is not?"); _klass_tag = tag_for(tag_map, _o->klass()->java_mirror()); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -228,8 +228,8 @@ { ResourceMark rm; Method* m2 = m_klass_non_interface->vtable()->method_at(vmindex); assert(m->name() == m2->name() && m->signature() == m2->signature(), - err_msg("at %d, %s != %s", vmindex, - m->name_and_sig_as_C_string(), m2->name_and_sig_as_C_string())); + "at %d, %s != %s", vmindex, + m->name_and_sig_as_C_string(), m2->name_and_sig_as_C_string()); } #endif //ASSERT } @@ -345,7 +345,7 @@ Symbol* MethodHandles::signature_polymorphic_intrinsic_name(vmIntrinsics::ID iid) { - assert(is_signature_polymorphic_intrinsic(iid), err_msg("iid=%d", iid)); + assert(is_signature_polymorphic_intrinsic(iid), "%d %s", iid, vmIntrinsics::name_at(iid)); switch (iid) { case vmIntrinsics::_invokeBasic: return vmSymbols::invokeBasic_name(); case vmIntrinsics::_linkToVirtual: return vmSymbols::linkToVirtual_name(); @@ -353,7 +353,7 @@ case vmIntrinsics::_linkToSpecial: return vmSymbols::linkToSpecial_name(); case vmIntrinsics::_linkToInterface: return vmSymbols::linkToInterface_name(); } - assert(false, ""); + fatal("unexpected intrinsic id: %d %s", iid, vmIntrinsics::name_at(iid)); return 0; } @@ -365,7 +365,7 @@ case vmIntrinsics::_linkToSpecial: return JVM_REF_invokeSpecial; case vmIntrinsics::_linkToInterface: return JVM_REF_invokeInterface; } - assert(false, err_msg("iid=%d", iid)); + fatal("unexpected intrinsic id: %d %s", iid, vmIntrinsics::name_at(iid)); return 0; } @@ -698,7 +698,7 @@ LinkResolver::resolve_virtual_call(result, Handle(), defc, link_info, false, THREAD); } else { - assert(false, err_msg("ref_kind=%d", ref_kind)); + assert(false, "ref_kind=%d", ref_kind); } if (HAS_PENDING_EXCEPTION) { return empty; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/nativeLookup.cpp --- a/hotspot/src/share/vm/prims/nativeLookup.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -111,6 +111,10 @@ void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls); void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass); void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass); +#if INCLUDE_JVMCI + jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); + void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); +#endif } #define CC (char*) /* cast a literal from (const char*) */ @@ -121,6 +125,10 @@ { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, { CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }, { CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) }, +#if INCLUDE_JVMCI + { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime", NULL, FN_PTR(JVM_GetJVMCIRuntime) }, + { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives", NULL, FN_PTR(JVM_RegisterJVMCINatives) }, +#endif }; static address lookup_special_native(char* jni_name) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/privilegedStack.cpp --- a/hotspot/src/share/vm/prims/privilegedStack.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/privilegedStack.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,8 +30,6 @@ #include "prims/privilegedStack.hpp" #include "runtime/vframe.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void PrivilegedElement::initialize(vframeStream* vfst, oop context, PrivilegedElement* next, TRAPS) { Method* method = vfst->method(); _klass = method->method_holder(); @@ -65,7 +63,7 @@ #ifndef PRODUCT void PrivilegedElement::print_on(outputStream* st) const { - st->print(" 0x%lx ", _frame_id); + st->print(" " PTR_FORMAT " ", p2i(_frame_id)); _klass->print_value_on(st); if (protection_domain() != NULL) { st->print(" "); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/unsafe.cpp --- a/hotspot/src/share/vm/prims/unsafe.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/unsafe.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -44,8 +44,6 @@ #include "gc/g1/g1SATBCardTableModRefBS.hpp" #endif // INCLUDE_ALL_GCS -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - /* * Implementation of class sun.misc.Unsafe */ @@ -126,7 +124,7 @@ "raw [ptr+disp] must be consistent with oop::field_base"); } jlong p_size = HeapWordSize * (jlong)(p->size()); - assert(byte_offset < p_size, err_msg("Unsafe access: offset " INT64_FORMAT " > object's size " INT64_FORMAT, byte_offset, p_size)); + assert(byte_offset < p_size, "Unsafe access: offset " INT64_FORMAT " > object's size " INT64_FORMAT, byte_offset, p_size); } #endif if (sizeof(char*) == sizeof(jint)) // (this constant folds!) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -29,6 +29,7 @@ #include "classfile/classLoaderData.hpp" #include "classfile/stringTable.hpp" #include "code/codeCache.hpp" +#include "compiler/methodMatcher.hpp" #include "jvmtifiles/jvmtiEnv.hpp" #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" @@ -64,8 +65,6 @@ #endif // INCLUDE_NMT -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #define SIZE_T_MAX_VALUE ((size_t) -1) bool WhiteBox::_used = false; @@ -200,8 +199,8 @@ "\tUniverse::narrow_oop_base() is " PTR_FORMAT "\n" "\tUniverse::narrow_oop_use_implicit_null_checks() is %d", UseCompressedOops, - rhs.base(), - Universe::narrow_oop_base(), + p2i(rhs.base()), + p2i(Universe::narrow_oop_base()), Universe::narrow_oop_use_implicit_null_checks()); return; } @@ -625,6 +624,32 @@ return (mh->queued_for_compilation() || nm != NULL); WB_END + +WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring pattern)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, JNI_FALSE); + + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + + ResourceMark rm; + char* method_str = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(pattern)); + + const char* error_msg = NULL; + + BasicMatcher* m = BasicMatcher::parse_method_pattern(method_str, error_msg); + if (m == NULL) { + assert(error_msg != NULL, "Must have error_msg"); + tty->print_cr("Got error: %s", error_msg); + return -1; + } + + // Pattern works - now check if it matches + int result = m->matches(mh); + delete m; + assert(result == 0 || result == 1, "Result out of range"); + return result; +WB_END + class AlwaysFalseClosure : public BoolObjectClosure { public: bool do_object_b(oop p) { return false; } @@ -998,7 +1023,7 @@ ThreadToNativeFromVM ttn(thread); jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); CHECK_JNI_EXCEPTION_(env, NULL); - result = env->NewObjectArray(4, clazz, NULL); + result = env->NewObjectArray(5, clazz, NULL); if (result == NULL) { return result; } @@ -1020,6 +1045,10 @@ CHECK_JNI_EXCEPTION_(env, NULL); env->SetObjectArrayElement(result, 3, id); + jobject address = longBox(thread, env, (jlong) code); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 4, address); + return result; WB_END @@ -1106,6 +1135,13 @@ return codeBlob2objectArray(thread, env, &stub); WB_END +WB_ENTRY(jlong, WB_GetMethodData(JNIEnv* env, jobject wv, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, 0); + methodHandle mh(thread, Method::checked_resolve_jmethod_id(jmid)); + return (jlong) mh->method_data(); +WB_END + WB_ENTRY(jlong, WB_GetThreadStackSize(JNIEnv* env, jobject o)) return (jlong) Thread::current()->stack_size(); WB_END @@ -1115,6 +1151,7 @@ return (jlong) t->stack_available(os::current_stack_pointer()) - (jlong) StackShadowPages * os::vm_page_size(); WB_END + int WhiteBox::array_bytes_to_length(size_t bytes) { return Array::bytes_to_length(bytes); } @@ -1191,6 +1228,11 @@ VMThread::execute(&force_safepoint_op); WB_END +WB_ENTRY(long, WB_GetConstantPool(JNIEnv* env, jobject wb, jclass klass)) + instanceKlassHandle ikh(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + return (long) ikh->constants(); +WB_END + template static bool GetMethodOption(JavaThread* thread, JNIEnv* env, jobject method, jstring name, T* value) { assert(value != NULL, "sanity"); @@ -1430,6 +1472,9 @@ CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, {CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation}, {CC"unlockCompilation", CC"()V", (void*)&WB_UnlockCompilation}, + {CC"matchesMethod", + CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I", + (void*)&WB_MatchesMethod}, {CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag}, {CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag}, {CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag}, @@ -1479,12 +1524,15 @@ {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, {CC"getCompilationActivityMode", CC"()I", (void*)&WB_GetCompilationActivityMode}, + {CC"getMethodData0", CC"(Ljava/lang/reflect/Executable;)J", + (void*)&WB_GetMethodData }, {CC"getCodeBlob", CC"(J)[Ljava/lang/Object;",(void*)&WB_GetCodeBlob }, {CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize }, {CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize }, {CC"assertMatchingSafepointCalls", CC"(ZZ)V", (void*)&WB_AssertMatchingSafepointCalls }, {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, + {CC"getConstantPool0", CC"(Ljava/lang/Class;)J", (void*)&WB_GetConstantPool }, {CC"getMethodBooleanOption", CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/Boolean;", (void*)&WB_GetMethodBooleaneOption}, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp --- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" +#include "compiler/compileTask.hpp" #include "runtime/advancedThresholdPolicy.hpp" #include "runtime/simpleThresholdPolicy.inline.hpp" @@ -162,6 +163,9 @@ // Called with the queue locked and with at least one element CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) { +#if INCLUDE_JVMCI + CompileTask *max_non_jvmci_task = NULL; +#endif CompileTask *max_task = NULL; Method* max_method = NULL; jlong t = os::javaTimeMillis(); @@ -179,6 +183,7 @@ if (PrintTieredEvents) { print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level()); } + task->log_task_dequeued("stale"); compile_queue->remove_and_mark_stale(task); method->clear_queued_for_compilation(); task = next_task; @@ -194,6 +199,15 @@ task = next_task; } +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + if (max_non_jvmci_task != NULL) { + max_task = max_non_jvmci_task; + max_method = max_task->method(); + } + } +#endif + if (max_task->comp_level() == CompLevel_full_profile && TieredStopAtLevel > CompLevel_full_profile && is_method_profiled(max_method)) { max_task->set_comp_level(CompLevel_limited_profile); @@ -354,6 +368,14 @@ if (common(p, method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { next_level = CompLevel_full_optimization; } else if ((this->*p)(i, b, cur_level, method)) { +#if INCLUDE_JVMCI + if (UseJVMCICompiler) { + // Since JVMCI takes a while to warm up, its queue inevitably backs up during + // early VM execution. + next_level = CompLevel_full_profile; + break; + } +#endif // C1-generated fully profiled code is about 30% slower than the limited profile // code that has only invocation and backedge counters. The observation is that // if C2 queue is large enough we can spend too much time in the fully profiled code @@ -362,7 +384,7 @@ // we choose to compile a limited profiled version and then recompile with full profiling // when the load on C2 goes down. if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) > - Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { + Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { next_level = CompLevel_limited_profile; } else { next_level = CompLevel_full_profile; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -32,6 +32,7 @@ #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/taskqueue.hpp" +#include "logging/logConfiguration.hpp" #include "memory/allocation.inline.hpp" #include "memory/universe.inline.hpp" #include "oops/oop.inline.hpp" @@ -50,6 +51,9 @@ #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" #include "utilities/stringUtils.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#endif #if INCLUDE_ALL_GCS #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" @@ -213,6 +217,8 @@ // Set OS specific system properties values os::init_system_properties_values(); + + JVMCI_ONLY(JVMCIRuntime::init_system_properties(&_system_properties);) } // Update/Initialize System properties after JDK version number is known @@ -793,8 +799,10 @@ } static bool set_fp_numeric_flag(const char* name, char* value, Flag::Flags origin) { - double v; - if (sscanf(value, "%lf", &v) != 1) { + char* end; + errno = 0; + double v = strtod(value, &end); + if ((errno != 0) || (*end != 0)) { return false; } @@ -978,9 +986,9 @@ return set_string_flag(real_name, value, origin); } -#define SIGNED_FP_NUMBER_RANGE "[-0123456789.]" +#define SIGNED_FP_NUMBER_RANGE "[-0123456789.eE+]" #define SIGNED_NUMBER_RANGE "[-0123456789]" -#define NUMBER_RANGE "[0123456789]" +#define NUMBER_RANGE "[0123456789eE+-]" char value[BUFLEN + 1]; char value2[BUFLEN + 1]; if (sscanf(arg, "%" XSTR(BUFLEN) NAME_RANGE "=" "%" XSTR(BUFLEN) SIGNED_NUMBER_RANGE "." "%" XSTR(BUFLEN) NUMBER_RANGE "%c", name, value, value2, &dummy) == 3) { @@ -1374,7 +1382,7 @@ } } -#if defined(COMPILER2) || defined(_LP64) || !INCLUDE_CDS +#if defined(COMPILER2) || INCLUDE_JVMCI || defined(_LP64) || !INCLUDE_CDS // Conflict: required to use shared spaces (-Xshare:on), but // incompatible command line options were chosen. @@ -1834,7 +1842,7 @@ void Arguments::set_ergonomics_flags() { select_gc(); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // Shared spaces work fine with other GCs but causes bytecode rewriting // to be disabled, which hurts interpreter performance and decreases // server performance. When -server is specified, keep the default off @@ -1918,7 +1926,7 @@ void Arguments::set_g1_gc_flags() { assert(UseG1GC, "Error"); -#ifdef COMPILER1 +#if defined(COMPILER1) || INCLUDE_JVMCI FastTLABRefill = false; #endif FLAG_SET_DEFAULT(ParallelGCThreads, Abstract_VM_Version::parallel_worker_threads()); @@ -2495,6 +2503,22 @@ } #endif } +#if INCLUDE_JVMCI + if (EnableJVMCI) { + if (!ScavengeRootsInCode) { + warning("forcing ScavengeRootsInCode non-zero because JVMCI is enabled"); + ScavengeRootsInCode = 1; + } + if (FLAG_IS_DEFAULT(TypeProfileLevel)) { + TypeProfileLevel = 0; + } + if (UseJVMCICompiler) { + if (FLAG_IS_DEFAULT(TypeProfileWidth)) { + TypeProfileWidth = 8; + } + } + } +#endif // Check lower bounds of the code cache // Template Interpreter code is approximately 3X larger in debug builds. @@ -3190,6 +3214,26 @@ if (FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true) != Flag::SUCCESS) { return JNI_EINVAL; } + } else if (match_option(option, "-Xlog", &tail)) { + bool ret = false; + if (strcmp(tail, ":help") == 0) { + LogConfiguration::print_command_line_help(defaultStream::output_stream()); + vm_exit(0); + } else if (strcmp(tail, ":disable") == 0) { + LogConfiguration::disable_logging(); + ret = true; + } else if (*tail == '\0') { + ret = LogConfiguration::parse_command_line_arguments(); + assert(ret, "-Xlog without arguments should never fail to parse"); + } else if (*tail == ':') { + ret = LogConfiguration::parse_command_line_arguments(tail + 1); + } + if (ret == false) { + jio_fprintf(defaultStream::error_stream(), + "Invalid -Xlog option '-Xlog%s'\n", + tail); + return JNI_EINVAL; + } // JNI hooks } else if (match_option(option, "-Xcheck", &tail)) { if (!strcmp(tail, ":jni")) { @@ -3463,6 +3507,37 @@ const char* fileSep = os::file_separator(); sprintf(path, "%s%slib%sendorsed", Arguments::get_java_home(), fileSep, fileSep); +#if INCLUDE_JVMCI + jint res = JVMCIRuntime::save_options(_system_properties); + if (res != JNI_OK) { + return res; + } + + if (EnableJVMCI) { + // Append lib/jvmci/*.jar to boot class path + char jvmciDir[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + jio_snprintf(jvmciDir, sizeof(jvmciDir), "%s%slib%sjvmci", Arguments::get_java_home(), fileSep, fileSep); + DIR* dir = os::opendir(jvmciDir); + if (dir != NULL) { + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(jvmciDir), mtInternal); + while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { + const char* name = entry->d_name; + const char* ext = name + strlen(name) - 4; + if (ext > name && strcmp(ext, ".jar") == 0) { + char fileName[JVM_MAXPATHLEN]; + jio_snprintf(fileName, sizeof(fileName), "%s%s%s", jvmciDir, fileSep, name); + scp_p->add_suffix(fileName); + scp_assembly_required = true; + } + } + FREE_C_HEAP_ARRAY(char, dbuf); + os::closedir(dir); + } + } +#endif // INCLUDE_JVMCI + if (CheckEndorsedAndExtDirs) { int nonEmptyDirs = 0; // check endorsed directory @@ -3521,7 +3596,7 @@ FLAG_SET_ERGO(uintx, InitialTenuringThreshold, MaxTenuringThreshold); } -#ifndef COMPILER2 +#if !defined(COMPILER2) && !INCLUDE_JVMCI // Don't degrade server performance for footprint if (FLAG_IS_DEFAULT(UseLargePages) && MaxHeapSize < LargePageHeapSizeThreshold) { @@ -3531,7 +3606,7 @@ FLAG_SET_DEFAULT(UseLargePages, false); } -#else +#elif defined(COMPILER2) if (!FLAG_IS_DEFAULT(OptoLoopAlignment) && FLAG_IS_DEFAULT(MaxLoopPad)) { FLAG_SET_DEFAULT(MaxLoopPad, OptoLoopAlignment-1); } @@ -3690,8 +3765,6 @@ return retcode; } -const int OPTION_BUFFER_SIZE = 1024; - jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* vm_args) { // read file into buffer int fd = ::open(file_name, O_RDONLY); @@ -3702,8 +3775,24 @@ return JNI_ERR; } + struct stat stbuf; + int retcode = os::stat(file_name, &stbuf); + if (retcode != 0) { + jio_fprintf(defaultStream::error_stream(), + "Could not stat options file '%s'\n", + file_name); + os::close(fd); + return JNI_ERR; + } + + if (stbuf.st_size == 0) { + // tell caller there is no option data and that is ok + os::close(fd); + return JNI_OK; + } + // '+ 1' for NULL termination even with max bytes - int bytes_alloc = OPTION_BUFFER_SIZE + 1; + size_t bytes_alloc = stbuf.st_size + 1; char *buf = NEW_C_HEAP_ARRAY_RETURN_NULL(char, bytes_alloc, mtInternal); if (NULL == buf) { @@ -3713,14 +3802,14 @@ return JNI_ENOMEM; } - memset(buf, 0, (unsigned)bytes_alloc); + memset(buf, 0, bytes_alloc); // Fill buffer // Use ::read() instead of os::read because os::read() // might do a thread state transition // and it is too early for that here - int bytes_read = ::read(fd, (void *)buf, (unsigned)bytes_alloc); + ssize_t bytes_read = ::read(fd, (void *)buf, (unsigned)bytes_alloc); os::close(fd); if (bytes_read < 0) { FREE_C_HEAP_ARRAY(char, buf); @@ -3735,16 +3824,7 @@ return JNI_OK; } - // file is larger than OPTION_BUFFER_SIZE - if (bytes_read > bytes_alloc - 1) { - FREE_C_HEAP_ARRAY(char, buf); - jio_fprintf(defaultStream::error_stream(), - "Options file '%s' is larger than %d bytes.\n", - file_name, bytes_alloc - 1); - return JNI_EINVAL; - } - - int retcode = parse_options_buffer(file_name, buf, bytes_read, vm_args); + retcode = parse_options_buffer(file_name, buf, bytes_read, vm_args); FREE_C_HEAP_ARRAY(char, buf); return retcode; @@ -4279,6 +4359,9 @@ #ifdef COMPILER1 || !UseFastLocking #endif // COMPILER1 +#if INCLUDE_JVMCI + || !JVMCIUseFastLocking +#endif ) { if (!FLAG_IS_DEFAULT(UseBiasedLocking) && UseBiasedLocking) { // flag set to true on command line; warn the user that they diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -33,6 +33,9 @@ #include "runtime/commandLineFlagConstraintsRuntime.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" +#if INCLUDE_JVMCI +#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" +#endif class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint { CommandLineFlagConstraintFunc_bool _constraint; @@ -220,7 +223,7 @@ #define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type // the "name" argument must be a string literal -#define INITIAL_CONSTRAINTS_SIZE 16 +#define INITIAL_CONSTRAINTS_SIZE 40 GrowableArray* CommandLineFlagConstraintList::_constraints = NULL; CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse; @@ -251,6 +254,18 @@ IGNORE_RANGE, EMIT_CONSTRAINT_CHECK)); +#if INCLUDE_JVMCI + emit_constraint_no(NULL JVMCI_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, + EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, + EMIT_CONSTRAINT_PRODUCT_FLAG, + EMIT_CONSTRAINT_PD_PRODUCT_FLAG, + EMIT_CONSTRAINT_DIAGNOSTIC_FLAG, + EMIT_CONSTRAINT_EXPERIMENTAL_FLAG, + EMIT_CONSTRAINT_NOTPRODUCT_FLAG, + IGNORE_RANGE, + EMIT_CONSTRAINT_CHECK)); +#endif // INCLUDE_JVMCI + #ifdef COMPILER1 emit_constraint_no(NULL C1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, @@ -274,7 +289,7 @@ EMIT_CONSTRAINT_CHECK)); #endif // COMPILER2 -#ifndef INCLUDE_ALL_GCS +#if INCLUDE_ALL_GCS emit_constraint_no(NULL G1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, EMIT_CONSTRAINT_PRODUCT_FLAG, @@ -305,10 +320,7 @@ // Check constraints for specific constraint type. bool CommandLineFlagConstraintList::check_constraints(CommandLineFlagConstraint::ConstraintType type) { - // Skip if we already checked. - if (type < _validating_type) { - return true; - } + guarantee(type > _validating_type, "Constraint check is out of order."); _validating_type = type; bool status = true; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -54,9 +54,9 @@ enum ConstraintType { // Will be validated during argument processing (Arguments::parse_argument). AtParse = 0, - // Will be validated by CommandLineFlags::check_constraints_of_after_ergo(). - AfterErgo = 1, - // Will be validated by CommandLineFlags::check_constraints_of_after_memory_init(). + // Will be validated by CommandLineFlagConstraintList::check_constraints(AfterErgo). + AfterErgo = 1, + // Will be validated by CommandLineFlagConstraintList::check_constraints(AfterMemoryInit). AfterMemoryInit = 2 }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -23,6 +23,10 @@ */ #include "precompiled.hpp" +#include "oops/metadata.hpp" +#include "runtime/os.hpp" +#include "code/relocInfo.hpp" +#include "interpreter/invocationCounter.hpp" #include "runtime/arguments.hpp" #include "runtime/commandLineFlagConstraintsCompiler.hpp" #include "runtime/commandLineFlagRangeList.hpp" @@ -58,7 +62,7 @@ */ Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose) { int min_number_of_compiler_threads = 0; -#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) +#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) && !INCLUDE_JVMCI // case 1 #else if (!TieredCompilation || (TieredStopAtLevel < CompLevel_full_optimization)) { @@ -84,3 +88,308 @@ return Flag::SUCCESS; } } + +Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose) { + if (value < 0) { + CommandLineError::print(verbose, + "Unable to determine system-specific value for AllocatePrefetchDistance. " + "Please provide appropriate value, if unsure, use 0 to disable prefetching\n"); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { + intx max_value = max_intx; +#if defined(SPARC) + max_value = 1; +#elif defined(X86) + max_value = 3; +#endif + if (value < 0 || value > max_value) { + CommandLineError::print(verbose, + "AllocatePrefetchInstr (" INTX_FORMAT ") must be " + "between 0 and " INTX_FORMAT "\n", value, max_value); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose) { + if (value < 0 || value > max_jint) { + CommandLineError::print(verbose, + "AllocatePrefetchStepSize (" INTX_FORMAT ") " + "must be between 0 and %d\n", + AllocatePrefetchStepSize, + max_jint); + return Flag::VIOLATES_CONSTRAINT; + } + + if (AllocatePrefetchDistance % AllocatePrefetchStepSize != 0) { + CommandLineError::print(verbose, + "AllocatePrefetchDistance (" INTX_FORMAT ") " + "%% AllocatePrefetchStepSize (" INTX_FORMAT ") " + "= " INTX_FORMAT " " + "must be 0\n", + AllocatePrefetchDistance, AllocatePrefetchStepSize, + AllocatePrefetchDistance % AllocatePrefetchStepSize); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose) { + if (value < 0 || value > INT_MAX >> InvocationCounter::count_shift) { + CommandLineError::print(verbose, + "CompileThreshold (" INTX_FORMAT ") " + "must be between 0 and %d\n", + value, + INT_MAX >> InvocationCounter::count_shift); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose) { + int backward_branch_limit; + if (ProfileInterpreter) { + if (OnStackReplacePercentage < InterpreterProfilePercentage) { + CommandLineError::print(verbose, + "OnStackReplacePercentage (" INTX_FORMAT ") must be " + "larger than InterpreterProfilePercentage (" INTX_FORMAT ")\n", + OnStackReplacePercentage, InterpreterProfilePercentage); + return Flag::VIOLATES_CONSTRAINT; + } + + backward_branch_limit = ((CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100) + << InvocationCounter::count_shift; + + if (backward_branch_limit < 0) { + CommandLineError::print(verbose, + "CompileThreshold * (InterpreterProfilePercentage - OnStackReplacePercentage) / 100 = " + INTX_FORMAT " " + "must be between 0 and " INTX_FORMAT ", try changing " + "CompileThreshold, InterpreterProfilePercentage, and/or OnStackReplacePercentage\n", + (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100, + INT_MAX >> InvocationCounter::count_shift); + return Flag::VIOLATES_CONSTRAINT; + } + } else { + if (OnStackReplacePercentage < 0 ) { + CommandLineError::print(verbose, + "OnStackReplacePercentage (" INTX_FORMAT ") must be " + "non-negative\n", OnStackReplacePercentage); + return Flag::VIOLATES_CONSTRAINT; + } + + backward_branch_limit = ((CompileThreshold * OnStackReplacePercentage) / 100) + << InvocationCounter::count_shift; + + if (backward_branch_limit < 0) { + CommandLineError::print(verbose, + "CompileThreshold * OnStackReplacePercentage / 100 = " INTX_FORMAT " " + "must be between 0 and " INTX_FORMAT ", try changing " + "CompileThreshold and/or OnStackReplacePercentage\n", + (CompileThreshold * OnStackReplacePercentage) / 100, + INT_MAX >> InvocationCounter::count_shift); + return Flag::VIOLATES_CONSTRAINT; + } + } + return Flag::SUCCESS; +} + +Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose) { + if (CodeCacheSegmentSize < (uintx)CodeEntryAlignment) { + CommandLineError::print(verbose, + "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " + "larger than or equal to CodeEntryAlignment (" INTX_FORMAT ")" + "to align entry points\n", + CodeCacheSegmentSize, CodeEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } + + if (CodeCacheSegmentSize < sizeof(jdouble)) { + CommandLineError::print(verbose, + "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " + "at least " SIZE_FORMAT " to align constants\n", + CodeCacheSegmentSize, sizeof(jdouble)); + return Flag::VIOLATES_CONSTRAINT; + } + +#ifdef COMPILER2 + if (CodeCacheSegmentSize < (uintx)OptoLoopAlignment) { + CommandLineError::print(verbose, + "CodeCacheSegmentSize (" UINTX_FORMAT ") must be " + "larger than or equal to OptoLoopAlignment (" INTX_FORMAT ")" + "to align inner loops\n", + CodeCacheSegmentSize, OptoLoopAlignment); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + return Flag::SUCCESS; +} + +Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { + if (value < min_jint || value > max_jint) { + CommandLineError::print(verbose, + "CompileThreadPriority (" INTX_FORMAT ") " + "must be between %d and %d. " + "Please also make sure to specify values that are " + "meaningful to your operating system\n", + value, min_jint, max_jint); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { +#ifdef SPARC + if (CodeEntryAlignment % relocInfo::addr_unit() != 0) { + CommandLineError::print(verbose, + "CodeEntryAlignment (" INTX_FORMAT ") must be " + "multiple of NOP size\n", CodeEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + if (!is_power_of_2(value)) { + CommandLineError::print(verbose, + "CodeEntryAlignment (" INTX_FORMAT ") must be " + "a power of two\n", CodeEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } + + if (CodeEntryAlignment < 16) { + CommandLineError::print(verbose, + "CodeEntryAlignment (" INTX_FORMAT ") must be " + "greater than or equal to %d\n", + CodeEntryAlignment, 16); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose) { + if (value < 0 || value > 16) { + CommandLineError::print(verbose, + "OptoLoopAlignment (" INTX_FORMAT ") " + "must be between 0 and 16\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } + + if (!is_power_of_2(value)) { + CommandLineError::print(verbose, + "OptoLoopAlignment (" INTX_FORMAT ") " + "must be a power of two\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } + +#ifdef SPARC + if (OptoLoopAlignment % relocInfo::addr_unit() != 0) { + CommandLineError::print(verbose, + "OptoLoopAlignment (" INTX_FORMAT ") must be " + "multiple of NOP size\n"); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + return Flag::SUCCESS; +} + +Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose) { + if (value != 0) { + CommandLineError::print(verbose, + "ArraycopyDstPrefetchDistance (" INTX_FORMAT ") must be 0\n"); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose) { + if (value != 0) { + CommandLineError::print(verbose, + "ArraycopySrcPrefetchDistance (" INTX_FORMAT ") must be 0\n"); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose) { + for (int i = 0; i < 3; i++) { + if (value % 10 > 2) { + CommandLineError::print(verbose, + "Invalid value (" UINTX_FORMAT ") " + "in TypeProfileLevel at position %d\n", value, i); + return Flag::VIOLATES_CONSTRAINT; + } + value = value / 10; + } + + return Flag::SUCCESS; +} + +#ifdef COMPILER2 +Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { + if (InteriorEntryAlignment > CodeEntryAlignment) { + CommandLineError::print(verbose, + "InteriorEntryAlignment (" INTX_FORMAT ") must be " + "less than or equal to CodeEntryAlignment (" INTX_FORMAT ")\n", + InteriorEntryAlignment, CodeEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } + +#ifdef SPARC + if (InteriorEntryAlignment % relocInfo::addr_unit() != 0) { + CommandLineError::print(verbose, + "InteriorEntryAlignment (" INTX_FORMAT ") must be " + "multiple of NOP size\n"); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + if (!is_power_of_2(value)) { + CommandLineError::print(verbose, + "InteriorEntryAlignment (" INTX_FORMAT ") must be " + "a power of two\n", InteriorEntryAlignment); + return Flag::VIOLATES_CONSTRAINT; + } + + int minimum_alignment = 16; +#if defined(SPARC) || (defined(X86) && !defined(AMD64)) + minimum_alignment = 4; +#endif + + if (InteriorEntryAlignment < minimum_alignment) { + CommandLineError::print(verbose, + "InteriorEntryAlignment (" INTX_FORMAT ") must be " + "greater than or equal to %d\n", + InteriorEntryAlignment, minimum_alignment); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} + +Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose) { + if (value < MaxNodeLimit * 2 / 100 || value > MaxNodeLimit * 40 / 100) { + CommandLineError::print(verbose, + "NodeLimitFudgeFactor must be between 2%% and 40%% " + "of MaxNodeLimit (" INTX_FORMAT ")\n", + MaxNodeLimit); + return Flag::VIOLATES_CONSTRAINT; + } + + return Flag::SUCCESS; +} +#endif // COMPILER2 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -38,4 +38,34 @@ Flag::Error CICompilerCountConstraintFunc(intx value, bool verbose); +Flag::Error AllocatePrefetchDistanceConstraintFunc(intx value, bool verbose); + +Flag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose); + +Flag::Error AllocatePrefetchStepSizeConstraintFunc(intx value, bool verbose); + +Flag::Error CompileThresholdConstraintFunc(intx value, bool verbose); + +Flag::Error OnStackReplacePercentageConstraintFunc(intx value, bool verbose); + +Flag::Error CodeCacheSegmentSizeConstraintFunc(uintx value, bool verbose); + +Flag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose); + +Flag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose); + +Flag::Error OptoLoopAlignmentConstraintFunc(intx value, bool verbose); + +Flag::Error ArraycopyDstPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +Flag::Error ArraycopySrcPrefetchDistanceConstraintFunc(uintx value, bool verbose); + +Flag::Error TypeProfileLevelConstraintFunc(uintx value, bool verbose); + +#ifdef COMPILER2 +Flag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose); + +Flag::Error NodeLimitFudgeFactorConstraintFunc(intx value, bool verbose); +#endif + #endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP */ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -23,16 +23,19 @@ */ #include "precompiled.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/collectorPolicy.hpp" +#include "gc/shared/threadLocalAllocBuffer.hpp" #include "runtime/arguments.hpp" #include "runtime/commandLineFlagConstraintsGC.hpp" #include "runtime/commandLineFlagRangeList.hpp" #include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "utilities/defaultStream.hpp" #if INCLUDE_ALL_GCS #include "gc/g1/g1_globals.hpp" #include "gc/g1/heapRegionBounds.inline.hpp" -#include "gc/parallel/parallelScavengeHeap.hpp" #include "gc/shared/plab.hpp" #endif // INCLUDE_ALL_GCS #ifdef COMPILER1 @@ -42,6 +45,71 @@ #include "opto/c2_globals.hpp" #endif // COMPILER2 +// Some flags that have default values that indicate that the +// JVM should automatically determine an appropriate value +// for that flag. In those cases it is only appropriate for the +// constraint checking to be done if the user has specified the +// value(s) of the flag(s) on the command line. In the constraint +// checking functions, FLAG_IS_CMDLINE() is used to check if +// the flag has been set by the user and so should be checked. + +#if INCLUDE_ALL_GCS +static Flag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) { + // CMSWorkQueueDrainThreshold is verified to be less than max_juint + if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) { + CommandLineError::print(verbose, + "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold (" + UINTX_FORMAT ") is too large\n", + threads, threshold); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} +#endif + +// As ParallelGCThreads differs among GC modes, we need constraint function. +Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + // Parallel GC passes ParallelGCThreads when creating GrowableArray as 'int' type parameter. + // So can't exceed with "max_jint" + if (UseParallelGC && (value > (uint)max_jint)) { + CommandLineError::print(verbose, + "ParallelGCThreads (" UINT32_FORMAT ") must be " + "less than or equal to " UINT32_FORMAT " for Parallel GC\n", + value, max_jint); + return Flag::VIOLATES_CONSTRAINT; + } + // To avoid overflow at ParScanClosure::do_oop_work. + if (UseConcMarkSweepGC && (value > (max_jint / 10))) { + CommandLineError::print(verbose, + "ParallelGCThreads (" UINT32_FORMAT ") must be " + "less than or equal to " UINT32_FORMAT " for CMS GC\n", + value, (max_jint / 10)); + return Flag::VIOLATES_CONSTRAINT; + } + status = ParallelGCThreadsAndCMSWorkQueueDrainThreshold(value, CMSWorkQueueDrainThreshold, verbose); +#endif + return status; +} + +// As ConcGCThreads should be smaller than ParallelGCThreads, +// we need constraint function. +Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) { +#if INCLUDE_ALL_GCS + // CMS and G1 GCs use ConcGCThreads. + if ((UseConcMarkSweepGC || UseG1GC) && (value > ParallelGCThreads)) { + CommandLineError::print(verbose, + "ConcGCThreads (" UINT32_FORMAT ") must be " + "less than or equal to ParallelGCThreads (" UINT32_FORMAT ")\n", + value, ParallelGCThreads); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} + static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) { #if INCLUDE_ALL_GCS if ((UseConcMarkSweepGC || UseG1GC) && (value < PLAB::min_size())) { @@ -69,16 +137,40 @@ } static Flag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) { - if (MinPLABSizeBounds(name, value, verbose) == Flag::SUCCESS) { + Flag::Error status = MinPLABSizeBounds(name, value, verbose); + + if (status == Flag::SUCCESS) { return MaxPLABSizeBounds(name, value, verbose); } - return Flag::VIOLATES_CONSTRAINT; + return status; } Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) { return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose); } +Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + if (value == 0) { + CommandLineError::print(verbose, + "OldPLABSize (" SIZE_FORMAT ") must be greater than 0", + value); + return Flag::VIOLATES_CONSTRAINT; + } + // For CMS, OldPLABSize is the number of free blocks of a given size that are used when + // replenishing the local per-worker free list caches. + // For more details, please refer to Arguments::set_cms_and_parnew_gc_flags(). + status = MaxPLABSizeBounds("OldPLABSize", value, verbose); + } else { + status = MinMaxPLABSizeBounds("OldPLABSize", value, verbose); + } +#endif + return status; +} + Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxHeapFreeRatio) { CommandLineError::print(verbose, @@ -103,6 +195,23 @@ } } +static Flag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) { + if ((softRef > 0) && ((maxHeap / M) > (max_uintx / softRef))) { + CommandLineError::print(verbose, + "Desired lifetime of SoftReferences cannot be expressed correctly. " + "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB " + "(" INTX_FORMAT ") is too large\n", + maxHeap, softRef); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) { + return CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(MaxHeapSize, value, verbose); +} + Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) { if (value > MaxMetaspaceFreeRatio) { CommandLineError::print(verbose, @@ -127,45 +236,111 @@ } } -// GC workaround for "-XX:+UseConcMarkSweepGC" -// which sets InitialTenuringThreshold to 7 but leaves MaxTenuringThreshold remaining at 6 -// and therefore would invalidate the constraint -#define UseConcMarkSweepGCWorkaroundIfNeeded(initial, max) { \ - if ((initial == 7) && (max == 6)) { \ - return Flag::SUCCESS; \ - } \ +Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + // InitialTenuringThreshold is only used for ParallelGC. + if (UseParallelGC && (value > MaxTenuringThreshold)) { + CommandLineError::print(verbose, + "InitialTenuringThreshold (" UINTX_FORMAT ") must be " + "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", + value, MaxTenuringThreshold); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; } -Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) { - UseConcMarkSweepGCWorkaroundIfNeeded(value, MaxTenuringThreshold); +Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + // As only ParallelGC uses InitialTenuringThreshold, + // we don't need to compare InitialTenuringThreshold with MaxTenuringThreshold. + if (UseParallelGC && (value < InitialTenuringThreshold)) { + CommandLineError::print(verbose, + "MaxTenuringThreshold (" UINTX_FORMAT ") must be " + "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n", + value, InitialTenuringThreshold); + return Flag::VIOLATES_CONSTRAINT; + } +#endif - if (value > MaxTenuringThreshold) { + // MaxTenuringThreshold=0 means NeverTenure=false && AlwaysTenure=true + if ((value == 0) && (NeverTenure || !AlwaysTenure)) { CommandLineError::print(verbose, - "InitialTenuringThreshold (" UINTX_FORMAT ") must be " - "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n", - value, MaxTenuringThreshold); + "MaxTenuringThreshold (0) should match to NeverTenure=false " + "&& AlwaysTenure=true. But we have NeverTenure=%s " + "AlwaysTenure=%s\n", + NeverTenure ? "true" : "false", + AlwaysTenure ? "true" : "false"); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} + +#if INCLUDE_ALL_GCS +Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + + // Default value of G1RSetRegionEntries=0 means will be set ergonomically. + // Minimum value is 1. + if (FLAG_IS_CMDLINE(G1RSetRegionEntries) && (value < 1)) { + CommandLineError::print(verbose, + "G1RSetRegionEntries (" INTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; } } -Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) { - UseConcMarkSweepGCWorkaroundIfNeeded(InitialTenuringThreshold, value); +Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; - if (value < InitialTenuringThreshold) { + // Default value of G1RSetSparseRegionEntries=0 means will be set ergonomically. + // Minimum value is 1. + if (FLAG_IS_CMDLINE(G1RSetSparseRegionEntries) && (value < 1)) { CommandLineError::print(verbose, - "MaxTenuringThreshold (" UINTX_FORMAT ") must be " - "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n", - value, InitialTenuringThreshold); + "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; } } -#if INCLUDE_ALL_GCS +Flag::Error G1YoungSurvRateNumRegionsSummaryConstraintFunc(intx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + + if (value > (intx)HeapRegionBounds::target_number()) { + CommandLineError::print(verbose, + "G1YoungSurvRateNumRegionsSummary (" INTX_FORMAT ") must be " + "less than or equal to region count (" SIZE_FORMAT ")\n", + value, HeapRegionBounds::target_number()); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + + // Default value of G1HeapRegionSize=0 means will be set ergonomically. + if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) { + CommandLineError::print(verbose, + "G1HeapRegionSize (" SIZE_FORMAT ") must be " + "greater than or equal to ergonomic heap region minimum size\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + if (value > G1MaxNewSizePercent) { CommandLineError::print(verbose, "G1NewSizePercent (" UINTX_FORMAT ") must be " @@ -178,6 +353,8 @@ } Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) { + if (!UseG1GC) return Flag::SUCCESS; + if (value < G1NewSizePercent) { CommandLineError::print(verbose, "G1MaxNewSizePercent (" UINTX_FORMAT ") must be " @@ -188,15 +365,56 @@ return Flag::SUCCESS; } } +#endif // INCLUDE_ALL_GCS -#endif // INCLUDE_ALL_GCS +Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC && (value > ((uintx)max_jint / (uintx)ParallelGCThreads))) { + CommandLineError::print(verbose, + "ParGCStridesPerThread (" UINTX_FORMAT ") must be " + "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n", + value, ((uintx)max_jint / (uintx)ParallelGCThreads)); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) { - if (value > CMSOldPLABMax) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + if (value > CMSOldPLABMax) { + CommandLineError::print(verbose, + "CMSOldPLABMin (" SIZE_FORMAT ") must be " + "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n", + value, CMSOldPLABMax); + return Flag::VIOLATES_CONSTRAINT; + } + status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose); + } +#endif + return status; +} + +Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) { + Flag::Error status = Flag::SUCCESS; + +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose); + } +#endif + return status; +} + +Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) { + if (value > MarkStackSizeMax) { CommandLineError::print(verbose, - "CMSOldPLABMin (" SIZE_FORMAT ") must be " - "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n", - value, CMSOldPLABMax); + "MarkStackSize (" SIZE_FORMAT ") must be " + "less than or equal to MarkStackSizeMax (" SIZE_FORMAT ")\n", + value, MarkStackSizeMax); return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; @@ -204,23 +422,212 @@ } Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) { - if (value <= CMSPrecleanNumerator) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) { CommandLineError::print(verbose, "CMSPrecleanDenominator (" UINTX_FORMAT ") must be " "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n", value, CMSPrecleanNumerator); return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} + +Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) { + CommandLineError::print(verbose, + "CMSPrecleanNumerator (" UINTX_FORMAT ") must be " + "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n", + value, CMSPrecleanDenominator); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + return Flag::SUCCESS; +} + +Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseConcMarkSweepGC) { + return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose); + } +#endif + return Flag::SUCCESS; +} + +Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) { + CommandLineError::print(verbose, + "MaxGCPauseMillis (" UINTX_FORMAT ") must be " + "less than GCPauseIntervalMillis (" UINTX_FORMAT ")\n", + value, GCPauseIntervalMillis); + return Flag::VIOLATES_CONSTRAINT; + } +#endif + + return Flag::SUCCESS; +} + +Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) { +#if INCLUDE_ALL_GCS + if (UseG1GC) { + if (FLAG_IS_CMDLINE(GCPauseIntervalMillis)) { + if (value < 1) { + CommandLineError::print(verbose, + "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " + "greater than or equal to 1\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } + if (value <= MaxGCPauseMillis) { + CommandLineError::print(verbose, + "GCPauseIntervalMillis (" UINTX_FORMAT ") must be " + "greater than MaxGCPauseMillis (" UINTX_FORMAT ")\n", + value, MaxGCPauseMillis); + return Flag::VIOLATES_CONSTRAINT; + } + } + } +#endif + return Flag::SUCCESS; +} + +Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) { + size_t aligned_max = (size_t)align_size_down(max_uintx/2, Metaspace::reserve_alignment_words()); + if (value > aligned_max) { + CommandLineError::print(verbose, + "InitialBootClassLoaderMetaspaceSize (" SIZE_FORMAT ") must be " + "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", + value, aligned_max); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} + +static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) { + // For G1 GC, we don't know until G1CollectorPolicy is created. + size_t heap_alignment; + +#if INCLUDE_ALL_GCS + if (UseG1GC) { + heap_alignment = HeapRegionBounds::max_size(); + } else +#endif + { + heap_alignment = CollectorPolicy::compute_heap_alignment(); + } + + // Not to overflow 'align_size_up(value, _heap_alignment) used from CollectorPolicy::initialize_flags()'. + size_t aligned_max = ((max_uintx - heap_alignment) & ~(heap_alignment-1)); + if (value > aligned_max) { + CommandLineError::print(verbose, + "%s (" SIZE_FORMAT ") must be " + "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n", + name, value, aligned_max); + return Flag::VIOLATES_CONSTRAINT; + } + return Flag::SUCCESS; +} + +Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) { + return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose); +} + +Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) { + Flag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose); + + if (status == Flag::SUCCESS) { + status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose); + } + return status; +} + +Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) { +#ifdef _LP64 +#if INCLUDE_ALL_GCS + // Overflow would happen for uint type variable of YoungGenSizer::_min_desired_young_length + // when the value to be assigned exceeds uint range. + // i.e. result of '(uint)(NewSize / region size(1~32MB))' + // So maximum of NewSize should be 'max_juint * 1M' + if (UseG1GC && (value > (max_juint * 1 * M))) { + CommandLineError::print(verbose, + "NewSize (" SIZE_FORMAT ") must be less than ergonomic maximum value\n", + value); + return Flag::VIOLATES_CONSTRAINT; + } +#endif // INCLUDE_ALL_GCS +#endif // _LP64 + return Flag::SUCCESS; +} + +Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) { + // At least, alignment reserve area is needed. + if (value < ThreadLocalAllocBuffer::alignment_reserve_in_bytes()) { + CommandLineError::print(verbose, + "MinTLABSize (" SIZE_FORMAT ") must be " + "greater than or equal to reserved area in TLAB (" SIZE_FORMAT ")\n", + value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes()); + return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; } } -Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) { - if (value > (CMSPrecleanDenominator - 1)) { +Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) { + // Skip for default value of zero which means set ergonomically. + if (FLAG_IS_CMDLINE(TLABSize)) { + if (value < MinTLABSize) { + CommandLineError::print(verbose, + "TLABSize (" SIZE_FORMAT ") must be " + "greater than or equal to MinTLABSize (" SIZE_FORMAT ")\n", + value, MinTLABSize); + return Flag::VIOLATES_CONSTRAINT; + } + if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) { + CommandLineError::print(verbose, + "TLABSize (" SIZE_FORMAT ") must be " + "less than or equal to ergonomic TLAB maximum size (" SIZE_FORMAT ")\n", + value, (ThreadLocalAllocBuffer::max_size() * HeapWordSize)); + return Flag::VIOLATES_CONSTRAINT; + } + } + return Flag::SUCCESS; +} + +Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) { + if (FLAG_IS_CMDLINE(SurvivorRatio) && + (value > (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()))) { CommandLineError::print(verbose, - "CMSPrecleanNumerator (" UINTX_FORMAT ") must be " - "less than or equal to CMSPrecleanDenominator - 1 (" UINTX_FORMAT ")\n", - value, CMSPrecleanDenominator - 1); + "SurvivorRatio (" UINTX_FORMAT ") must be " + "less than or equal to ergonomic SurvivorRatio maximum (" SIZE_FORMAT ")\n", + value, + (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment())); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) { + if (value > MaxMetaspaceSize) { + CommandLineError::print(verbose, + "MetaspaceSize (" SIZE_FORMAT ") must be " + "less than or equal to MaxMetaspaceSize (" SIZE_FORMAT ")\n", + value, MaxMetaspaceSize); + return Flag::VIOLATES_CONSTRAINT; + } else { + return Flag::SUCCESS; + } +} + +Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { + if (value < MetaspaceSize) { + CommandLineError::print(verbose, + "MaxMetaspaceSize (" SIZE_FORMAT ") must be " + "greater than or equal to MetaspaceSize (" SIZE_FORMAT ")\n", + value, MaxMetaspaceSize); return Flag::VIOLATES_CONSTRAINT; } else { return Flag::SUCCESS; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -34,27 +34,45 @@ * an appropriate error value. */ +Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose); +Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose); Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose); - +Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose); Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose); Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose); - +Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose); Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose); - Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose); Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose); #if INCLUDE_ALL_GCS +Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose); +Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose); +Flag::Error G1YoungSurvRateNumRegionsSummaryConstraintFunc(intx value, bool verbose); +Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose); Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose); Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose); #endif // INCLUDE_ALL_GCS +Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose); Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose); - +Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose); +Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose); Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose); Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose); - +Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose); +Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose); +Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose); +Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose); +Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose); +Flag::Error NewSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose); +Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose); +Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose); +Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose); Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose); #endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP */ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp --- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -278,7 +278,7 @@ // Generate func argument to pass into emit_range_xxx functions #define EMIT_RANGE_CHECK(a, b) , a, b -#define INITIAL_RANGES_SIZE 128 +#define INITIAL_RANGES_SIZE 165 GrowableArray* CommandLineFlagRangeList::_ranges = NULL; // Check the ranges of all flags that have them @@ -309,6 +309,18 @@ EMIT_RANGE_CHECK, IGNORE_CONSTRAINT)); +#if INCLUDE_JVMCI + emit_range_no(NULL JVMCI_FLAGS(EMIT_RANGE_DEVELOPER_FLAG, + EMIT_RANGE_PD_DEVELOPER_FLAG, + EMIT_RANGE_PRODUCT_FLAG, + EMIT_RANGE_PD_PRODUCT_FLAG, + EMIT_RANGE_DIAGNOSTIC_FLAG, + EMIT_RANGE_EXPERIMENTAL_FLAG, + EMIT_RANGE_NOTPRODUCT_FLAG, + EMIT_RANGE_CHECK, + IGNORE_CONSTRAINT)); +#endif // INCLUDE_JVMCI + #ifdef COMPILER1 emit_range_no(NULL C1_FLAGS(EMIT_RANGE_DEVELOPER_FLAG, EMIT_RANGE_PD_DEVELOPER_FLAG, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/deoptimization.cpp --- a/hotspot/src/share/vm/runtime/deoptimization.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -37,6 +37,7 @@ #include "memory/resourceArea.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" +#include "oops/fieldStreams.hpp" #include "oops/verifyOopClosure.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/biasedLocking.hpp" @@ -53,7 +54,11 @@ #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC +#if INCLUDE_JVMCI +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciJavaClasses.hpp" +#endif + bool DeoptimizationMarker::_is_active = false; @@ -112,7 +117,7 @@ tty->print_cr(" size_of_deoptimized_frame = %d", _size_of_deoptimized_frame); tty->print( " frame_sizes: "); for (int index = 0; index < number_of_frames(); index++) { - tty->print("%d ", frame_sizes()[index]); + tty->print(INTX_FORMAT " ", frame_sizes()[index]); } tty->cr(); } @@ -132,6 +137,9 @@ // handler. Note this fact before we start generating temporary frames // that can confuse an asynchronous stack walker. This counter is // decremented at the end of unpack_frames(). + if (TraceDeoptimization) { + tty->print_cr("Deoptimizing thread " INTPTR_FORMAT, p2i(thread)); + } thread->inc_in_deopt_handler(); return fetch_unroll_info_helper(thread); @@ -159,6 +167,7 @@ // Set the deoptee nmethod assert(thread->deopt_nmethod() == NULL, "Pending deopt!"); thread->set_deopt_nmethod(deoptee.cb()->as_nmethod_or_null()); + bool skip_internal = thread->deopt_nmethod() != NULL && !thread->deopt_nmethod()->compiler()->is_jvmci(); if (VerifyStack) { thread->validate_frame_layout(); @@ -179,11 +188,13 @@ bool realloc_failures = false; -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI // Reallocate the non-escaping objects and restore their fields. Then // relock objects if synchronization on them was eliminated. +#ifndef INCLUDE_JVMCI if (DoEscapeAnalysis || EliminateNestedLocks) { if (EliminateAllocations) { +#endif // INCLUDE_JVMCI assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames"); GrowableArray* objects = chunk->at(0)->scope()->objects(); @@ -206,18 +217,18 @@ assert(Universe::heap()->is_in_or_null(result), "must be heap pointer"); if (TraceDeoptimization) { ttyLocker ttyl; - tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, (void *)result, thread); + tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, p2i(result), p2i(thread)); } } if (objects != NULL) { JRT_BLOCK realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD); JRT_END - reassign_fields(&deoptee, &map, objects, realloc_failures); + reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal); #ifndef PRODUCT if (TraceDeoptimization) { ttyLocker ttyl; - tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread); + tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, p2i(thread)); print_objects(objects, realloc_failures); } #endif @@ -226,8 +237,10 @@ // Restore result. deoptee.set_saved_oop_result(&map, return_value()); } +#ifndef INCLUDE_JVMCI } if (EliminateLocks) { +#endif // INCLUDE_JVMCI #ifndef PRODUCT bool first = true; #endif @@ -238,37 +251,40 @@ if (monitors->is_nonempty()) { relock_objects(monitors, thread, realloc_failures); #ifndef PRODUCT - if (TraceDeoptimization) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; for (int j = 0; j < monitors->length(); j++) { MonitorInfo* mi = monitors->at(j); if (mi->eliminated()) { if (first) { first = false; - tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread); + tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, p2i(thread)); } if (mi->owner_is_scalar_replaced()) { Klass* k = java_lang_Class::as_Klass(mi->owner_klass()); tty->print_cr(" failed reallocation for klass %s", k->external_name()); } else { - tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner()); + tty->print_cr(" object <" INTPTR_FORMAT "> locked", p2i(mi->owner())); } } } } -#endif +#endif // !PRODUCT } } +#ifndef INCLUDE_JVMCI } } -#endif // COMPILER2 +#endif // INCLUDE_JVMCI +#endif // COMPILER2 || INCLUDE_JVMCI + // Ensure that no safepoint is taken after pointers have been stored // in fields of rematerialized objects. If a safepoint occurs from here on // out the java state residing in the vframeArray will be missed. No_Safepoint_Verifier no_safepoint; vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI if (realloc_failures) { pop_frames_failed_reallocs(thread, array); } @@ -318,7 +334,11 @@ unpack_sp = deoptee.unextended_sp(); #ifdef ASSERT - assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking"); + assert(cb->is_deoptimization_stub() || + cb->is_uncommon_trap_stub() || + strcmp("Stub", cb->name()) == 0 || + strcmp("Stub", cb->name()) == 0, + "unexpected code blob: %s", cb->name()); #endif #else intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp(); @@ -550,11 +570,12 @@ #ifndef PRODUCT if (TraceDeoptimization) { ttyLocker ttyl; - tty->print_cr("DEOPT UNPACKING thread " INTPTR_FORMAT " vframeArray " INTPTR_FORMAT " mode %d", thread, array, exec_mode); + tty->print_cr("DEOPT UNPACKING thread " INTPTR_FORMAT " vframeArray " INTPTR_FORMAT " mode %d", + p2i(thread), p2i(array), exec_mode); } #endif Events::log(thread, "DEOPT UNPACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT " mode %d", - stub_frame.pc(), stub_frame.sp(), exec_mode); + p2i(stub_frame.pc()), p2i(stub_frame.sp()), exec_mode); UnrollBlock* info = array->unroll_block(); @@ -690,7 +711,7 @@ tty->print_cr(" top_frame_expression_stack_adjustment = %d", top_frame_expression_stack_adjustment); tty->print_cr(" exec_mode = %d", exec_mode); tty->print_cr(" cur_invoke_parameter_size = %d", cur_invoke_parameter_size); - tty->print_cr(" Thread = " INTPTR_FORMAT ", thread ID = " UINTX_FORMAT, thread, thread->osthread()->thread_id()); + tty->print_cr(" Thread = " INTPTR_FORMAT ", thread ID = %d", p2i(thread), thread->osthread()->thread_id()); tty->print_cr(" Interpreted frames:"); for (int k = 0; k < cur_array->frames(); k++) { vframeArrayElement* el = cur_array->element(k); @@ -721,7 +742,7 @@ Deoptimization::DeoptAction Deoptimization::_unloaded_action = Deoptimization::Action_reinterpret; -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArray* objects, TRAPS) { Handle pending_exception(thread->pending_exception()); const char* exception_file = thread->exception_file(); @@ -769,77 +790,6 @@ return failures; } -// This assumes that the fields are stored in ObjectValue in the same order -// they are yielded by do_nonstatic_fields. -class FieldReassigner: public FieldClosure { - frame* _fr; - RegisterMap* _reg_map; - ObjectValue* _sv; - InstanceKlass* _ik; - oop _obj; - - int _i; -public: - FieldReassigner(frame* fr, RegisterMap* reg_map, ObjectValue* sv, oop obj) : - _fr(fr), _reg_map(reg_map), _sv(sv), _obj(obj), _i(0) {} - - int i() const { return _i; } - - - void do_field(fieldDescriptor* fd) { - intptr_t val; - StackValue* value = - StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(i())); - int offset = fd->offset(); - switch (fd->field_type()) { - case T_OBJECT: case T_ARRAY: - assert(value->type() == T_OBJECT, "Agreement."); - _obj->obj_field_put(offset, value->get_obj()()); - break; - - case T_LONG: case T_DOUBLE: { - assert(value->type() == T_INT, "Agreement."); - StackValue* low = - StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(++_i)); -#ifdef _LP64 - jlong res = (jlong)low->get_int(); -#else -#ifdef SPARC - // For SPARC we have to swap high and low words. - jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); -#else - jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); -#endif //SPARC -#endif - _obj->long_field_put(offset, res); - break; - } - // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. - case T_INT: case T_FLOAT: // 4 bytes. - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->int_field_put(offset, (jint)*((jint*)&val)); - break; - - case T_SHORT: case T_CHAR: // 2 bytes - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->short_field_put(offset, (jshort)*((jint*)&val)); - break; - - case T_BOOLEAN: case T_BYTE: // 1 byte - assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - _obj->bool_field_put(offset, (jboolean)*((jint*)&val)); - break; - - default: - ShouldNotReachHere(); - } - _i++; - } -}; - // restore elements of an eliminated type array void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) { int index = 0; @@ -867,11 +817,43 @@ } // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. - case T_INT: case T_FLOAT: // 4 bytes. + case T_INT: case T_FLOAT: { // 4 bytes. assert(value->type() == T_INT, "Agreement."); - val = value->get_int(); - obj->int_at_put(index, (jint)*((jint*)&val)); + bool big_value = false; + if (i + 1 < sv->field_size() && type == T_INT) { + if (sv->field_at(i)->is_location()) { + Location::Type type = ((LocationValue*) sv->field_at(i))->location().type(); + if (type == Location::dbl || type == Location::lng) { + big_value = true; + } + } else if (sv->field_at(i)->is_constant_int()) { + ScopeValue* next_scope_field = sv->field_at(i + 1); + if (next_scope_field->is_constant_long() || next_scope_field->is_constant_double()) { + big_value = true; + } + } + } + + if (big_value) { + StackValue* low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++i)); + #ifdef _LP64 + jlong res = (jlong)low->get_int(); + #else + #ifdef SPARC + // For SPARC we have to swap high and low words. + jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); + #else + jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); + #endif //SPARC + #endif + obj->int_at_put(index, (jint)*((jint*)&res)); + obj->int_at_put(++index, (jint)*(((jint*)&res) + 1)); + } else { + val = value->get_int(); + obj->int_at_put(index, (jint)*((jint*)&val)); + } break; + } case T_SHORT: case T_CHAR: // 2 bytes assert(value->type() == T_INT, "Agreement."); @@ -902,22 +884,135 @@ } } +class ReassignedField { +public: + int _offset; + BasicType _type; +public: + ReassignedField() { + _offset = 0; + _type = T_ILLEGAL; + } +}; + +int compare(ReassignedField* left, ReassignedField* right) { + return left->_offset - right->_offset; +} + +// Restore fields of an eliminated instance object using the same field order +// returned by HotSpotResolvedObjectTypeImpl.getInstanceFields(true) +static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap* reg_map, ObjectValue* sv, int svIndex, oop obj, bool skip_internal) { + if (klass->superklass() != NULL) { + svIndex = reassign_fields_by_klass(klass->superklass(), fr, reg_map, sv, svIndex, obj, skip_internal); + } + + GrowableArray* fields = new GrowableArray(); + for (AllFieldStream fs(klass); !fs.done(); fs.next()) { + if (!fs.access_flags().is_static() && (!skip_internal || !fs.access_flags().is_internal())) { + ReassignedField field; + field._offset = fs.offset(); + field._type = FieldType::basic_type(fs.signature()); + fields->append(field); + } + } + fields->sort(compare); + for (int i = 0; i < fields->length(); i++) { + intptr_t val; + ScopeValue* scope_field = sv->field_at(svIndex); + StackValue* value = StackValue::create_stack_value(fr, reg_map, scope_field); + int offset = fields->at(i)._offset; + BasicType type = fields->at(i)._type; + switch (type) { + case T_OBJECT: case T_ARRAY: + assert(value->type() == T_OBJECT, "Agreement."); + obj->obj_field_put(offset, value->get_obj()()); + break; + + // Have to cast to INT (32 bits) pointer to avoid little/big-endian problem. + case T_INT: case T_FLOAT: { // 4 bytes. + assert(value->type() == T_INT, "Agreement."); + bool big_value = false; + if (i+1 < fields->length() && fields->at(i+1)._type == T_INT) { + if (scope_field->is_location()) { + Location::Type type = ((LocationValue*) scope_field)->location().type(); + if (type == Location::dbl || type == Location::lng) { + big_value = true; + } + } + if (scope_field->is_constant_int()) { + ScopeValue* next_scope_field = sv->field_at(svIndex + 1); + if (next_scope_field->is_constant_long() || next_scope_field->is_constant_double()) { + big_value = true; + } + } + } + + if (big_value) { + i++; + assert(i < fields->length(), "second T_INT field needed"); + assert(fields->at(i)._type == T_INT, "T_INT field needed"); + } else { + val = value->get_int(); + obj->int_field_put(offset, (jint)*((jint*)&val)); + break; + } + } + /* no break */ + + case T_LONG: case T_DOUBLE: { + assert(value->type() == T_INT, "Agreement."); + StackValue* low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++svIndex)); +#ifdef _LP64 + jlong res = (jlong)low->get_int(); +#else +#ifdef SPARC + // For SPARC we have to swap high and low words. + jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); +#else + jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); +#endif //SPARC +#endif + obj->long_field_put(offset, res); + break; + } + + case T_SHORT: case T_CHAR: // 2 bytes + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->short_field_put(offset, (jshort)*((jint*)&val)); + break; + + case T_BOOLEAN: case T_BYTE: // 1 byte + assert(value->type() == T_INT, "Agreement."); + val = value->get_int(); + obj->bool_field_put(offset, (jboolean)*((jint*)&val)); + break; + + default: + ShouldNotReachHere(); + } + svIndex++; + } + return svIndex; +} // restore fields of all eliminated objects and arrays -void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects, bool realloc_failures) { +void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects, bool realloc_failures, bool skip_internal) { for (int i = 0; i < objects->length(); i++) { ObjectValue* sv = (ObjectValue*) objects->at(i); KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())); Handle obj = sv->value(); assert(obj.not_null() || realloc_failures, "reallocation was missed"); + if (PrintDeoptimizationDetails) { + tty->print_cr("reassign fields for object of type %s!", k->name()->as_C_string()); + } if (obj.is_null()) { continue; } if (k->oop_is_instance()) { InstanceKlass* ik = InstanceKlass::cast(k()); - FieldReassigner reassign(fr, reg_map, sv, obj()); - ik->do_nonstatic_fields(&reassign); + reassign_fields_by_klass(ik, fr, reg_map, sv, 0, obj(), skip_internal); } else if (k->oop_is_typeArray()) { TypeArrayKlass* ak = TypeArrayKlass::cast(k()); reassign_type_array_elements(fr, reg_map, sv, (typeArrayOop) obj(), ak->element_type()); @@ -966,7 +1061,7 @@ KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()())); Handle obj = sv->value(); - tty->print(" object <" INTPTR_FORMAT "> of type ", (void *)sv->value()()); + tty->print(" object <" INTPTR_FORMAT "> of type ", p2i(sv->value()())); k->print_value(); assert(obj.not_null() || realloc_failures, "reallocation was missed"); if (obj.is_null()) { @@ -982,15 +1077,15 @@ } } #endif -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk, bool realloc_failures) { - Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, fr.pc(), fr.sp()); + Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, p2i(fr.pc()), p2i(fr.sp())); #ifndef PRODUCT - if (TraceDeoptimization) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; - tty->print("DEOPT PACKING thread " INTPTR_FORMAT " ", thread); + tty->print("DEOPT PACKING thread " INTPTR_FORMAT " ", p2i(thread)); fr.print_on(tty); tty->print_cr(" Virtual frames (innermost first):"); for (int index = 0; index < chunk->length(); index++) { @@ -1033,16 +1128,16 @@ assert(array->structural_compare(thread, chunk), "just checking"); #ifndef PRODUCT - if (TraceDeoptimization) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; - tty->print_cr(" Created vframeArray " INTPTR_FORMAT, array); + tty->print_cr(" Created vframeArray " INTPTR_FORMAT, p2i(array)); } #endif // PRODUCT return array; } -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array) { // Reallocation of some scalar replaced objects failed. Record // that we need to pop all the interpreter frames for the @@ -1150,17 +1245,38 @@ } -void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr) { +void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) { assert(fr.can_be_deoptimized(), "checking frame type"); - gather_statistics(Reason_constraint, Action_none, Bytecodes::_illegal); + gather_statistics(reason, Action_none, Bytecodes::_illegal); + + if (LogCompilation && xtty != NULL) { + nmethod* nm = fr.cb()->as_nmethod_or_null(); + assert(nm != NULL, "only compiled methods can deopt"); - // Patch the nmethod so that when execution returns to it we will + ttyLocker ttyl; + xtty->begin_head("deoptimized thread='" UINTX_FORMAT "'", (uintx)thread->osthread()->thread_id()); + nm->log_identity(xtty); + xtty->end_head(); + for (ScopeDesc* sd = nm->scope_desc_at(fr.pc()); ; sd = sd->sender()) { + xtty->begin_elem("jvms bci='%d'", sd->bci()); + xtty->method(sd->method()); + xtty->end_elem(); + if (sd->is_top()) break; + } + xtty->tail("deoptimized"); + } + + // Patch the compiled method so that when execution returns to it we will // deopt the execution state and return to the interpreter. fr.deoptimize(thread); } void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map) { + deoptimize(thread, fr, map, Reason_constraint); +} + +void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map, DeoptReason reason) { // Deoptimize only if the frame comes from compile code. // Do not deoptimize the frame which is already patched // during the execution of the loops below. @@ -1172,12 +1288,12 @@ if (UseBiasedLocking) { revoke_biases_of_monitors(thread, fr, map); } - deoptimize_single_frame(thread, fr); + deoptimize_single_frame(thread, fr, reason); } -void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id) { +void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason) { assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(), "can only deoptimize other thread at a safepoint"); // Compute frame and register map based on thread and sp. @@ -1186,19 +1302,22 @@ while (fr.id() != id) { fr = fr.sender(®_map); } - deoptimize(thread, fr, ®_map); + deoptimize(thread, fr, ®_map, reason); } -void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) { +void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason) { if (thread == Thread::current()) { - Deoptimization::deoptimize_frame_internal(thread, id); + Deoptimization::deoptimize_frame_internal(thread, id, reason); } else { - VM_DeoptimizeFrame deopt(thread, id); + VM_DeoptimizeFrame deopt(thread, id, reason); VMThread::execute(&deopt); } } +void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) { + deoptimize_frame(thread, id, Reason_constraint); +} // JVMTI PopFrame support JRT_LEAF(void, Deoptimization::popframe_preserve_args(JavaThread* thread, int bytes_to_save, void* start_address)) @@ -1225,7 +1344,7 @@ return mdo; } -#if defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI void Deoptimization::load_class_by_index(constantPoolHandle constant_pool, int index, TRAPS) { // in case of an unresolved klass entry, load the class. if (constant_pool->tag_at(index).is_unresolved_klass()) { @@ -1288,7 +1407,12 @@ thread->inc_in_deopt_handler(); // We need to update the map if we have biased locking. +#if INCLUDE_JVMCI + // JVMCI might need to get an exception from the stack, which in turn requires the register map to be valid + RegisterMap reg_map(thread, true); +#else RegisterMap reg_map(thread, UseBiasedLocking); +#endif frame stub_frame = thread->last_frame(); frame fr = stub_frame.sender(®_map); // Make sure the calling nmethod is not getting deoptimized and removed @@ -1296,8 +1420,8 @@ nmethodLocker nl(fr.pc()); // Log a message - Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT, - trap_request, fr.pc()); + Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT " relative=" INTPTR_FORMAT, + trap_request, p2i(fr.pc()), fr.pc() - fr.cb()->code_begin()); { ResourceMark rm; @@ -1307,6 +1431,9 @@ DeoptReason reason = trap_request_reason(trap_request); DeoptAction action = trap_request_action(trap_request); +#if INCLUDE_JVMCI + int debug_id = trap_request_debug_id(trap_request); +#endif jint unloaded_class_index = trap_request_index(trap_request); // CP idx or -1 vframe* vf = vframe::new_vframe(&fr, ®_map, thread); @@ -1315,10 +1442,71 @@ nmethod* nm = cvf->code(); ScopeDesc* trap_scope = cvf->scope(); + + if (TraceDeoptimization) { + ttyLocker ttyl; + tty->print_cr(" bci=%d pc=" INTPTR_FORMAT ", relative_pc=" INTPTR_FORMAT ", method=%s" JVMCI_ONLY(", debug_id=%d"), trap_scope->bci(), p2i(fr.pc()), fr.pc() - nm->code_begin(), trap_scope->method()->name_and_sig_as_C_string() +#if INCLUDE_JVMCI + , debug_id +#endif + ); + } + methodHandle trap_method = trap_scope->method(); int trap_bci = trap_scope->bci(); +#if INCLUDE_JVMCI + oop speculation = thread->pending_failed_speculation(); + if (nm->is_compiled_by_jvmci()) { + if (speculation != NULL) { + oop speculation_log = nm->speculation_log(); + if (speculation_log != NULL) { + if (TraceDeoptimization || TraceUncollectedSpeculations) { + if (SpeculationLog::lastFailed(speculation_log) != NULL) { + tty->print_cr("A speculation that was not collected by the compiler is being overwritten"); + } + } + if (TraceDeoptimization) { + tty->print_cr("Saving speculation to speculation log"); + } + SpeculationLog::set_lastFailed(speculation_log, speculation); + } else { + if (TraceDeoptimization) { + tty->print_cr("Speculation present but no speculation log"); + } + } + thread->set_pending_failed_speculation(NULL); + } else { + if (TraceDeoptimization) { + tty->print_cr("No speculation"); + } + } + } else { + assert(speculation == NULL, "There should not be a speculation for method compiled by non-JVMCI compilers"); + } + + if (trap_bci == SynchronizationEntryBCI) { + trap_bci = 0; + thread->set_pending_monitorenter(true); + } + + if (reason == Deoptimization::Reason_transfer_to_interpreter) { + thread->set_pending_transfer_to_interpreter(true); + } +#endif + Bytecodes::Code trap_bc = trap_method->java_code_at(trap_bci); + if (trap_scope->rethrow_exception()) { + if (PrintDeoptimizationDetails) { + tty->print_cr("Exception to be rethrown in the interpreter for method %s::%s at bci %d", trap_method->method_holder()->name()->as_C_string(), trap_method->name()->as_C_string(), trap_bci); + } + GrowableArray* expressions = trap_scope->expressions(); + guarantee(expressions != NULL, "must have exception to throw"); + ScopeValue* topOfStack = expressions->top(); + Handle topOfStackObj = StackValue::create_stack_value(&fr, ®_map, topOfStack)->get_obj(); + THREAD->set_pending_exception(topOfStackObj(), NULL, 0); + } + // Record this event in the histogram. gather_statistics(reason, action, trap_bc); @@ -1326,12 +1514,23 @@ // Need MDO to record RTM code generation state. bool create_if_missing = ProfileTraps || UseCodeAging RTM_OPT_ONLY( || UseRTMLocking ); + methodHandle profiled_method; +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci()) { + profiled_method = nm->method(); + } else { + profiled_method = trap_method; + } +#else + profiled_method = trap_method; +#endif + MethodData* trap_mdo = - get_method_data(thread, trap_method, create_if_missing); + get_method_data(thread, profiled_method, create_if_missing); // Log a message Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d", - trap_reason_name(reason), trap_action_name(action), fr.pc(), + trap_reason_name(reason), trap_action_name(action), p2i(fr.pc()), trap_method->name_and_sig_as_C_string(), trap_bci); // Print a bunch of diagnostics, if requested. @@ -1385,12 +1584,33 @@ if (TraceDeoptimization) { // make noise on the tty tty->print("Uncommon trap occurred in"); nm->method()->print_short_name(tty); - tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d", - fr.pc(), + tty->print(" compiler=%s compile_id=%d", nm->compiler() == NULL ? "" : nm->compiler()->name(), nm->compile_id()); +#if INCLUDE_JVMCI + oop installedCode = nm->jvmci_installed_code(); + if (installedCode != NULL) { + oop installedCodeName = NULL; + if (installedCode->is_a(InstalledCode::klass())) { + installedCodeName = InstalledCode::name(installedCode); + } + if (installedCodeName != NULL) { + tty->print(" (JVMCI: installedCodeName=%s) ", java_lang_String::as_utf8_string(installedCodeName)); + } else { + tty->print(" (JVMCI: installed code has no name) "); + } + } else if (nm->is_compiled_by_jvmci()) { + tty->print(" (JVMCI: no installed code) "); + } +#endif + tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d" JVMCI_ONLY(" debug_id=%d"), + p2i(fr.pc()), os::current_thread_id(), trap_reason_name(reason), trap_action_name(action), - unloaded_class_index); + unloaded_class_index +#if INCLUDE_JVMCI + , debug_id +#endif + ); if (class_name != NULL) { tty->print(unresolved ? " unresolved class: " : " symbol: "); class_name->print_symbol_on(tty); @@ -1524,11 +1744,14 @@ bool inc_recompile_count = false; ProfileData* pdata = NULL; if (ProfileTraps && update_trap_state && trap_mdo != NULL) { - assert(trap_mdo == get_method_data(thread, trap_method, false), "sanity"); + assert(trap_mdo == get_method_data(thread, profiled_method, false), "sanity"); uint this_trap_count = 0; bool maybe_prior_trap = false; bool maybe_prior_recompile = false; - pdata = query_update_method_data(trap_mdo, trap_bci, reason, + pdata = query_update_method_data(trap_mdo, trap_bci, reason, true, +#if INCLUDE_JVMCI + nm->is_compiled_by_jvmci() && nm->is_osr_method(), +#endif nm->method(), //outputs: this_trap_count, @@ -1660,26 +1883,42 @@ Deoptimization::query_update_method_data(MethodData* trap_mdo, int trap_bci, Deoptimization::DeoptReason reason, + bool update_total_trap_count, +#if INCLUDE_JVMCI + bool is_osr, +#endif Method* compiled_method, //outputs: uint& ret_this_trap_count, bool& ret_maybe_prior_trap, bool& ret_maybe_prior_recompile) { - uint prior_trap_count = trap_mdo->trap_count(reason); - uint this_trap_count = trap_mdo->inc_trap_count(reason); + bool maybe_prior_trap = false; + bool maybe_prior_recompile = false; + uint this_trap_count = 0; + if (update_total_trap_count) { + uint idx = reason; +#if INCLUDE_JVMCI + if (is_osr) { + idx += Reason_LIMIT; + } +#endif + uint prior_trap_count = trap_mdo->trap_count(idx); + this_trap_count = trap_mdo->inc_trap_count(idx); - // If the runtime cannot find a place to store trap history, - // it is estimated based on the general condition of the method. - // If the method has ever been recompiled, or has ever incurred - // a trap with the present reason , then this BCI is assumed - // (pessimistically) to be the culprit. - bool maybe_prior_trap = (prior_trap_count != 0); - bool maybe_prior_recompile = (trap_mdo->decompile_count() != 0); + // If the runtime cannot find a place to store trap history, + // it is estimated based on the general condition of the method. + // If the method has ever been recompiled, or has ever incurred + // a trap with the present reason , then this BCI is assumed + // (pessimistically) to be the culprit. + maybe_prior_trap = (prior_trap_count != 0); + maybe_prior_recompile = (trap_mdo->decompile_count() != 0); + } ProfileData* pdata = NULL; // For reasons which are recorded per bytecode, we check per-BCI data. DeoptReason per_bc_reason = reason_recorded_per_bytecode_if_any(reason); + assert(per_bc_reason != Reason_none || update_total_trap_count, "must be"); if (per_bc_reason != Reason_none) { // Find the profile data for this BCI. If there isn't one, // try to allocate one from the MDO's set of spares. @@ -1732,8 +1971,14 @@ bool ignore_maybe_prior_trap; bool ignore_maybe_prior_recompile; assert(!reason_is_speculate(reason), "reason speculate only used by compiler"); + // JVMCI uses the total counts to determine if deoptimizations are happening too frequently -> do not adjust total counts + bool update_total_counts = JVMCI_ONLY(false) NOT_JVMCI(true); query_update_method_data(trap_mdo, trap_bci, (DeoptReason)reason, + update_total_counts, +#if INCLUDE_JVMCI + false, +#endif NULL, ignore_this_trap_count, ignore_maybe_prior_trap, @@ -1741,7 +1986,9 @@ } Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request) { - + if (TraceDeoptimization) { + tty->print("Uncommon trap "); + } // Still in Java no safepoints { // This enters VM and may safepoint @@ -1846,12 +2093,12 @@ // Note: Keep this in sync. with enum DeoptReason. "none", "null_check", - "null_assert", + "null_assert" JVMCI_ONLY("_or_unreached0"), "range_check", "class_check", "array_check", - "intrinsic", - "bimorphic", + "intrinsic" JVMCI_ONLY("_or_type_checked_inlining"), + "bimorphic" JVMCI_ONLY("_or_optimized_type_check"), "unloaded", "uninitialized", "unreached", @@ -1866,6 +2113,13 @@ "rtm_state_change", "unstable_if", "unstable_fused_if", +#if INCLUDE_JVMCI + "aliasing", + "transfer_to_interpreter", + "not_compiled_exception_handler", + "unresolved", + "jsr_mismatch", +#endif "tenured" }; const char* Deoptimization::_trap_action_name[] = { @@ -1905,13 +2159,24 @@ jint unloaded_class_index = trap_request_index(trap_request); const char* reason = trap_reason_name(trap_request_reason(trap_request)); const char* action = trap_action_name(trap_request_action(trap_request)); +#if INCLUDE_JVMCI + int debug_id = trap_request_debug_id(trap_request); +#endif size_t len; if (unloaded_class_index < 0) { - len = jio_snprintf(buf, buflen, "reason='%s' action='%s'", - reason, action); + len = jio_snprintf(buf, buflen, "reason='%s' action='%s'" JVMCI_ONLY(" debug_id='%d'"), + reason, action +#if INCLUDE_JVMCI + ,debug_id +#endif + ); } else { - len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'", - reason, action, unloaded_class_index); + len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'" JVMCI_ONLY(" debug_id='%d'"), + reason, action, unloaded_class_index +#if INCLUDE_JVMCI + ,debug_id +#endif + ); } if (len >= buflen) buf[buflen-1] = '\0'; @@ -2008,7 +2273,7 @@ if (xtty != NULL) xtty->tail("statistics"); } } -#else // COMPILER2 || SHARK +#else // COMPILER2 || SHARK || INCLUDE_JVMCI // Stubs for C1 only system. @@ -2044,4 +2309,4 @@ return buf; } -#endif // COMPILER2 || SHARK +#endif // COMPILER2 || SHARK || INCLUDE_JVMCI diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/deoptimization.hpp --- a/hotspot/src/share/vm/runtime/deoptimization.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,7 +41,13 @@ enum DeoptReason { Reason_many = -1, // indicates presence of several reasons Reason_none = 0, // indicates absence of a relevant deopt. - // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits + // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits. + // This is more complicated for JVMCI as JVMCI may deoptimize to *some* bytecode before the + // bytecode that actually caused the deopt (with inlining, JVMCI may even deoptimize to a + // bytecode in another method): + // - bytecode y in method b() causes deopt + // - JVMCI deoptimizes to bytecode x in method a() + // -> the deopt reason will be recorded for method a() at bytecode x Reason_null_check, // saw unexpected null or zero divisor (@bci) Reason_null_assert, // saw unexpected non-null or non-zero (@bci) Reason_range_check, // saw unexpected array index (@bci) @@ -50,6 +56,13 @@ Reason_intrinsic, // saw unexpected operand to intrinsic (@bci) Reason_bimorphic, // saw unexpected object class in bimorphic inlining (@bci) +#if INCLUDE_JVMCI + Reason_unreached0 = Reason_null_assert, + Reason_type_checked_inlining = Reason_intrinsic, + Reason_optimized_type_check = Reason_bimorphic, +#endif + + // recorded per method Reason_unloaded, // unloaded class or constant pool entry Reason_uninitialized, // bad class state (uninitialized) Reason_unreached, // code is not reached, compiler @@ -64,11 +77,19 @@ Reason_rtm_state_change, // rtm state change detected Reason_unstable_if, // a branch predicted always false was taken Reason_unstable_fused_if, // fused two ifs that had each one untaken branch. One is now taken. +#if INCLUDE_JVMCI + Reason_aliasing, // optimistic assumption about aliasing failed + Reason_transfer_to_interpreter, // explicit transferToInterpreter() + Reason_not_compiled_exception_handler, + Reason_unresolved, + Reason_jsr_mismatch, +#endif // Reason_tenured is counted separately, add normal counted Reasons above. // Related to MethodData::_trap_hist_limit where Reason_tenured isn't included Reason_tenured, // age of the code has reached the limit Reason_LIMIT, + // Note: Keep this enum in sync. with _trap_reason_name. Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc // Note: Reason_RECORDED_LIMIT should be < 8 to fit into 3 bits of @@ -91,8 +112,10 @@ enum { _action_bits = 3, _reason_bits = 5, + _debug_id_bits = 23, _action_shift = 0, _reason_shift = _action_shift+_action_bits, + _debug_id_shift = _reason_shift+_reason_bits, BC_CASE_LIMIT = PRODUCT_ONLY(1) NOT_PRODUCT(4) // for _deoptimization_hist }; @@ -109,10 +132,11 @@ // Deoptimizes a frame lazily. nmethod gets patched deopt happens on return to the frame static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map); + static void deoptimize(JavaThread* thread, frame fr, RegisterMap *reg_map, DeoptReason reason); private: // Does the actual work for deoptimizing a single frame - static void deoptimize_single_frame(JavaThread* thread, frame fr); + static void deoptimize_single_frame(JavaThread* thread, frame fr, DeoptReason reason); // Helper function to revoke biases of all monitors in frame if UseBiasedLocking // is enabled @@ -121,16 +145,18 @@ // executing in a particular CodeBlob if UseBiasedLocking is enabled static void revoke_biases_of_monitors(CodeBlob* cb); -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI +JVMCI_ONLY(public:) + // Support for restoring non-escaping objects static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray* objects, TRAPS); static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type); static void reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj); - static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects, bool realloc_failures); + static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray* objects, bool realloc_failures, bool skip_internal); static void relock_objects(GrowableArray* monitors, JavaThread* thread, bool realloc_failures); static void pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array); NOT_PRODUCT(static void print_objects(GrowableArray* objects, bool realloc_failures);) -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI public: static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray* chunk, bool realloc_failures); @@ -140,6 +166,7 @@ // UnrollBlock is returned by fetch_unroll_info() to the deoptimization handler (blob). // This is only a CheapObj to ease debugging after a deopt failure class UnrollBlock : public CHeapObj { + friend class VMStructs; private: int _size_of_deoptimized_frame; // Size, in bytes, of current deoptimized frame int _caller_adjustment; // Adjustment, in bytes, to caller's SP by initial interpreted frame @@ -243,10 +270,11 @@ // Only called from VMDeoptimizeFrame // @argument thread. Thread where stub_frame resides. // @argument id. id of frame that should be deoptimized. - static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id); + static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason); - // If thread is not the current thread then execute + // if thread is not the current thread then execute // VM_DeoptimizeFrame otherwise deoptimize directly. + static void deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason); static void deoptimize_frame(JavaThread* thread, intptr_t* id); // Statistics @@ -276,6 +304,14 @@ // standard action for unloaded CP entry return _unloaded_action; } + static int trap_request_debug_id(int trap_request) { + if (trap_request < 0) { + return ((~(trap_request) >> _debug_id_shift) & right_n_bits(_debug_id_bits)); + } else { + // standard action for unloaded CP entry + return 0; + } + } static int trap_request_index(int trap_request) { if (trap_request < 0) return -1; @@ -374,6 +410,10 @@ static ProfileData* query_update_method_data(MethodData* trap_mdo, int trap_bci, DeoptReason reason, + bool update_total_trap_count, +#if INCLUDE_JVMCI + bool is_osr, +#endif Method* compiled_method, //outputs: uint& ret_this_trap_count, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/fprofiler.cpp --- a/hotspot/src/share/vm/runtime/fprofiler.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/fprofiler.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -42,8 +42,6 @@ #include "runtime/vframe.hpp" #include "utilities/macros.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Static fields of FlatProfiler int FlatProfiler::received_gc_ticks = 0; int FlatProfiler::vm_operation_ticks = 0; @@ -186,7 +184,7 @@ if (counters == NULL) return; tty->cr(); - tty->print_cr("Printing compiled methods with PC buckets having more than %d ticks", ProfilerPCTickThreshold); + tty->print_cr("Printing compiled methods with PC buckets having more than " INTX_FORMAT " ticks", ProfilerPCTickThreshold); tty->print_cr("==================================================================="); tty->cr(); @@ -1494,7 +1492,7 @@ } if (WizardMode) { - tty->print_cr("Node area used: %dKb", (area_top - area_bottom) / 1024); + tty->print_cr("Node area used: " INTX_FORMAT " Kb", (area_top - area_bottom) / 1024); } reset(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/frame.cpp --- a/hotspot/src/share/vm/runtime/frame.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/frame.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -50,9 +50,6 @@ #include "runtime/thread.inline.hpp" #include "utilities/decoder.hpp" - -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - RegisterMap::RegisterMap(JavaThread *thread, bool update_map) { _thread = thread; _update_map = update_map; @@ -112,7 +109,7 @@ if (src != NULL) { r->print_on(st); - st->print(" [" INTPTR_FORMAT "] = ", src); + st->print(" [" INTPTR_FORMAT "] = ", p2i(src)); if (((uintptr_t)src & (sizeof(*src)-1)) != 0) { st->print_cr(""); } else { @@ -494,9 +491,10 @@ NOT_PRODUCT(address begin = pc()-40;) NOT_PRODUCT(address end = NULL;) - st->print("%s frame (sp=" INTPTR_FORMAT " unextended sp=" INTPTR_FORMAT, print_name(), sp(), unextended_sp()); + st->print("%s frame (sp=" INTPTR_FORMAT " unextended sp=" INTPTR_FORMAT, print_name(), p2i(sp()), p2i(unextended_sp())); if (sp() != NULL) - st->print(", fp=" INTPTR_FORMAT ", real_fp=" INTPTR_FORMAT ", pc=" INTPTR_FORMAT, fp(), real_fp(), pc()); + st->print(", fp=" INTPTR_FORMAT ", real_fp=" INTPTR_FORMAT ", pc=" INTPTR_FORMAT, + p2i(fp()), p2i(real_fp()), p2i(pc())); if (StubRoutines::contains(pc())) { st->print_cr(")"); @@ -569,15 +567,15 @@ st->print_cr("]"); } // monitor - st->print_cr(" - monitor[" INTPTR_FORMAT "]", interpreter_frame_monitor_begin()); + st->print_cr(" - monitor[" INTPTR_FORMAT "]", p2i(interpreter_frame_monitor_begin())); // bcp - st->print(" - bcp [" INTPTR_FORMAT "]", interpreter_frame_bcp()); + st->print(" - bcp [" INTPTR_FORMAT "]", p2i(interpreter_frame_bcp())); st->fill_to(23); st->print_cr("; @%d", interpreter_frame_bci()); // locals - st->print_cr(" - locals [" INTPTR_FORMAT "]", interpreter_frame_local_at(0)); + st->print_cr(" - locals [" INTPTR_FORMAT "]", p2i(interpreter_frame_local_at(0))); // method - st->print(" - method [" INTPTR_FORMAT "]", (address)interpreter_frame_method()); + st->print(" - method [" INTPTR_FORMAT "]", p2i(interpreter_frame_method())); st->fill_to(23); st->print("; "); interpreter_frame_method()->print_name(st); @@ -606,7 +604,7 @@ while ((p2 = strstr(p1, os::file_separator())) != NULL) p1 = p2 + len; st->print(" [%s+0x%x]", p1, offset); } else { - st->print(" " PTR_FORMAT, pc); + st->print(" " PTR_FORMAT, p2i(pc)); } // function name - os::dll_address_to_function_name() may return confusing @@ -645,14 +643,14 @@ st->print("j %s", buf); st->print("+%d", this->interpreter_frame_bci()); } else { - st->print("j " PTR_FORMAT, pc()); + st->print("j " PTR_FORMAT, p2i(pc())); } } else if (StubRoutines::contains(pc())) { StubCodeDesc* desc = StubCodeDesc::desc_for(pc()); if (desc != NULL) { st->print("v ~StubRoutines::%s", desc->name()); } else { - st->print("v ~StubRoutines::" PTR_FORMAT, pc()); + st->print("v ~StubRoutines::" PTR_FORMAT, p2i(pc())); } } else if (_cb->is_buffer_blob()) { st->print("v ~BufferBlob::%s", ((BufferBlob *)_cb)->name()); @@ -661,12 +659,19 @@ Method* m = nm->method(); if (m != NULL) { m->name_and_sig_as_C_string(buf, buflen); - st->print("J %d%s %s %s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+0x%x]", + st->print("J %d%s %s ", nm->compile_id(), (nm->is_osr_method() ? "%" : ""), - ((nm->compiler() != NULL) ? nm->compiler()->name() : ""), - buf, m->code_size(), _pc, _cb->code_begin(), _pc - _cb->code_begin()); + ((nm->compiler() != NULL) ? nm->compiler()->name() : "")); +#if INCLUDE_JVMCI + char* jvmciName = nm->jvmci_installed_code_name(buf, buflen); + if (jvmciName != NULL) { + st->print(" (%s)", jvmciName); + } +#endif + st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", + buf, m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); } else { - st->print("J " PTR_FORMAT, pc()); + st->print("J " PTR_FORMAT, p2i(pc())); } } else if (_cb->is_runtime_stub()) { st->print("v ~RuntimeStub::%s", ((RuntimeStub *)_cb)->name()); @@ -677,7 +682,7 @@ } else if (_cb->is_safepoint_stub()) { st->print("v ~SafepointBlob"); } else { - st->print("v blob " PTR_FORMAT, pc()); + st->print("v blob " PTR_FORMAT, p2i(pc())); } } else { print_C_frame(st, buf, buflen, pc()); @@ -998,7 +1003,8 @@ } }; -void frame::oops_compiled_arguments_do(Symbol* signature, bool has_receiver, bool has_appendix, const RegisterMap* reg_map, OopClosure* f) { +void frame::oops_compiled_arguments_do(Symbol* signature, bool has_receiver, bool has_appendix, + const RegisterMap* reg_map, OopClosure* f) { ResourceMark rm; CompiledArgumentOopFinder finder(signature, has_receiver, has_appendix, f, *this, reg_map); finder.oops_do(); @@ -1022,7 +1028,7 @@ return NULL; } oop r = *oop_adr; - assert(Universe::heap()->is_in_or_null(r), err_msg("bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", (void *) r, (void *) r)); + assert(Universe::heap()->is_in_or_null(r), "bad receiver: " INTPTR_FORMAT " (" INTX_FORMAT ")", p2i(r), p2i(r)); return r; } @@ -1111,104 +1117,6 @@ } } -# ifdef ENABLE_ZAP_DEAD_LOCALS - -void frame::CheckValueClosure::do_oop(oop* p) { - if (CheckOopishValues && Universe::heap()->is_in_reserved(*p)) { - warning("value @ " INTPTR_FORMAT " looks oopish (" INTPTR_FORMAT ") (thread = " INTPTR_FORMAT ")", p, (address)*p, Thread::current()); - } -} -frame::CheckValueClosure frame::_check_value; - - -void frame::CheckOopClosure::do_oop(oop* p) { - if (*p != NULL && !(*p)->is_oop()) { - warning("value @ " INTPTR_FORMAT " should be an oop (" INTPTR_FORMAT ") (thread = " INTPTR_FORMAT ")", p, (address)*p, Thread::current()); - } -} -frame::CheckOopClosure frame::_check_oop; - -void frame::check_derived_oop(oop* base, oop* derived) { - _check_oop.do_oop(base); -} - - -void frame::ZapDeadClosure::do_oop(oop* p) { - if (TraceZapDeadLocals) tty->print_cr("zapping @ " INTPTR_FORMAT " containing " INTPTR_FORMAT, p, (address)*p); - *p = cast_to_oop(0xbabebabe); -} -frame::ZapDeadClosure frame::_zap_dead; - -void frame::zap_dead_locals(JavaThread* thread, const RegisterMap* map) { - assert(thread == Thread::current(), "need to synchronize to do this to another thread"); - // Tracing - part 1 - if (TraceZapDeadLocals) { - ResourceMark rm(thread); - tty->print_cr("--------------------------------------------------------------------------------"); - tty->print("Zapping dead locals in "); - print_on(tty); - tty->cr(); - } - // Zapping - if (is_entry_frame ()) zap_dead_entry_locals (thread, map); - else if (is_interpreted_frame()) zap_dead_interpreted_locals(thread, map); - else if (is_compiled_frame()) zap_dead_compiled_locals (thread, map); - - else - // could be is_runtime_frame - // so remove error: ShouldNotReachHere(); - ; - // Tracing - part 2 - if (TraceZapDeadLocals) { - tty->cr(); - } -} - - -void frame::zap_dead_interpreted_locals(JavaThread *thread, const RegisterMap* map) { - // get current interpreter 'pc' - assert(is_interpreted_frame(), "Not an interpreted frame"); - Method* m = interpreter_frame_method(); - int bci = interpreter_frame_bci(); - - int max_locals = m->is_native() ? m->size_of_parameters() : m->max_locals(); - - // process dynamic part - InterpreterFrameClosure value_blk(this, max_locals, m->max_stack(), - &_check_value); - InterpreterFrameClosure oop_blk(this, max_locals, m->max_stack(), - &_check_oop ); - InterpreterFrameClosure dead_blk(this, max_locals, m->max_stack(), - &_zap_dead ); - - // get frame map - InterpreterOopMap mask; - m->mask_for(bci, &mask); - mask.iterate_all( &oop_blk, &value_blk, &dead_blk); -} - - -void frame::zap_dead_compiled_locals(JavaThread* thread, const RegisterMap* reg_map) { - - ResourceMark rm(thread); - assert(_cb != NULL, "sanity check"); - if (_cb->oop_maps() != NULL) { - OopMapSet::all_do(this, reg_map, &_check_oop, check_derived_oop, &_check_value); - } -} - - -void frame::zap_dead_entry_locals(JavaThread*, const RegisterMap*) { - if (TraceZapDeadLocals) warning("frame::zap_dead_entry_locals unimplemented"); -} - - -void frame::zap_dead_deoptimized_locals(JavaThread*, const RegisterMap*) { - if (TraceZapDeadLocals) warning("frame::zap_dead_deoptimized_locals unimplemented"); -} - -# endif // ENABLE_ZAP_DEAD_LOCALS - void frame::verify(const RegisterMap* map) { // for now make sure receiver type is correct if (is_interpreted_frame()) { @@ -1220,7 +1128,9 @@ // make sure we have the right receiver type } } - COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), "must be empty before verify");) +#if defined(COMPILER2) || INCLUDE_JVMCI + assert(DerivedPointerTable::is_empty(), "must be empty before verify"); +#endif oops_do_internal(&VerifyOopClosure::verify_oop, NULL, NULL, (RegisterMap*)map, false); } @@ -1321,7 +1231,7 @@ nmethod* nm = cb()->as_nmethod_or_null(); values.describe(-1, info_address, FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for method %s%s", frame_no, - nm, nm->method()->name_and_sig_as_C_string(), + p2i(nm), nm->method()->name_and_sig_as_C_string(), (_deopt_state == is_deoptimized) ? " (deoptimized)" : ((_deopt_state == unknown) ? " (state unknown)" : "")), @@ -1331,7 +1241,7 @@ nmethod* nm = cb()->as_nmethod_or_null(); values.describe(-1, info_address, FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for native method %s", frame_no, - nm, nm->method()->name_and_sig_as_C_string()), 2); + p2i(nm), nm->method()->name_and_sig_as_C_string()), 2); } else { // provide default info if not handled before char *info = (char *) "special frame"; @@ -1388,8 +1298,8 @@ if (prev.location == fv.location) { if (fv.owner != prev.owner) { tty->print_cr("overlapping storage"); - tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", prev.location, *prev.location, prev.description); - tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", fv.location, *fv.location, fv.description); + tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", p2i(prev.location), *prev.location, prev.description); + tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", p2i(fv.location), *fv.location, fv.description); error = true; } } else { @@ -1433,14 +1343,14 @@ for (int i = max_index; i >= min_index; i--) { FrameValue fv = _values.at(i); while (cur > fv.location) { - tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT, cur, *cur); + tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT, p2i(cur), *cur); cur--; } if (last == fv.location) { const char* spacer = " " LP64_ONLY(" "); tty->print_cr(" %s %s %s", spacer, spacer, fv.description); } else { - tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", fv.location, *fv.location, fv.description); + tty->print_cr(" " INTPTR_FORMAT ": " INTPTR_FORMAT " %s", p2i(fv.location), *fv.location, fv.description); last = fv.location; cur--; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/frame.hpp --- a/hotspot/src/share/vm/runtime/frame.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/frame.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -405,39 +405,6 @@ // RedefineClasses support for finding live interpreted methods on the stack void metadata_do(void f(Metadata*)); -# ifdef ENABLE_ZAP_DEAD_LOCALS - private: - class CheckValueClosure: public OopClosure { - public: - void do_oop(oop* p); - void do_oop(narrowOop* p) { ShouldNotReachHere(); } - }; - static CheckValueClosure _check_value; - - class CheckOopClosure: public OopClosure { - public: - void do_oop(oop* p); - void do_oop(narrowOop* p) { ShouldNotReachHere(); } - }; - static CheckOopClosure _check_oop; - - static void check_derived_oop(oop* base, oop* derived); - - class ZapDeadClosure: public OopClosure { - public: - void do_oop(oop* p); - void do_oop(narrowOop* p) { ShouldNotReachHere(); } - }; - static ZapDeadClosure _zap_dead; - - public: - // Zapping - void zap_dead_locals (JavaThread* thread, const RegisterMap* map); - void zap_dead_interpreted_locals(JavaThread* thread, const RegisterMap* map); - void zap_dead_compiled_locals (JavaThread* thread, const RegisterMap* map); - void zap_dead_entry_locals (JavaThread* thread, const RegisterMap* map); - void zap_dead_deoptimized_locals(JavaThread* thread, const RegisterMap* map); -# endif // Verification void verify(const RegisterMap* map); static bool verify_return_pc(address x); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/globals.cpp --- a/hotspot/src/share/vm/runtime/globals.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/globals.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -42,6 +42,9 @@ #ifdef COMPILER1 #include "c1/c1_globals.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmci_globals.hpp" +#endif #ifdef COMPILER2 #include "opto/c2_globals.hpp" #endif @@ -49,8 +52,6 @@ #include "shark/shark_globals.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - RUNTIME_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_PD_DEVELOPER_FLAG, \ MATERIALIZE_PRODUCT_FLAG, \ @@ -93,7 +94,7 @@ void Flag::check_writable() { if (is_constant_in_binary()) { - fatal(err_msg("flag is constant: %s", _name)); + fatal("flag is constant: %s", _name); } } @@ -369,11 +370,11 @@ } else if (is_uint()) { st->print("%-16u", get_uint()); } else if (is_intx()) { - st->print("%-16ld", get_intx()); + st->print(INTX_FORMAT_W(-16), get_intx()); } else if (is_uintx()) { - st->print("%-16lu", get_uintx()); + st->print(UINTX_FORMAT_W(-16), get_uintx()); } else if (is_uint64_t()) { - st->print("%-16lu", get_uint64_t()); + st->print(UINT64_FORMAT_W(-16), get_uint64_t()); } else if (is_size_t()) { st->print(SIZE_FORMAT_W(-16), get_size_t()); } else if (is_double()) { @@ -441,6 +442,7 @@ }; Data data[] = { + { KIND_JVMCI, "JVMCI" }, { KIND_C1, "C1" }, { KIND_C2, "C2" }, { KIND_ARCH, "ARCH" }, @@ -548,6 +550,14 @@ #define RUNTIME_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, #define RUNTIME_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_NOT_PRODUCT) }, +#define JVMCI_PRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT) }, +#define JVMCI_PD_PRODUCT_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_PRODUCT | Flag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_DEVELOP_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP) }, +#define JVMCI_PD_DEVELOP_FLAG_STRUCT( type, name, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DEVELOP | Flag::KIND_PLATFORM_DEPENDENT) }, +#define JVMCI_DIAGNOSTIC_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_DIAGNOSTIC) }, +#define JVMCI_EXPERIMENTAL_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_EXPERIMENTAL) }, +#define JVMCI_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_JVMCI | Flag::KIND_NOT_PRODUCT) }, + #ifdef _LP64 #define RUNTIME_LP64_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_LP64_PRODUCT) }, #else @@ -616,6 +626,17 @@ IGNORE_RANGE, \ IGNORE_CONSTRAINT) #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \ + JVMCI_PD_DEVELOP_FLAG_STRUCT, \ + JVMCI_PRODUCT_FLAG_STRUCT, \ + JVMCI_PD_PRODUCT_FLAG_STRUCT, \ + JVMCI_DIAGNOSTIC_FLAG_STRUCT, \ + JVMCI_EXPERIMENTAL_FLAG_STRUCT, \ + JVMCI_NOTPRODUCT_FLAG_STRUCT, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) +#endif // INCLUDE_JVMCI #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \ C1_PD_DEVELOP_FLAG_STRUCT, \ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/globals.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -25,7 +25,9 @@ #ifndef SHARE_VM_RUNTIME_GLOBALS_HPP #define SHARE_VM_RUNTIME_GLOBALS_HPP +#include #include "utilities/debug.hpp" +#include // for DBL_MAX // use this for flags that are true per default in the tiered build // but false in non-tiered builds, and vice versa @@ -176,7 +178,7 @@ #endif #endif -#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) +#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) && !INCLUDE_JVMCI define_pd_global(bool, BackgroundCompilation, false); define_pd_global(bool, UseTLAB, false); define_pd_global(bool, CICompileOSR, false); @@ -211,11 +213,11 @@ #define CI_COMPILER_COUNT 0 #else -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI #define CI_COMPILER_COUNT 2 #else #define CI_COMPILER_COUNT 1 -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI #endif // no compilers @@ -254,6 +256,7 @@ KIND_SHARK = 1 << 15, KIND_LP64_PRODUCT = 1 << 16, KIND_COMMERCIAL = 1 << 17, + KIND_JVMCI = 1 << 18, KIND_MASK = ~VALUE_ORIGIN_MASK }; @@ -527,7 +530,7 @@ // notproduct flags are settable / visible only during development and are not declared in the PRODUCT version // A flag must be declared with one of the following types: -// bool, intx, uintx, size_t, ccstr, double, or uint64_t. +// bool, int, uint, intx, uintx, size_t, ccstr, double, or uint64_t. // The type "ccstr" is an alias for "const char*" and is used // only in this file, because the macrology requires single-token type names. @@ -700,6 +703,7 @@ \ product(intx, UseSSE, 99, \ "Highest supported SSE instructions set on x86/x64") \ + range(0, 99) \ \ product(bool, UseAES, false, \ "Control whether AES instructions can be used on x86/x64") \ @@ -937,16 +941,6 @@ notproduct(bool, VerifyCodeCache, false, \ "Verify code cache on memory allocation/deallocation") \ \ - develop(bool, ZapDeadCompiledLocals, false, \ - "Zap dead locals in compiler frames") \ - \ - notproduct(bool, ZapDeadLocalsOld, false, \ - "Zap dead locals (old version, zaps all frames when " \ - "entering the VM") \ - \ - notproduct(bool, CheckOopishValues, false, \ - "Warn if value contains oop (requires ZapDeadLocals)") \ - \ develop(bool, UseMallocOnly, false, \ "Use only malloc/free for allocation (no resource area/arena)") \ \ @@ -1108,9 +1102,15 @@ diagnostic(ccstr, PrintAssemblyOptions, NULL, \ "Print options string passed to disassembler.so") \ \ + notproduct(bool, PrintNMethodStatistics, false, \ + "Print a summary statistic for the generated nmethods") \ + \ diagnostic(bool, PrintNMethods, false, \ "Print assembly code for nmethods when generated") \ \ + diagnostic(intx, PrintNMethodsAtLevel, -1, \ + "Only print code for nmethods at the given compilation level") \ + \ diagnostic(bool, PrintNativeNMethods, false, \ "Print assembly code for native nmethods when generated") \ \ @@ -1258,6 +1258,7 @@ "Control emission of inline sync fast-path code") \ \ product(intx, MonitorBound, 0, "Bound Monitor population") \ + range(0, max_jint) \ \ product(bool, MonitorInUseLists, false, "Track Monitors for Deflation") \ \ @@ -1489,9 +1490,6 @@ develop(bool, TraceCompiledIC, false, \ "Trace changes of compiled IC") \ \ - notproduct(bool, TraceZapDeadLocals, false, \ - "Trace zapping dead locals") \ - \ develop(bool, TraceStartupTime, false, \ "Trace setup time") \ \ @@ -1547,6 +1545,7 @@ \ product(uint, ParallelGCThreads, 0, \ "Number of parallel threads parallel gc will use") \ + constraint(ParallelGCThreadsConstraintFunc,AfterErgo) \ \ diagnostic(bool, UseSemaphoreGCThreadsSynchronization, true, \ "Use semaphore synchronization for the GC Threads, " \ @@ -1578,14 +1577,7 @@ \ product(uint, ConcGCThreads, 0, \ "Number of threads concurrent gc will use") \ - \ - product(size_t, YoungPLABSize, 4096, \ - "Size of young gen promotion LAB's (in HeapWords)") \ - constraint(YoungPLABSizeConstraintFunc,AfterMemoryInit) \ - \ - product(size_t, OldPLABSize, 1024, \ - "Size of old gen promotion LAB's (in HeapWords), or Number \ - of blocks to attempt to claim when refilling CMS LAB's") \ + constraint(ConcGCThreadsConstraintFunc,AfterErgo) \ \ product(uintx, GCTaskTimeStampEntries, 200, \ "Number of time stamp entries per gc worker thread") \ @@ -1693,6 +1685,7 @@ "The number of strides per worker thread that we divide up the " \ "card table scanning work into") \ range(1, max_uintx) \ + constraint(ParGCStridesPerThreadConstraintFunc,AfterErgo) \ \ diagnostic(intx, ParGCCardsPerStrideChunk, 256, \ "The number of cards in each chunk of the parallel chunks used " \ @@ -1715,12 +1708,13 @@ "Maximum size of CMS gen promotion LAB caches per worker " \ "per block size") \ range(1, max_uintx) \ + constraint(CMSOldPLABMaxConstraintFunc,AfterMemoryInit) \ \ product(size_t, CMSOldPLABMin, 16, \ "Minimum size of CMS gen promotion LAB caches per worker " \ "per block size") \ range(1, max_uintx) \ - constraint(CMSOldPLABMinConstraintFunc,AfterErgo) \ + constraint(CMSOldPLABMinConstraintFunc,AfterMemoryInit) \ \ product(uintx, CMSOldPLABNumRefills, 4, \ "Nominal number of refills of CMS gen promotion LAB cache " \ @@ -1779,24 +1773,29 @@ product(double, FLSLargestBlockCoalesceProximity, 0.99, \ "CMS: the smaller the percentage the greater the coalescing " \ "force") \ + range(0.0, 1.0) \ \ product(double, CMSSmallCoalSurplusPercent, 1.05, \ "CMS: the factor by which to inflate estimated demand of small " \ "block sizes to prevent coalescing with an adjoining block") \ + range(0.0, DBL_MAX) \ \ product(double, CMSLargeCoalSurplusPercent, 0.95, \ "CMS: the factor by which to inflate estimated demand of large " \ "block sizes to prevent coalescing with an adjoining block") \ + range(0.0, DBL_MAX) \ \ product(double, CMSSmallSplitSurplusPercent, 1.10, \ "CMS: the factor by which to inflate estimated demand of small " \ "block sizes to prevent splitting to supply demand for smaller " \ "blocks") \ + range(0.0, DBL_MAX) \ \ product(double, CMSLargeSplitSurplusPercent, 1.00, \ "CMS: the factor by which to inflate estimated demand of large " \ "block sizes to prevent splitting to supply demand for smaller " \ "blocks") \ + range(0.0, DBL_MAX) \ \ product(bool, CMSExtrapolateSweep, false, \ "CMS: cushion for block demand during sweep") \ @@ -1824,9 +1823,11 @@ \ develop(intx, CMSDictionaryChoice, 0, \ "Use BinaryTreeDictionary as default in the CMS generation") \ + range(0, 2) \ \ product(uintx, CMSIndexedFreeListReplenish, 4, \ "Replenish an indexed free list with this number of chunks") \ + range(1, max_uintx) \ \ product(bool, CMSReplenishIntermediate, true, \ "Replenish all intermediate free-list caches") \ @@ -1841,14 +1842,15 @@ develop(bool, CMSOverflowEarlyRestoration, false, \ "Restore preserved marks early") \ \ - product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \ - "Size of marking stack") \ - \ /* where does the range max value of (max_jint - 1) come from? */ \ product(size_t, MarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \ "Maximum size of marking stack") \ range(1, (max_jint - 1)) \ \ + product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \ + "Size of marking stack") \ + constraint(MarkStackSizeConstraintFunc,AfterErgo) \ + \ notproduct(bool, CMSMarkStackOverflowALot, false, \ "Simulate frequent marking stack / work queue overflow") \ \ @@ -1861,6 +1863,7 @@ \ product(intx, CMSMaxAbortablePrecleanTime, 5000, \ "Maximum time in abortable preclean (in milliseconds)") \ + range(0, max_intx) \ \ product(uintx, CMSAbortablePrecleanMinWorkPerIteration, 100, \ "Nominal minimum work per abortable preclean iteration") \ @@ -1868,6 +1871,7 @@ manageable(intx, CMSAbortablePrecleanWaitMillis, 100, \ "Time that we sleep between iterations when not given " \ "enough work per iteration") \ + range(0, max_intx) \ \ product(size_t, CMSRescanMultiple, 32, \ "Size (in cards) of CMS parallel rescan task") \ @@ -1974,6 +1978,8 @@ \ product(uintx, CMSWorkQueueDrainThreshold, 10, \ "Don't drain below this size per parallel worker/thief") \ + range(1, max_juint) \ + constraint(CMSWorkQueueDrainThresholdConstraintFunc,AfterErgo) \ \ manageable(intx, CMSWaitDuration, 2000, \ "Time in milliseconds that CMS thread waits for young GC") \ @@ -2225,9 +2231,11 @@ \ develop(intx, PSAdaptiveSizePolicyResizeVirtualSpaceAlot, -1, \ "Resize the virtual spaces of the young or old generations") \ + range(-1, 1) \ \ product(uintx, AdaptiveSizeThroughPutPolicy, 0, \ "Policy for changing generation size for throughput goals") \ + range(0, 1) \ \ develop(bool, PSAdjustTenuredGenForMinorPause, false, \ "Adjust tenured generation to achieve a minor pause goal") \ @@ -2299,9 +2307,12 @@ product(uintx, MaxGCPauseMillis, max_uintx, \ "Adaptive size policy maximum GC pause time goal in millisecond, "\ "or (G1 Only) the maximum GC time per MMU time slice") \ + range(1, max_uintx) \ + constraint(MaxGCPauseMillisConstraintFunc,AfterMemoryInit) \ \ product(uintx, GCPauseIntervalMillis, 0, \ "Time slice for MMU specification") \ + constraint(GCPauseIntervalMillisConstraintFunc,AfterMemoryInit) \ \ product(uintx, MaxGCMinorPauseMillis, max_uintx, \ "Adaptive size policy maximum GC minor pause time goal " \ @@ -2322,6 +2333,7 @@ \ product(uintx, MinSurvivorRatio, 3, \ "Minimum ratio of young generation/survivor space size") \ + range(3, max_uintx) \ \ product(uintx, InitialSurvivorRatio, 8, \ "Initial ratio of young generation/survivor space size") \ @@ -2345,6 +2357,7 @@ \ develop(uintx, AdaptiveSizePolicyGCTimeLimitThreshold, 5, \ "Number of consecutive collections before gc time limit fires") \ + range(1, max_uintx) \ \ product(bool, PrintAdaptiveSizePolicy, false, \ "Print information about AdaptiveSizePolicy") \ @@ -2444,6 +2457,7 @@ develop(intx, ConcGCYieldTimeout, 0, \ "If non-zero, assert that GC threads yield within this " \ "number of milliseconds") \ + range(0, max_intx) \ \ product(bool, PrintReferenceGC, false, \ "Print times spent handling reference objects during GC " \ @@ -2482,6 +2496,8 @@ product(size_t, InitialBootClassLoaderMetaspaceSize, \ NOT_LP64(2200*K) LP64_ONLY(4*M), \ "Initial size of the boot class loader data metaspace") \ + range(30*K, max_uintx/BytesPerWord) \ + constraint(InitialBootClassLoaderMetaspaceSizeConstraintFunc, AfterErgo)\ \ product(bool, TraceYoungGenTime, false, \ "Trace accumulated time for young collection") \ @@ -2558,6 +2574,7 @@ experimental(double, ObjectCountCutOffPercent, 0.5, \ "The percentage of the used heap that the instances of a class " \ "must occupy for the class to generate a trace event") \ + range(0.0, 100.0) \ \ /* GC log rotation setting */ \ \ @@ -2718,6 +2735,7 @@ diagnostic(intx, HotMethodDetectionLimit, 100000, \ "Number of compiled code invocations after which " \ "the method is considered as hot by the flusher") \ + range(1, max_jint) \ \ diagnostic(intx, MinPassesBeforeFlush, 10, \ "Minimum number of sweeper passes before an nmethod " \ @@ -2838,7 +2856,7 @@ \ develop(bool, CompileTheWorld, false, \ "Compile all methods in all classes in bootstrap class path " \ - "(stress test)") \ + "(stress test)") \ \ develop(bool, CompileTheWorldPreloadClasses, true, \ "Preload all classes used by a class before start loading") \ @@ -2876,13 +2894,16 @@ "Y: Type profiling of return value at call; " \ "X: Type profiling of parameters to methods; " \ "X, Y and Z in 0=off ; 1=jsr292 only; 2=all methods") \ + constraint(TypeProfileLevelConstraintFunc, AfterErgo) \ \ product(intx, TypeProfileArgsLimit, 2, \ "max number of call arguments to consider for type profiling") \ + range(0, 16) \ \ product(intx, TypeProfileParmsLimit, 2, \ "max number of incoming parameters to consider for type profiling"\ ", -1 for all") \ + range(-1, 64) \ \ /* statistics */ \ develop(bool, CountCompiledCalls, false, \ @@ -3041,13 +3062,17 @@ "Analyze bytecodes to estimate escape state of arguments") \ \ product(intx, BCEATraceLevel, 0, \ - "How much tracing to do of bytecode escape analysis estimates") \ + "How much tracing to do of bytecode escape analysis estimates " \ + "(0-3)") \ + range(0, 3) \ \ product(intx, MaxBCEAEstimateLevel, 5, \ "Maximum number of nested calls that are analyzed by BC EA") \ + range(0, max_jint) \ \ product(intx, MaxBCEAEstimateSize, 150, \ "Maximum bytecode size of a method to be analyzed by BC EA") \ + range(0, max_jint) \ \ product(intx, AllocatePrefetchStyle, 1, \ "0 = no prefetch, " \ @@ -3057,25 +3082,34 @@ range(0, 3) \ \ product(intx, AllocatePrefetchDistance, -1, \ - "Distance to prefetch ahead of allocation pointer") \ + "Distance to prefetch ahead of allocation pointer. " \ + "-1: use system-specific value (automatically determined") \ + constraint(AllocatePrefetchDistanceConstraintFunc, AfterMemoryInit)\ \ product(intx, AllocatePrefetchLines, 3, \ "Number of lines to prefetch ahead of array allocation pointer") \ + range(1, max_jint / 2) \ \ product(intx, AllocateInstancePrefetchLines, 1, \ "Number of lines to prefetch ahead of instance allocation " \ "pointer") \ + range(1, max_jint / 2) \ \ product(intx, AllocatePrefetchStepSize, 16, \ "Step size in bytes of sequential prefetch instructions") \ + constraint(AllocatePrefetchStepSizeConstraintFunc,AfterMemoryInit)\ \ product(intx, AllocatePrefetchInstr, 0, \ "Prefetch instruction to prefetch ahead of allocation pointer") \ + constraint(AllocatePrefetchInstrConstraintFunc, AfterErgo) \ \ /* deoptimization */ \ develop(bool, TraceDeoptimization, false, \ "Trace deoptimization") \ \ + develop(bool, PrintDeoptimizationDetails, false, \ + "Print more information about deoptimization") \ + \ develop(bool, DebugDeoptimization, false, \ "Tracing various information while debugging deoptimization") \ \ @@ -3137,30 +3171,38 @@ \ product(intx, MaxInlineLevel, 9, \ "maximum number of nested calls that are inlined") \ + range(0, max_jint) \ \ product(intx, MaxRecursiveInlineLevel, 1, \ "maximum number of nested recursive calls that are inlined") \ + range(0, max_jint) \ \ develop(intx, MaxForceInlineLevel, 100, \ "maximum number of nested calls that are forced for inlining " \ - "(using CompilerOracle or marked w/ @ForceInline)") \ + "(using CompileCommand or marked w/ @ForceInline)") \ + range(0, max_jint) \ \ product_pd(intx, InlineSmallCode, \ "Only inline already compiled methods if their code size is " \ "less than this") \ + range(0, max_jint) \ \ product(intx, MaxInlineSize, 35, \ "The maximum bytecode size of a method to be inlined") \ + range(0, max_jint) \ \ product_pd(intx, FreqInlineSize, \ "The maximum bytecode size of a frequent method to be inlined") \ + range(0, max_jint) \ \ product(intx, MaxTrivialSize, 6, \ "The maximum bytecode size of a trivial method to be inlined") \ + range(0, max_jint) \ \ product(intx, MinInliningThreshold, 250, \ "The minimum invocation count a method needs to have to be " \ "inlined") \ + range(0, max_jint) \ \ develop(intx, MethodHistogramCutoff, 100, \ "The cutoff value for method invocation histogram (+CountCalls)") \ @@ -3222,8 +3264,12 @@ "If non-zero, maximum number of words that malloc/realloc can " \ "allocate (for testing only)") \ \ - product(intx, TypeProfileWidth, 2, \ + product(intx, TypeProfileWidth, 2, \ "Number of receiver types to record in call/cast profile") \ + range(0, 8) \ + \ + experimental(intx, MethodProfileWidth, 0, \ + "Number of methods to record in call profile") \ \ develop(intx, BciProfileWidth, 2, \ "Number of return bci's to record in ret profile") \ @@ -3238,45 +3284,56 @@ \ product(intx, PerMethodTrapLimit, 100, \ "Limit on traps (of one kind) in a method (includes inlines)") \ + range(0, max_jint) \ \ experimental(intx, PerMethodSpecTrapLimit, 5000, \ "Limit on speculative traps (of one kind) in a method " \ "(includes inlines)") \ + range(0, max_jint) \ \ product(intx, PerBytecodeTrapLimit, 4, \ "Limit on traps (of one kind) at a particular BCI") \ + range(0, max_jint) \ \ experimental(intx, SpecTrapLimitExtraEntries, 3, \ "Extra method data trap entries for speculation") \ \ develop(intx, InlineFrequencyRatio, 20, \ "Ratio of call site execution to caller method invocation") \ + range(0, max_jint) \ \ develop_pd(intx, InlineFrequencyCount, \ "Count of call site execution necessary to trigger frequent " \ "inlining") \ + range(0, max_jint) \ \ develop(intx, InlineThrowCount, 50, \ "Force inlining of interpreted methods that throw this often") \ + range(0, max_jint) \ \ develop(intx, InlineThrowMaxSize, 200, \ "Force inlining of throwing methods smaller than this") \ + range(0, max_jint) \ \ develop(intx, ProfilerNodeSize, 1024, \ "Size in K to allocate for the Profile Nodes of each thread") \ + range(0, 1024) \ \ /* gc parameters */ \ product(size_t, InitialHeapSize, 0, \ "Initial heap size (in bytes); zero means use ergonomics") \ + constraint(InitialHeapSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxHeapSize, ScaleForWordSize(96*M), \ "Maximum heap size (in bytes)") \ + constraint(MaxHeapSizeConstraintFunc,AfterErgo) \ \ product(size_t, OldSize, ScaleForWordSize(4*M), \ "Initial tenured generation size (in bytes)") \ \ product(size_t, NewSize, ScaleForWordSize(1*M), \ "Initial new generation size (in bytes)") \ + constraint(NewSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxNewSize, max_uintx, \ "Maximum new generation size (in bytes), max_uintx means set " \ @@ -3286,12 +3343,23 @@ "Maximum size in bytes of objects allocated in DefNew " \ "generation; zero means no maximum") \ \ - product(size_t, TLABSize, 0, \ - "Starting TLAB size (in bytes); zero means set ergonomically") \ - \ product(size_t, MinTLABSize, 2*K, \ "Minimum allowed TLAB size (in bytes)") \ range(1, max_uintx) \ + constraint(MinTLABSizeConstraintFunc,AfterMemoryInit) \ + \ + product(size_t, TLABSize, 0, \ + "Starting TLAB size (in bytes); zero means set ergonomically") \ + constraint(TLABSizeConstraintFunc,AfterMemoryInit) \ + \ + product(size_t, YoungPLABSize, 4096, \ + "Size of young gen promotion LAB's (in HeapWords)") \ + constraint(YoungPLABSizeConstraintFunc,AfterMemoryInit) \ + \ + product(size_t, OldPLABSize, 1024, \ + "Size of old gen promotion LAB's (in HeapWords), or Number " \ + "of blocks to attempt to claim when refilling CMS LAB's") \ + constraint(OldPLABSizeConstraintFunc,AfterMemoryInit) \ \ product(uintx, TLABAllocationWeight, 35, \ "Allocation averaging weight") \ @@ -3312,9 +3380,12 @@ \ product(uintx, SurvivorRatio, 8, \ "Ratio of eden/survivor space size") \ + range(1, max_uintx-2) \ + constraint(SurvivorRatioConstraintFunc,AfterMemoryInit) \ \ product(uintx, NewRatio, 2, \ "Ratio of old/new generation sizes") \ + range(0, max_uintx-1) \ \ product_pd(size_t, NewSizeThreadIncrease, \ "Additional size added to desired new generation size per " \ @@ -3322,9 +3393,11 @@ \ product_pd(size_t, MetaspaceSize, \ "Initial size of Metaspaces (in bytes)") \ + constraint(MetaspaceSizeConstraintFunc,AfterErgo) \ \ product(size_t, MaxMetaspaceSize, max_uintx, \ "Maximum size of Metaspaces (in bytes)") \ + constraint(MaxMetaspaceSizeConstraintFunc,AfterErgo) \ \ product(size_t, CompressedClassSpaceSize, 1*G, \ "Maximum size of class area in Metaspace when compressed " \ @@ -3347,6 +3420,8 @@ \ product(intx, SoftRefLRUPolicyMSPerMB, 1000, \ "Number of milliseconds per MB of free space in the heap") \ + range(0, max_intx) \ + constraint(SoftRefLRUPolicyMSPerMBConstraintFunc,AfterMemoryInit) \ \ product(size_t, MinHeapDeltaBytes, ScaleForWordSize(128*K), \ "The minimum change in heap space due to GC (in bytes)") \ @@ -3378,6 +3453,7 @@ \ diagnostic(intx, VerifyGCLevel, 0, \ "Generation level at which to start +VerifyBefore/AfterGC") \ + range(0, 1) \ \ product(uintx, MaxTenuringThreshold, 15, \ "Maximum value for tenuring threshold") \ @@ -3436,6 +3512,7 @@ "before changing safepoint polling page to RO ") \ \ product(intx, SafepointSpinBeforeYield, 2000, "(Unstable)") \ + range(0, max_intx) \ \ product(bool, PSChunkLargeArrays, true, \ "Process large arrays in chunks") \ @@ -3467,6 +3544,7 @@ \ product_pd(intx, CompilerThreadStackSize, \ "Compiler Thread Stack Size (in Kbytes)") \ + range(0, max_intx) \ \ develop_pd(size_t, JVMInvokeMethodSlack, \ "Stack space (bytes) required for JVM_InvokeMethod to complete") \ @@ -3477,36 +3555,46 @@ "Code cache segment size (in bytes) - smallest unit of " \ "allocation") \ range(1, 1024) \ + constraint(CodeCacheSegmentSizeConstraintFunc, AfterErgo) \ \ develop_pd(intx, CodeEntryAlignment, \ "Code entry alignment for generated code (in bytes)") \ + constraint(CodeEntryAlignmentConstraintFunc, AfterErgo) \ \ product_pd(intx, OptoLoopAlignment, \ "Align inner loops to zero relative to this modulus") \ + constraint(OptoLoopAlignmentConstraintFunc, AfterErgo) \ \ product_pd(uintx, InitialCodeCacheSize, \ "Initial code cache size (in bytes)") \ + range(0, max_uintx) \ \ develop_pd(uintx, CodeCacheMinimumUseSpace, \ "Minimum code cache size (in bytes) required to start VM.") \ + range(0, max_uintx) \ \ product(bool, SegmentedCodeCache, false, \ "Use a segmented code cache") \ \ product_pd(uintx, ReservedCodeCacheSize, \ "Reserved code cache size (in bytes) - maximum code cache size") \ + range(0, max_uintx) \ \ product_pd(uintx, NonProfiledCodeHeapSize, \ "Size of code heap with non-profiled methods (in bytes)") \ + range(0, max_uintx) \ \ product_pd(uintx, ProfiledCodeHeapSize, \ "Size of code heap with profiled methods (in bytes)") \ + range(0, max_uintx) \ \ product_pd(uintx, NonNMethodCodeHeapSize, \ "Size of code heap with non-nmethods (in bytes)") \ + range(0, max_uintx) \ \ product_pd(uintx, CodeCacheExpansionSize, \ "Code cache expansion size (in bytes)") \ + range(0, max_uintx) \ \ develop_pd(uintx, CodeCacheMinBlockLength, \ "Minimum number of segments in a code cache block") \ @@ -3636,6 +3724,7 @@ product(intx, CompilerThreadPriority, -1, \ "The native priority at which compiler threads should run " \ "(-1 means no change)") \ + constraint(CompilerThreadPriorityConstraintFunc, AfterErgo) \ \ product(intx, VMThreadPriority, -1, \ "The native priority at which the VM thread should run " \ @@ -3708,6 +3797,7 @@ /* recompilation */ \ product_pd(intx, CompileThreshold, \ "number of interpreted method invocations before (re-)compiling") \ + constraint(CompileThresholdConstraintFunc, AfterErgo) \ \ product(double, CompileThresholdScaling, 1.0, \ "Factor to control when first compilation happens " \ @@ -3721,90 +3811,115 @@ "If a value is specified for a method, compilation thresholds " \ "for that method are scaled by both the value of the global flag "\ "and the value of the per-method flag.") \ + range(0.0, DBL_MAX) \ \ product(intx, Tier0InvokeNotifyFreqLog, 7, \ "Interpreter (tier 0) invocation notification frequency") \ + range(0, 30) \ \ product(intx, Tier2InvokeNotifyFreqLog, 11, \ "C1 without MDO (tier 2) invocation notification frequency") \ + range(0, 30) \ \ product(intx, Tier3InvokeNotifyFreqLog, 10, \ "C1 with MDO profiling (tier 3) invocation notification " \ "frequency") \ + range(0, 30) \ \ product(intx, Tier23InlineeNotifyFreqLog, 20, \ "Inlinee invocation (tiers 2 and 3) notification frequency") \ + range(0, 30) \ \ product(intx, Tier0BackedgeNotifyFreqLog, 10, \ "Interpreter (tier 0) invocation notification frequency") \ + range(0, 30) \ \ product(intx, Tier2BackedgeNotifyFreqLog, 14, \ "C1 without MDO (tier 2) invocation notification frequency") \ + range(0, 30) \ \ product(intx, Tier3BackedgeNotifyFreqLog, 13, \ "C1 with MDO profiling (tier 3) invocation notification " \ "frequency") \ + range(0, 30) \ \ product(intx, Tier2CompileThreshold, 0, \ "threshold at which tier 2 compilation is invoked") \ + range(0, max_jint) \ \ product(intx, Tier2BackEdgeThreshold, 0, \ "Back edge threshold at which tier 2 compilation is invoked") \ + range(0, max_jint) \ \ product(intx, Tier3InvocationThreshold, 200, \ "Compile if number of method invocations crosses this " \ "threshold") \ + range(0, max_jint) \ \ product(intx, Tier3MinInvocationThreshold, 100, \ "Minimum invocation to compile at tier 3") \ + range(0, max_jint) \ \ product(intx, Tier3CompileThreshold, 2000, \ "Threshold at which tier 3 compilation is invoked (invocation " \ - "minimum must be satisfied") \ + "minimum must be satisfied)") \ + range(0, max_jint) \ \ product(intx, Tier3BackEdgeThreshold, 60000, \ "Back edge threshold at which tier 3 OSR compilation is invoked") \ + range(0, max_jint) \ \ product(intx, Tier4InvocationThreshold, 5000, \ "Compile if number of method invocations crosses this " \ "threshold") \ + range(0, max_jint) \ \ product(intx, Tier4MinInvocationThreshold, 600, \ "Minimum invocation to compile at tier 4") \ + range(0, max_jint) \ \ product(intx, Tier4CompileThreshold, 15000, \ "Threshold at which tier 4 compilation is invoked (invocation " \ "minimum must be satisfied") \ + range(0, max_jint) \ \ product(intx, Tier4BackEdgeThreshold, 40000, \ "Back edge threshold at which tier 4 OSR compilation is invoked") \ + range(0, max_jint) \ \ 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") \ + range(0, max_jint) \ \ 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") \ + range(0, max_jint) \ \ product(intx, Tier3LoadFeedback, 5, \ "Tier 3 thresholds will increase twofold when C1 queue size " \ "reaches this amount per compiler thread") \ + range(0, max_jint) \ \ product(intx, Tier4LoadFeedback, 3, \ "Tier 4 thresholds will increase twofold when C2 queue size " \ "reaches this amount per compiler thread") \ + range(0, max_jint) \ \ product(intx, TieredCompileTaskTimeout, 50, \ "Kill compile task if method was not used within " \ "given timeout in milliseconds") \ + range(0, max_intx) \ \ product(intx, TieredStopAtLevel, 4, \ "Stop at given compilation level") \ + range(0, 4) \ \ product(intx, Tier0ProfilingStartPercentage, 200, \ "Start profiling in interpreter if the counters exceed tier 3 " \ "thresholds by the specified percentage") \ + range(0, max_jint) \ \ product(uintx, IncreaseFirstTierCompileThresholdAt, 50, \ "Increase the compile threshold for C1 compilation if the code " \ @@ -3813,9 +3928,11 @@ \ product(intx, TieredRateUpdateMinTime, 1, \ "Minimum rate sampling interval (in milliseconds)") \ + range(0, max_intx) \ \ product(intx, TieredRateUpdateMaxTime, 25, \ "Maximum rate sampling interval (in milliseconds)") \ + range(0, max_intx) \ \ product_pd(bool, TieredCompilation, \ "Enable tiered compilation") \ @@ -3826,6 +3943,7 @@ product_pd(intx, OnStackReplacePercentage, \ "NON_TIERED number of method invocations/branches (expressed as " \ "% of CompileThreshold) before (re-)compiling OSR code") \ + constraint(OnStackReplacePercentageConstraintFunc, AfterErgo) \ \ product(intx, InterpreterProfilePercentage, 33, \ "NON_TIERED number of method invocations/branches (expressed as " \ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/globals_extension.hpp --- a/hotspot/src/share/vm/runtime/globals_extension.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/globals_extension.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -44,6 +44,14 @@ #define RUNTIME_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), #define RUNTIME_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define JVMCI_DEVELOP_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_PD_DEVELOP_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), +#define JVMCI_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define JVMCI_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), + #ifdef _LP64 #define RUNTIME_LP64_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #else @@ -105,6 +113,17 @@ IGNORE_RANGE, \ IGNORE_CONSTRAINT) #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER, \ + JVMCI_PD_DEVELOP_FLAG_MEMBER, \ + JVMCI_PRODUCT_FLAG_MEMBER, \ + JVMCI_PD_PRODUCT_FLAG_MEMBER, \ + JVMCI_DIAGNOSTIC_FLAG_MEMBER, \ + JVMCI_EXPERIMENTAL_FLAG_MEMBER, \ + JVMCI_NOTPRODUCT_FLAG_MEMBER, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) +#endif // INCLUDE_JVMCI #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, \ C1_PD_DEVELOP_FLAG_MEMBER, \ @@ -151,6 +170,14 @@ #define RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define JVMCI_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), + #define C1_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), @@ -212,6 +239,17 @@ IGNORE_RANGE, IGNORE_CONSTRAINT) #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER_WITH_TYPE, + JVMCI_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, + JVMCI_PRODUCT_FLAG_MEMBER_WITH_TYPE, + JVMCI_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE, + JVMCI_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE, + JVMCI_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE, + JVMCI_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE, + IGNORE_RANGE, + IGNORE_CONSTRAINT) +#endif // INCLUDE_JVMCI #ifdef COMPILER1 C1_FLAGS(C1_DEVELOP_FLAG_MEMBER_WITH_TYPE, C1_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/handles.cpp --- a/hotspot/src/share/vm/runtime/handles.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/handles.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,13 +30,11 @@ #include "runtime/handles.inline.hpp" #include "runtime/thread.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef ASSERT oop* HandleArea::allocate_handle(oop obj) { assert(_handle_mark_nesting > 1, "memory leak: allocating handle outside HandleMark"); assert(_no_handle_mark_nesting == 0, "allocating handle inside NoHandleMark"); - assert(obj->is_oop(), err_msg("not an oop: " INTPTR_FORMAT, (intptr_t*) obj)); + assert(obj->is_oop(), "not an oop: " INTPTR_FORMAT, p2i(obj)); return real_allocate_handle(obj); } @@ -85,10 +83,9 @@ // The thread local handle areas should not get very large if (TraceHandleAllocation && (size_t)handles_visited > TotalHandleAllocationLimit) { #ifdef ASSERT - warning("%d: Visited in HandleMark : %d", - _nof_handlemarks, handles_visited); + warning("%d: Visited in HandleMark : " SIZE_FORMAT, _nof_handlemarks, handles_visited); #else - warning("Visited in HandleMark : %d", handles_visited); + warning("Visited in HandleMark : " SIZE_FORMAT, handles_visited); #endif } if (_prev != NULL) _prev->oops_do(f); @@ -137,10 +134,10 @@ handles /= sizeof(void *); // Adjust for size of a handle if (handles > HandleAllocationLimit) { // Note: _nof_handlemarks is only set in debug mode - warning("%d: Allocated in HandleMark : %d", _nof_handlemarks, handles); + warning("%d: Allocated in HandleMark : " SIZE_FORMAT, _nof_handlemarks, handles); } - tty->print_cr("Handles %d", handles); + tty->print_cr("Handles " SIZE_FORMAT, handles); } #endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/interfaceSupport.cpp --- a/hotspot/src/share/vm/runtime/interfaceSupport.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/interfaceSupport.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,8 +36,6 @@ #include "runtime/vframe.hpp" #include "utilities/preserveException.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of InterfaceSupport #ifdef ASSERT @@ -73,7 +71,7 @@ } void InterfaceSupport::trace(const char* result_type, const char* header) { - tty->print_cr("%6d %s", _number_of_calls, header); + tty->print_cr("%6ld %s", _number_of_calls, header); } void InterfaceSupport::gc_alot() { @@ -109,8 +107,7 @@ if (FullGCALotInterval > 1) { _fullgc_alot_counter = 1+(long)((double)FullGCALotInterval*os::random()/(max_jint+1.0)); if (PrintGCDetails && Verbose) { - tty->print_cr("Full gc no: %u\tInterval: %d", invocations, - _fullgc_alot_counter); + tty->print_cr("Full gc no: %u\tInterval: %ld", invocations, _fullgc_alot_counter); } } else { _fullgc_alot_counter = 1; @@ -130,8 +127,7 @@ if (ScavengeALotInterval > 1) { _scavenge_alot_counter = 1+(long)((double)ScavengeALotInterval*os::random()/(max_jint+1.0)); if (PrintGCDetails && Verbose) { - tty->print_cr("Scavenge no: %u\tInterval: %d", invocations, - _scavenge_alot_counter); + tty->print_cr("Scavenge no: %u\tInterval: %ld", invocations, _scavenge_alot_counter); } } else { _scavenge_alot_counter = 1; @@ -167,25 +163,6 @@ walk_stack_from(thread->last_java_vframe(®_map)); } - -# ifdef ENABLE_ZAP_DEAD_LOCALS - -static int zap_traversals = 0; - -void InterfaceSupport::zap_dead_locals_old() { - JavaThread* thread = JavaThread::current(); - if (zap_traversals == -1) // edit constant for debugging - warning("I am here"); - int zap_frame_count = 0; // count frames to help debugging - for (StackFrameStream sfs(thread); !sfs.is_done(); sfs.next()) { - sfs.current()->zap_dead_locals(thread, sfs.register_map()); - ++zap_frame_count; - } - ++zap_traversals; -} - -# endif - // invocation counter for InterfaceSupport::deoptimizeAll/zombieAll functions int deoptimizeAllCounter = 0; int zombieAllCounter = 0; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/interfaceSupport.hpp --- a/hotspot/src/share/vm/runtime/interfaceSupport.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/interfaceSupport.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -84,10 +84,6 @@ static void walk_stack_from(vframe* start_vf); static void walk_stack(); -# ifdef ENABLE_ZAP_DEAD_LOCALS - static void zap_dead_locals_old(); -# endif - static void zombieAll(); static void unlinkSymbols(); static void deoptimizeAll(); @@ -357,11 +353,6 @@ if (WalkStackALot) { InterfaceSupport::walk_stack(); } -#ifdef ENABLE_ZAP_DEAD_LOCALS - if (ZapDeadLocalsOld) { - InterfaceSupport::zap_dead_locals_old(); - } -#endif #ifdef COMPILER2 // This option is not used by Compiler 1 if (StressDerivedPointers) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/java.cpp --- a/hotspot/src/share/vm/runtime/java.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/java.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,6 +31,10 @@ #include "compiler/compilerOracle.hpp" #include "gc/shared/genCollectedHeap.hpp" #include "interpreter/bytecodeHistogram.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif #include "memory/oopFactory.hpp" #include "memory/universe.hpp" #include "oops/constantPool.hpp" @@ -80,8 +84,6 @@ #include "opto/runtime.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - GrowableArray* collected_profiled_methods; int compare_methods(Method** a, Method** b) { @@ -159,7 +161,7 @@ collected_invoked_methods->sort(&compare_methods); // tty->cr(); - tty->print_cr("Histogram Over MethodOop Invocation Counters (cutoff = %d):", MethodHistogramCutoff); + tty->print_cr("Histogram Over MethodOop Invocation Counters (cutoff = " INTX_FORMAT "):", MethodHistogramCutoff); tty->cr(); tty->print_cr("____Count_(I+C)____Method________________________Module_________________"); unsigned total = 0, int_total = 0, comp_total = 0, static_total = 0, final_total = 0, @@ -236,7 +238,6 @@ Runtime1::print_statistics(); Deoptimization::print_statistics(); SharedRuntime::print_statistics(); - nmethod::print_statistics(); } #endif /* COMPILER1 */ @@ -246,7 +247,6 @@ Compile::print_statistics(); #ifndef COMPILER1 Deoptimization::print_statistics(); - nmethod::print_statistics(); SharedRuntime::print_statistics(); #endif //COMPILER1 os::print_statistics(); @@ -264,7 +264,21 @@ IndexSet::print_statistics(); } #endif // ASSERT -#endif // COMPILER2 +#else +#ifdef INCLUDE_JVMCI +#ifndef COMPILER1 + if ((TraceDeoptimization || LogVMOutput || LogCompilation) && UseCompiler) { + FlagSetting fs(DisplayVMOutput, DisplayVMOutput && TraceDeoptimization); + Deoptimization::print_statistics(); + SharedRuntime::print_statistics(); + } +#endif +#endif +#endif + + if (PrintNMethodStatistics) { + nmethod::print_statistics(); + } if (CountCompiledCalls) { print_method_invocation_histogram(); } @@ -331,14 +345,6 @@ BiasedLocking::print_counters(); } -#ifdef ENABLE_ZAP_DEAD_LOCALS -#ifdef COMPILER2 - if (ZapDeadCompiledLocals) { - tty->print_cr("Compile::CompiledZap_count = %d", Compile::CompiledZap_count); - tty->print_cr("OptoRuntime::ZapDeadCompiledLocals_count = %d", OptoRuntime::ZapDeadCompiledLocals_count); - } -#endif // COMPILER2 -#endif // ENABLE_ZAP_DEAD_LOCALS // Native memory tracking data if (PrintNMTStatistics) { MemTracker::final_report(tty); @@ -417,6 +423,10 @@ } } +#if INCLUDE_JVMCI + JVMCIRuntime::shutdown(); +#endif + // Hang forever on exit if we're reporting an error. if (ShowMessageBoxOnError && is_error_reported()) { os::infinite_sleep(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/javaCalls.cpp --- a/hotspot/src/share/vm/runtime/javaCalls.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/javaCalls.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,6 +41,10 @@ #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/thread.inline.hpp" +#if INCLUDE_JVMCI +#include "jvmci/jvmciJavaClasses.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif // ----------------------------------------------------- // Implementation of JavaCallWrapper @@ -51,7 +55,7 @@ guarantee(thread->is_Java_thread(), "crucial check - the VM thread cannot and must not escape to Java code"); assert(!thread->owns_locks(), "must release all locks when leaving VM"); - guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler"); + guarantee(thread->can_call_java(), "cannot make java calls from the native compiler"); _result = result; // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub, @@ -309,19 +313,27 @@ CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();) - // Verify the arguments +#if INCLUDE_JVMCI + // Gets the nmethod (if any) that should be called instead of normal target + nmethod* alternative_target = args->alternative_target(); + if (alternative_target == NULL) { +#endif +// Verify the arguments if (CheckJNICalls) { args->verify(method, result->get_type(), thread); } else debug_only(args->verify(method, result->get_type(), thread)); +#if INCLUDE_JVMCI + } +#else // Ignore call if method is empty if (method->is_empty_method()) { assert(result->get_type() == T_VOID, "an empty method must return a void value"); return; } - +#endif #ifdef ASSERT { InstanceKlass* holder = method->method_holder(); @@ -333,7 +345,7 @@ #endif - assert(!thread->is_Compiler_thread(), "cannot compile from the compiler"); + assert(thread->can_call_java(), "cannot compile from the native compiler"); if (CompilationPolicy::must_be_compiled(method)) { CompileBroker::compile_method(method, InvocationEntryBci, CompilationPolicy::policy()->initial_compile_level(), @@ -377,6 +389,17 @@ os::bang_stack_shadow_pages(); } +#if INCLUDE_JVMCI + if (alternative_target != NULL) { + if (alternative_target->is_alive()) { + thread->set_jvmci_alternate_call_target(alternative_target->verified_entry_point()); + entry_point = method->adapter()->get_i2c_entry(); + } else { + THROW(vmSymbols::jdk_vm_ci_code_InvalidInstalledCodeException()); + } + } +#endif + // do call { JavaCallWrapper link(method, receiver, result, CHECK); { HandleMark hm(thread); // HandleMark used by HandleMarkCleaner diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/javaCalls.hpp --- a/hotspot/src/share/vm/runtime/javaCalls.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/javaCalls.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -103,6 +103,7 @@ int _size; int _max_size; bool _start_at_zero; // Support late setting of receiver + JVMCI_ONLY(nmethod* _alternative_target;) // Nmethod that should be called instead of normal target void initialize() { // Starts at first element to support set_receiver. @@ -112,6 +113,7 @@ _max_size = _default_size; _size = 0; _start_at_zero = false; + JVMCI_ONLY(_alternative_target = NULL;) } public: @@ -133,11 +135,22 @@ _max_size = max_size; _size = 0; _start_at_zero = false; + JVMCI_ONLY(_alternative_target = NULL;) } else { initialize(); } } +#if INCLUDE_JVMCI + void set_alternative_target(nmethod* target) { + _alternative_target = target; + } + + nmethod* alternative_target() { + return _alternative_target; + } +#endif + inline void push_oop(Handle h) { _is_oop[_size] = true; JNITypes::put_obj((oop)h.raw_value(), _value, _size); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/jniHandles.cpp --- a/hotspot/src/share/vm/runtime/jniHandles.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,8 +30,6 @@ #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - JNIHandleBlock* JNIHandles::_global_handles = NULL; JNIHandleBlock* JNIHandles::_weak_global_handles = NULL; oop JNIHandles::_deleted_handle = NULL; @@ -281,7 +279,7 @@ _blocks_allocated++; if (TraceJNIHandleAllocation) { tty->print_cr("JNIHandleBlock " INTPTR_FORMAT " allocated (%d total blocks)", - block, _blocks_allocated); + p2i(block), _blocks_allocated); } if (ZapJNIHandleArea) block->zap(); #ifndef PRODUCT @@ -396,7 +394,7 @@ } else { // The weakly referenced object is not alive, clear the reference by storing NULL if (TraceReferenceGC) { - tty->print_cr("Clearing JNI weak reference (" INTPTR_FORMAT ")", root); + tty->print_cr("Clearing JNI weak reference (" INTPTR_FORMAT ")", p2i(root)); } *root = NULL; } @@ -504,7 +502,7 @@ } if (TraceJNIHandleAllocation) { tty->print_cr("Rebuild free list JNIHandleBlock " INTPTR_FORMAT " blocks=%d used=%d free=%d add=%d", - this, blocks, total-free, free, _allocate_before_rebuild); + p2i(this), blocks, total-free, free, _allocate_before_rebuild); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/memprofiler.cpp --- a/hotspot/src/share/vm/runtime/memprofiler.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/memprofiler.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -75,7 +75,7 @@ // Create log file _log_fp = fopen(log_name , "w+"); if (_log_fp == NULL) { - fatal(err_msg("MemProfiler: Cannot create log file: %s", log_name)); + fatal("MemProfiler: Cannot create log file: %s", log_name); } fprintf(_log_fp, "MemProfiler: sizes are in Kb, time is in seconds since startup\n\n"); fprintf(_log_fp, " time, #thr, #cls, heap, heap, perm, perm, code, hndls, rescs, oopmp\n"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/mutex.cpp --- a/hotspot/src/share/vm/runtime/mutex.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/mutex.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -42,8 +42,6 @@ # include "mutex_bsd.inline.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o // // Native Monitor-Mutex locking - theory of operations @@ -897,8 +895,7 @@ void Monitor::lock(Thread * Self) { // Ensure that the Monitor requires/allows safepoint checks. assert(_safepoint_check_required != Monitor::_safepoint_check_never, - err_msg("This lock should never have a safepoint check: %s", - name())); + "This lock should never have a safepoint check: %s", name()); #ifdef CHECK_UNHANDLED_OOPS // Clear unhandled oops so we get a crash right away. Only clear for non-vm @@ -960,8 +957,7 @@ void Monitor::lock_without_safepoint_check(Thread * Self) { // Ensure that the Monitor does not require or allow safepoint checks. assert(_safepoint_check_required != Monitor::_safepoint_check_always, - err_msg("This lock should always have a safepoint check: %s", - name())); + "This lock should always have a safepoint check: %s", name()); assert(_owner != Self, "invariant"); ILock(Self); assert(_owner == NULL, "invariant"); @@ -1093,9 +1089,9 @@ bool as_suspend_equivalent) { // Make sure safepoint checking is used properly. assert(!(_safepoint_check_required == Monitor::_safepoint_check_never && no_safepoint_check == false), - err_msg("This lock should never have a safepoint check: %s", name())); + "This lock should never have a safepoint check: %s", name()); assert(!(_safepoint_check_required == Monitor::_safepoint_check_always && no_safepoint_check == true), - err_msg("This lock should always have a safepoint check: %s", name())); + "This lock should always have a safepoint check: %s", name()); Thread * const Self = Thread::current(); assert(_owner == Self, "invariant"); @@ -1214,9 +1210,9 @@ } void Monitor::print_on_error(outputStream* st) const { - st->print("[" PTR_FORMAT, this); + st->print("[" PTR_FORMAT, p2i(this)); st->print("] %s", _name); - st->print(" - owner thread: " PTR_FORMAT, _owner); + st->print(" - owner thread: " PTR_FORMAT, p2i(_owner)); } @@ -1227,7 +1223,8 @@ #ifndef PRODUCT void Monitor::print_on(outputStream* st) const { - st->print_cr("Mutex: [0x%lx/0x%lx] %s - owner: 0x%lx", this, _LockWord.FullWord, _name, _owner); + st->print_cr("Mutex: [" PTR_FORMAT "/" PTR_FORMAT "] %s - owner: " PTR_FORMAT, + p2i(this), _LockWord.FullWord, _name, p2i(_owner)); } #endif @@ -1335,9 +1332,9 @@ !(this == Safepoint_lock && contains(locks, Terminator_lock) && SafepointSynchronize::is_synchronizing())) { new_owner->print_owned_locks(); - fatal(err_msg("acquiring lock %s/%d out of order with lock %s/%d -- " - "possible deadlock", this->name(), this->rank(), - locks->name(), locks->rank())); + fatal("acquiring lock %s/%d out of order with lock %s/%d -- " + "possible deadlock", this->name(), this->rank(), + locks->name(), locks->rank()); } this->_next = new_owner->_owned_locks; @@ -1386,8 +1383,7 @@ || rank() == Mutex::special, "wrong thread state for using locks"); if (StrictSafepointChecks) { if (thread->is_VM_thread() && !allow_vm_block()) { - fatal(err_msg("VM thread using lock %s (not allowed to block on)", - name())); + fatal("VM thread using lock %s (not allowed to block on)", name()); } debug_only(if (rank() != Mutex::special) \ thread->check_for_valid_safepoint_state(false);) diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/mutexLocker.cpp --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -127,6 +127,7 @@ Mutex* Management_lock = NULL; Monitor* Service_lock = NULL; Monitor* PeriodicTask_lock = NULL; +Mutex* LogConfiguration_lock = NULL; #ifdef INCLUDE_TRACE Mutex* JfrStacktrace_lock = NULL; @@ -155,7 +156,7 @@ // see if invoker of VM operation owns it VM_Operation* op = VMThread::vm_operation(); if (op != NULL && op->calling_thread() == lock->owner()) return; - fatal(err_msg("must own lock %s", lock->name())); + fatal("must own lock %s", lock->name()); } // a stronger assertion than the above @@ -163,7 +164,7 @@ if (IgnoreLockingAssertions) return; assert(lock != NULL, "Need non-NULL lock"); if (lock->owned_by_self()) return; - fatal(err_msg("must own lock %s", lock->name())); + fatal("must own lock %s", lock->name()); } #endif @@ -282,6 +283,7 @@ if (WhiteBoxAPI) { def(Compilation_lock , Monitor, leaf, false, Monitor::_safepoint_check_never); } + def(LogConfiguration_lock , Mutex, nonleaf, false, Monitor::_safepoint_check_always); #ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true, Monitor::_safepoint_check_always); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/mutexLocker.hpp --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -126,6 +126,7 @@ extern Mutex* Management_lock; // a lock used to serialize JVM management extern Monitor* Service_lock; // a lock used for service thread operation extern Monitor* PeriodicTask_lock; // protects the periodic task structure +extern Mutex* LogConfiguration_lock; // protects configuration of logging #ifdef INCLUDE_TRACE extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/os.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -61,8 +61,6 @@ # include -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - OSThread* os::_starting_thread = NULL; address os::_polling_page = NULL; volatile int32_t* os::_mem_serialize_page = NULL; @@ -621,12 +619,12 @@ ptr = guarded.get_user_ptr(); #endif if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) { - tty->print_cr("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr); + tty->print_cr("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); breakpoint(); } debug_only(if (paranoid) verify_memory(ptr)); if (PrintMalloc && tty != NULL) { - tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr); + tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); } // we do not track guard memory @@ -658,7 +656,7 @@ return os::malloc(size, memflags, stack); } if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { - tty->print_cr("os::realloc caught " PTR_FORMAT, memblock); + tty->print_cr("os::realloc caught " PTR_FORMAT, p2i(memblock)); breakpoint(); } // NMT support @@ -671,7 +669,7 @@ // always move the block void* ptr = os::malloc(size, memflags, stack); if (PrintMalloc && tty != NULL) { - tty->print_cr("os::realloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr); + tty->print_cr("os::realloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, p2i(memblock), p2i(ptr)); } // Copy to new memory if malloc didn't fail if ( ptr != NULL ) { @@ -681,7 +679,7 @@ memcpy(ptr, memblock, MIN2(size, memblock_size)); if (paranoid) verify_memory(MemTracker::malloc_base(ptr)); if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) { - tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr); + tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); breakpoint(); } os::free(memblock); @@ -696,7 +694,7 @@ #ifdef ASSERT if (memblock == NULL) return; if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { - if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, memblock); + if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, p2i(memblock)); breakpoint(); } void* membase = MemTracker::record_free(memblock); @@ -796,7 +794,7 @@ } address p = start; - st->print(PTR_FORMAT ": ", start); + st->print(PTR_FORMAT ": ", p2i(start)); while (p < end) { switch (unitsize) { case 1: st->print("%02x", *(u1*)p); break; @@ -809,7 +807,7 @@ if (cols >= cols_per_line && p < end) { cols = 0; st->cr(); - st->print(PTR_FORMAT ": ", p); + st->print(PTR_FORMAT ": ", p2i(p)); } else { st->print(" "); } @@ -856,9 +854,9 @@ size_t mem = physical_memory()/G; if (mem == 0) { // for low memory systems mem = physical_memory()/M; - st->print("%d cores, %dM, ", processor_count(), mem); + st->print("%d cores, " SIZE_FORMAT "M, ", processor_count(), mem); } else { - st->print("%d cores, %dG, ", processor_count(), mem); + st->print("%d cores, " SIZE_FORMAT "G, ", processor_count(), mem); } get_summary_os_info(buf, buflen); st->print_raw(buf); @@ -914,41 +912,40 @@ // the interpreter is generated into a buffer blob InterpreterCodelet* i = Interpreter::codelet_containing(addr); if (i != NULL) { - st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an Interpreter codelet", addr, (int)(addr - i->code_begin())); + st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an Interpreter codelet", p2i(addr), (int)(addr - i->code_begin())); i->print_on(st); return; } if (Interpreter::contains(addr)) { st->print_cr(INTPTR_FORMAT " is pointing into interpreter code" - " (not bytecode specific)", addr); + " (not bytecode specific)", p2i(addr)); return; } // if (AdapterHandlerLibrary::contains(b)) { - st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an AdapterHandler", addr, (int)(addr - b->code_begin())); + st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an AdapterHandler", p2i(addr), (int)(addr - b->code_begin())); AdapterHandlerLibrary::print_handler_on(st, b); } // the stubroutines are generated into a buffer blob StubCodeDesc* d = StubCodeDesc::desc_for(addr); if (d != NULL) { - st->print_cr(INTPTR_FORMAT " is at begin+%d in a stub", addr, (int)(addr - d->begin())); + st->print_cr(INTPTR_FORMAT " is at begin+%d in a stub", p2i(addr), (int)(addr - d->begin())); d->print_on(st); st->cr(); return; } if (StubRoutines::contains(addr)) { - st->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) " - "stub routine", addr); + st->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) stub routine", p2i(addr)); return; } // the InlineCacheBuffer is using stubs generated into a buffer blob if (InlineCacheBuffer::contains(addr)) { - st->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", addr); + st->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", p2i(addr)); return; } VtableStub* v = VtableStubs::stub_containing(addr); if (v != NULL) { - st->print_cr(INTPTR_FORMAT " is at entry_point+%d in a vtable stub", addr, (int)(addr - v->entry_point())); + st->print_cr(INTPTR_FORMAT " is at entry_point+%d in a vtable stub", p2i(addr), (int)(addr - v->entry_point())); v->print_on(st); st->cr(); return; @@ -958,7 +955,7 @@ if (nm != NULL) { ResourceMark rm; st->print(INTPTR_FORMAT " is at entry_point+%d in (nmethod*)" INTPTR_FORMAT, - addr, (int)(addr - nm->entry_point()), nm); + p2i(addr), (int)(addr - nm->entry_point()), p2i(nm)); if (verbose) { st->print(" for "); nm->method()->print_value_on(st); @@ -967,7 +964,7 @@ nm->print_nmethod(verbose); return; } - st->print_cr(INTPTR_FORMAT " is at code_begin+%d in ", addr, (int)(addr - b->code_begin())); + st->print_cr(INTPTR_FORMAT " is at code_begin+%d in ", p2i(addr), (int)(addr - b->code_begin())); b->print_on(st); return; } @@ -985,9 +982,9 @@ } if (print) { if (p == (HeapWord*) addr) { - st->print_cr(INTPTR_FORMAT " is an oop", addr); + st->print_cr(INTPTR_FORMAT " is an oop", p2i(addr)); } else { - st->print_cr(INTPTR_FORMAT " is pointing into object: " INTPTR_FORMAT, addr, p); + st->print_cr(INTPTR_FORMAT " is pointing into object: " INTPTR_FORMAT, p2i(addr), p2i(p)); } oop(p)->print_on(st); return; @@ -995,22 +992,22 @@ } else { if (Universe::heap()->is_in_reserved(addr)) { st->print_cr(INTPTR_FORMAT " is an unallocated location " - "in the heap", addr); + "in the heap", p2i(addr)); return; } } if (JNIHandles::is_global_handle((jobject) addr)) { - st->print_cr(INTPTR_FORMAT " is a global jni handle", addr); + st->print_cr(INTPTR_FORMAT " is a global jni handle", p2i(addr)); return; } if (JNIHandles::is_weak_global_handle((jobject) addr)) { - st->print_cr(INTPTR_FORMAT " is a weak global jni handle", addr); + st->print_cr(INTPTR_FORMAT " is a weak global jni handle", p2i(addr)); return; } #ifndef PRODUCT // we don't keep the block list in product mode if (JNIHandleBlock::any_contains((jobject) addr)) { - st->print_cr(INTPTR_FORMAT " is a local jni handle", addr); + st->print_cr(INTPTR_FORMAT " is a local jni handle", p2i(addr)); return; } #endif @@ -1020,7 +1017,7 @@ if (thread->privileged_stack_top() != NULL && thread->privileged_stack_top()->contains(addr)) { st->print_cr(INTPTR_FORMAT " is pointing into the privilege stack " - "for thread: " INTPTR_FORMAT, addr, thread); + "for thread: " INTPTR_FORMAT, p2i(addr), p2i(thread)); if (verbose) thread->print_on(st); return; } @@ -1029,7 +1026,7 @@ if (verbose) { thread->print_on(st); } else { - st->print_cr(INTPTR_FORMAT " is a thread", addr); + st->print_cr(INTPTR_FORMAT " is a thread", p2i(addr)); } return; } @@ -1038,7 +1035,7 @@ if (thread->stack_base() >= addr && addr > (thread->stack_base() - thread->stack_size())) { st->print_cr(INTPTR_FORMAT " is pointing into the stack for thread: " - INTPTR_FORMAT, addr, thread); + INTPTR_FORMAT, p2i(addr), p2i(thread)); if (verbose) thread->print_on(st); return; } @@ -1052,7 +1049,7 @@ st->cr(); } else { // Use addr->print() from the debugger instead (not here) - st->print_cr(INTPTR_FORMAT " is pointing into metadata", addr); + st->print_cr(INTPTR_FORMAT " is pointing into metadata", p2i(addr)); } return; } @@ -1062,7 +1059,7 @@ return; } - st->print_cr(INTPTR_FORMAT " is an unknown value", addr); + st->print_cr(INTPTR_FORMAT " is an unknown value", p2i(addr)); } // Looks like all platforms except IA64 can use the same function to check @@ -1461,7 +1458,7 @@ " pg_sz=" SIZE_FORMAT " base=" PTR_FORMAT " size=" SIZE_FORMAT, str, region_min_size, region_max_size, - page_size, base, size); + page_size, p2i(base), size); } } #endif // #ifndef PRODUCT @@ -1679,7 +1676,7 @@ #ifndef PRODUCT -#define assert_eq(a,b) assert(a == b, err_msg(SIZE_FORMAT " != " SIZE_FORMAT, a, b)) +#define assert_eq(a,b) assert(a == b, SIZE_FORMAT " != " SIZE_FORMAT, a, b) class TestOS : AllStatic { static size_t small_page_size() { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/osThread.cpp --- a/hotspot/src/share/vm/runtime/osThread.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/osThread.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,8 +26,6 @@ #include "oops/oop.inline.hpp" #include "runtime/osThread.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - OSThread::OSThread(OSThreadStartFunc start_proc, void* start_parm) { pd_initialize(); set_start_proc(start_proc); @@ -41,7 +39,7 @@ // Printing void OSThread::print_on(outputStream *st) const { - st->print("nid=0x%lx ", thread_id()); + st->print("nid=0x%x ", thread_id()); switch (_state) { case ALLOCATED: st->print("allocated "); break; case INITIALIZED: st->print("initialized "); break; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/perfData.cpp --- a/hotspot/src/share/vm/runtime/perfData.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/perfData.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -34,8 +34,6 @@ #include "utilities/exceptions.hpp" #include "utilities/globalDefinitions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - PerfDataList* PerfDataManager::_all = NULL; PerfDataList* PerfDataManager::_sampled = NULL; PerfDataList* PerfDataManager::_constants = NULL; @@ -170,14 +168,14 @@ if (PerfTraceDataCreation) { tty->print("name = %s, dtype = %d, variability = %d," - " units = %d, dsize = %d, vlen = %d," - " pad_length = %d, size = %d, on_c_heap = %s," + " units = %d, dsize = " SIZE_FORMAT ", vlen = " SIZE_FORMAT "," + " pad_length = " SIZE_FORMAT ", size = " SIZE_FORMAT ", on_c_heap = %s," " address = " INTPTR_FORMAT "," " data address = " INTPTR_FORMAT "\n", cname, dtype, variability(), units(), dsize, vlen, pad_length, size, is_on_c_heap() ? "TRUE":"FALSE", - psmp, valuep); + p2i(psmp), p2i(valuep)); } // record the start of the entry and the location of the data field. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/perfMemory.cpp --- a/hotspot/src/share/vm/runtime/perfMemory.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/perfMemory.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,8 +36,6 @@ #include "runtime/statSampler.hpp" #include "utilities/globalDefinitions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Prefix of performance data file. const char PERFDATA_NAME[] = "hsperfdata"; @@ -96,7 +94,7 @@ if (PerfTraceMemOps) { tty->print("PerfDataMemorySize = " SIZE_FORMAT "," - " os::vm_allocation_granularity = " SIZE_FORMAT "," + " os::vm_allocation_granularity = %d," " adjusted size = " SIZE_FORMAT "\n", PerfDataMemorySize, os::vm_allocation_granularity(), @@ -129,7 +127,7 @@ if (PerfTraceMemOps) { tty->print("PerfMemory created: address = " INTPTR_FORMAT "," " size = " SIZE_FORMAT "\n", - (void*)_start, + p2i(_start), _capacity); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/rframe.cpp --- a/hotspot/src/share/vm/runtime/rframe.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/rframe.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -155,7 +155,7 @@ void RFrame::print(const char* kind) { #ifndef PRODUCT -#ifdef COMPILER2 +#if defined(COMPILER2) || INCLUDE_JVMCI int cnt = top_method()->interpreter_invocation_count(); #else int cnt = top_method()->invocation_count(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/safepoint.cpp --- a/hotspot/src/share/vm/runtime/safepoint.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/safepoint.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -63,8 +63,6 @@ #include "c1/c1_globals.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // -------------------------------------------------------------------------------------------------- // Implementation of Safepoint begin/end @@ -689,7 +687,7 @@ break; default: - fatal(err_msg("Illegal threadstate encountered: %d", state)); + fatal("Illegal threadstate encountered: %d", state); } // Check for pending. async. exceptions or suspends - except if the @@ -773,12 +771,10 @@ // To debug the long safepoint, specify both DieOnSafepointTimeout & // ShowMessageBoxOnError. if (DieOnSafepointTimeout) { - char msg[1024]; VM_Operation *op = VMThread::vm_operation(); - sprintf(msg, "Safepoint sync time longer than " INTX_FORMAT "ms detected when executing %s.", - SafepointTimeoutDelay, - op != NULL ? op->name() : "no vm operation"); - fatal(msg); + fatal("Safepoint sync time longer than " INTX_FORMAT "ms detected when executing %s.", + SafepointTimeoutDelay, + op != NULL ? op->name() : "no vm operation"); } } @@ -895,7 +891,7 @@ case _running: default: tty->print_cr("restart thread " INTPTR_FORMAT " with state %d", - _thread, _type); + p2i(_thread), _type); _thread->print(); ShouldNotReachHere(); } @@ -917,7 +913,7 @@ st->print_cr("Thread: " INTPTR_FORMAT " [0x%2x] State: %s _has_called_back %d _at_poll_safepoint %d", - _thread, _thread->osthread()->thread_id(), s, _has_called_back, + p2i(_thread), _thread->osthread()->thread_id(), s, _has_called_back, _at_poll_safepoint); _thread->print_thread_state_on(st); @@ -936,7 +932,7 @@ // Step 1: Find the nmethod from the return address if (ShowSafepointMsgs && Verbose) { - tty->print_cr("Polling page exception at " INTPTR_FORMAT, thread()->saved_exception_pc()); + tty->print_cr("Polling page exception at " INTPTR_FORMAT, p2i(thread()->saved_exception_pc())); } address real_return_addr = thread()->saved_exception_pc(); @@ -1243,8 +1239,8 @@ if (!need_to_track_page_armed_status) { tty->print_cr("Polling page always armed"); } else { - tty->print_cr("Defer polling page loop count = %d\n", - DeferPollingPageLoopCount); + tty->print_cr("Defer polling page loop count = " INTX_FORMAT "\n", + DeferPollingPageLoopCount); } for (int index = 0; index < VM_Operation::VMOp_Terminating; index++) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/sharedRuntime.cpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" @@ -46,6 +47,7 @@ #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/biasedLocking.hpp" +#include "runtime/compilationPolicy.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" @@ -64,8 +66,6 @@ #include "c1/c1_Runtime1.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Shared stub locations RuntimeStub* SharedRuntime::_wrong_method_blob; RuntimeStub* SharedRuntime::_wrong_method_abstract_blob; @@ -93,12 +93,13 @@ _resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C), "resolve_virtual_call"); _resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C), "resolve_static_call"); -#ifdef COMPILER2 - // Vectors are generated only by C2. - if (is_wide_vector(MaxVectorSize)) { +#if defined(COMPILER2) || INCLUDE_JVMCI + // Vectors are generated only by C2 and JVMCI. + bool support_wide = is_wide_vector(MaxVectorSize); + if (support_wide) { _polling_page_vectors_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_VECTOR_LOOP); } -#endif // COMPILER2 +#endif // COMPILER2 || INCLUDE_JVMCI _polling_page_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_LOOP); _polling_page_return_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_RETURN); @@ -183,7 +184,7 @@ tty->print_cr("IC Miss Histogram:"); int tot_misses = 0; for (int i = 0; i < _ICmiss_index; i++) { - tty->print_cr(" at: " INTPTR_FORMAT " nof: %d", _ICmiss_at[i], _ICmiss_count[i]); + tty->print_cr(" at: " INTPTR_FORMAT " nof: %d", p2i(_ICmiss_at[i]), _ICmiss_count[i]); tot_misses += _ICmiss_count[i]; } tty->print_cr("Total IC misses: %7d", tot_misses); @@ -455,12 +456,18 @@ // previous frame depending on the return address. address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thread, address return_address) { - assert(frame::verify_return_pc(return_address), err_msg("must be a return address: " INTPTR_FORMAT, return_address)); + assert(frame::verify_return_pc(return_address), "must be a return address: " INTPTR_FORMAT, p2i(return_address)); assert(thread->frames_to_pop_failed_realloc() == 0 || Interpreter::contains(return_address), "missed frames to pop?"); // Reset method handle flag. thread->set_is_method_handle_return(false); +#if INCLUDE_JVMCI + // JVMCI's ExceptionHandlerStub expects the thread local exception PC to be clear + // and other exception handler continuations do not read it + thread->set_exception_pc(NULL); +#endif + // The fastest case first CodeBlob* blob = CodeCache::find_blob(return_address); nmethod* nm = (blob != NULL) ? blob->as_nmethod_or_null() : NULL; @@ -498,7 +505,7 @@ #ifndef PRODUCT { ResourceMark rm; - tty->print_cr("No exception handler found for exception at " INTPTR_FORMAT " - potential problems:", return_address); + tty->print_cr("No exception handler found for exception at " INTPTR_FORMAT " - potential problems:", p2i(return_address)); tty->print_cr("a) exception happened in (new?) code stubs/buffers that is not handled here"); tty->print_cr("b) other problem"); } @@ -526,8 +533,13 @@ assert(((nmethod*)cb)->is_at_poll_or_poll_return(pc), "safepoint polling: type must be poll"); - assert(((NativeInstruction*)pc)->is_safepoint_poll(), - "Only polling locations are used for safepoint"); +#ifdef ASSERT + if (!((NativeInstruction*)pc)->is_safepoint_poll()) { + tty->print_cr("bad pc: " PTR_FORMAT, p2i(pc)); + Disassembler::decode(cb); + fatal("Only polling locations are used for safepoint"); + } +#endif bool at_poll_return = ((nmethod*)cb)->is_at_poll_return(pc); bool has_wide_vectors = ((nmethod*)cb)->has_wide_vectors(); @@ -617,6 +629,33 @@ assert(nm != NULL, "must exist"); ResourceMark rm; +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci()) { + // lookup exception handler for this pc + int catch_pco = ret_pc - nm->code_begin(); + ExceptionHandlerTable table(nm); + HandlerTableEntry *t = table.entry_for(catch_pco, -1, 0); + if (t != NULL) { + return nm->code_begin() + t->pco(); + } else { + // there is no exception handler for this pc => deoptimize + nm->make_not_entrant(); + + // Use Deoptimization::deoptimize for all of its side-effects: + // revoking biases of monitors, gathering traps statistics, logging... + // it also patches the return pc but we do not care about that + // since we return a continuation to the deopt_blob below. + JavaThread* thread = JavaThread::current(); + RegisterMap reg_map(thread, UseBiasedLocking); + frame runtime_frame = thread->last_frame(); + frame caller_frame = runtime_frame.sender(®_map); + Deoptimization::deoptimize(thread, caller_frame, ®_map, Deoptimization::Reason_not_compiled_exception_handler); + + return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); + } + } +#endif // INCLUDE_JVMCI + ScopeDesc* sd = nm->scope_desc_at(ret_pc); // determine handler bci, if any EXCEPTION_MARK; @@ -685,7 +724,7 @@ #endif if (t == NULL) { - tty->print_cr("MISSING EXCEPTION HANDLER for pc " INTPTR_FORMAT " and handler bci %d", ret_pc, handler_bci); + tty->print_cr("MISSING EXCEPTION HANDLER for pc " INTPTR_FORMAT " and handler bci %d", p2i(ret_pc), handler_bci); tty->print_cr(" Exception:"); exception->print(); tty->cr(); @@ -737,6 +776,15 @@ throw_and_post_jvmti_exception(thread, exception); JRT_END +#if INCLUDE_JVMCI +address SharedRuntime::deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason) { + assert(deopt_reason > Deoptimization::Reason_none && deopt_reason < Deoptimization::Reason_LIMIT, "invalid deopt reason"); + thread->set_jvmci_implicit_exception_pc(pc); + thread->set_pending_deoptimization(Deoptimization::make_trap_request((Deoptimization::DeoptReason)deopt_reason, Deoptimization::Action_reinterpret)); + return (SharedRuntime::deopt_blob()->implicit_exception_uncommon_trap()); +} +#endif // INCLUDE_JVMCI + address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread, address pc, SharedRuntime::ImplicitExceptionKind exception_kind) @@ -769,7 +817,7 @@ // in a debug VM to verify the correctness of the compiled // method stack banging. assert(thread->deopt_mark() == NULL, "no stack overflow from deopt blob/uncommon trap"); - Events::log_exception(thread, "StackOverflowError at " INTPTR_FORMAT, pc); + Events::log_exception(thread, "StackOverflowError at " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_StackOverflowError_entry(); } @@ -786,10 +834,10 @@ if (vt_stub->is_abstract_method_error(pc)) { assert(!vt_stub->is_vtable_stub(), "should never see AbstractMethodErrors from vtable-type VtableStubs"); - Events::log_exception(thread, "AbstractMethodError at " INTPTR_FORMAT, pc); + Events::log_exception(thread, "AbstractMethodError at " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_AbstractMethodError_entry(); } else { - Events::log_exception(thread, "NullPointerException at vtable entry " INTPTR_FORMAT, pc); + Events::log_exception(thread, "NullPointerException at vtable entry " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_NullPointerException_at_call_entry(); } } else { @@ -806,10 +854,10 @@ if (!cb->is_nmethod()) { bool is_in_blob = cb->is_adapter_blob() || cb->is_method_handles_adapter_blob(); if (!is_in_blob) { - cb->print(); - fatal(err_msg("exception happened outside interpreter, nmethods and vtable stubs at pc " INTPTR_FORMAT, pc)); + // Allow normal crash reporting to handle this + return NULL; } - Events::log_exception(thread, "NullPointerException in code blob at " INTPTR_FORMAT, pc); + Events::log_exception(thread, "NullPointerException in code blob at " INTPTR_FORMAT, p2i(pc)); // There is no handler here, so we will simply unwind. return StubRoutines::throw_NullPointerException_at_call_entry(); } @@ -821,20 +869,32 @@ // => the nmethod is not yet active (i.e., the frame // is not set up yet) => use return address pushed by // caller => don't push another return address - Events::log_exception(thread, "NullPointerException in IC check " INTPTR_FORMAT, pc); + Events::log_exception(thread, "NullPointerException in IC check " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_NullPointerException_at_call_entry(); } if (nm->method()->is_method_handle_intrinsic()) { // exception happened inside MH dispatch code, similar to a vtable stub - Events::log_exception(thread, "NullPointerException in MH adapter " INTPTR_FORMAT, pc); + Events::log_exception(thread, "NullPointerException in MH adapter " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_NullPointerException_at_call_entry(); } #ifndef PRODUCT _implicit_null_throws++; #endif +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci() && nm->pc_desc_at(pc) != NULL) { + // If there's no PcDesc then we'll die way down inside of + // deopt instead of just getting normal error reporting, + // so only go there if it will succeed. + return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_null_check); + } else { +#endif // INCLUDE_JVMCI + assert (nm->is_nmethod(), "Expect nmethod"); target_pc = nm->continuation_for_implicit_exception(pc); +#if INCLUDE_JVMCI + } +#endif // INCLUDE_JVMCI // If there's an unexpected fault, target_pc might be NULL, // in which case we want to fall through into the normal // error handling code. @@ -846,11 +906,19 @@ case IMPLICIT_DIVIDE_BY_ZERO: { nmethod* nm = CodeCache::find_nmethod(pc); - guarantee(nm != NULL, "must have containing nmethod for implicit division-by-zero exceptions"); + guarantee(nm != NULL, "must have containing compiled method for implicit division-by-zero exceptions"); #ifndef PRODUCT _implicit_div0_throws++; #endif +#if INCLUDE_JVMCI + if (nm->is_compiled_by_jvmci() && nm->pc_desc_at(pc) != NULL) { + return deoptimize_for_implicit_exception(thread, pc, nm, Deoptimization::Reason_div0_check); + } else { +#endif // INCLUDE_JVMCI target_pc = nm->continuation_for_implicit_exception(pc); +#if INCLUDE_JVMCI + } +#endif // INCLUDE_JVMCI // If there's an unexpected fault, target_pc might be NULL, // in which case we want to fall through into the normal // error handling code. @@ -862,12 +930,18 @@ assert(exception_kind == IMPLICIT_NULL || exception_kind == IMPLICIT_DIVIDE_BY_ZERO, "wrong implicit exception kind"); - // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort("java.lang.NullPointerException")); if (exception_kind == IMPLICIT_NULL) { - Events::log_exception(thread, "Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); +#ifndef PRODUCT + // for AbortVMOnException flag + Exceptions::debug_check_abort("java.lang.NullPointerException"); +#endif //PRODUCT + Events::log_exception(thread, "Implicit null exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, p2i(pc), p2i(target_pc)); } else { - Events::log_exception(thread, "Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, pc, target_pc); +#ifndef PRODUCT + // for AbortVMOnException flag + Exceptions::debug_check_abort("java.lang.ArithmeticException"); +#endif //PRODUCT + Events::log_exception(thread, "Implicit division by zero exception at " INTPTR_FORMAT " to " INTPTR_FORMAT, p2i(pc), p2i(target_pc)); } return target_pc; } @@ -916,6 +990,16 @@ JRT_ENTRY_NO_ASYNC(void, SharedRuntime::register_finalizer(JavaThread* thread, oopDesc* obj)) assert(obj->is_oop(), "must be a valid oop"); +#if INCLUDE_JVMCI + // This removes the requirement for JVMCI compilers to emit code + // performing a dynamic check that obj has a finalizer before + // calling this routine. There should be no performance impact + // for C1 since it emits a dynamic check. C2 and the interpreter + // uses other runtime routines for registering finalizers. + if (!obj->klass()->has_finalizer()) { + return; + } +#endif // INCLUDE_JVMCI assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise"); InstanceKlass::register_finalizer(instanceOop(obj), CHECK); JRT_END @@ -1157,6 +1241,7 @@ methodHandle callee_method = call_info.selected_method(); assert((!is_virtual && invoke_code == Bytecodes::_invokestatic ) || + (!is_virtual && invoke_code == Bytecodes::_invokespecial) || (!is_virtual && invoke_code == Bytecodes::_invokehandle ) || (!is_virtual && invoke_code == Bytecodes::_invokedynamic) || ( is_virtual && invoke_code != Bytecodes::_invokestatic ), "inconsistent bytecode"); @@ -1176,7 +1261,8 @@ (is_optimized) ? "optimized " : "", (is_virtual) ? "virtual" : "static", Bytecodes::name(invoke_code)); callee_method->print_short_name(tty); - tty->print_cr(" at pc: " INTPTR_FORMAT " to code: " INTPTR_FORMAT, caller_frame.pc(), callee_method->code()); + tty->print_cr(" at pc: " INTPTR_FORMAT " to code: " INTPTR_FORMAT, + p2i(caller_frame.pc()), p2i(callee_method->code())); } #endif @@ -1367,9 +1453,6 @@ JRT_END - - - methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) { ResourceMark rm(thread); CallInfo call_info; @@ -1397,8 +1480,8 @@ ResourceMark rm(thread); tty->print("converting IC miss to reresolve (%s) call to", Bytecodes::name(bc)); callee_method->print_short_name(tty); - tty->print_cr(" from pc: " INTPTR_FORMAT, caller_frame.pc()); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" from pc: " INTPTR_FORMAT, p2i(caller_frame.pc())); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } return callee_method; } @@ -1415,7 +1498,7 @@ ResourceMark rm(thread); tty->print("IC miss (%s) call to", Bytecodes::name(bc)); callee_method->print_short_name(tty); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } if (ICMissHistogram) { @@ -1447,7 +1530,7 @@ ResourceMark rm(thread); tty->print("OPTIMIZED IC miss (%s) call to", Bytecodes::name(bc)); callee_method->print_short_name(tty); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } should_be_mono = true; } else if (inline_cache->is_icholder_call()) { @@ -1464,7 +1547,7 @@ ResourceMark rm(thread); tty->print("FALSE IC miss (%s) converting to compiled call to", Bytecodes::name(bc)); callee_method->print_short_name(tty); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } should_be_mono = true; } @@ -1493,6 +1576,8 @@ } else { // Either clean or megamorphic } + } else { + fatal("Unimplemented"); } } // Release CompiledIC_lock @@ -1520,6 +1605,10 @@ address pc = caller.pc(); + // Check for static or virtual call + bool is_static_call = false; + nmethod* caller_nm = CodeCache::find_nmethod(pc); + // Default call_addr is the location of the "basic" call. // Determine the address of the call we a reresolving. With // Inline Caches we will always find a recognizable call. @@ -1549,10 +1638,6 @@ call_addr = ncall->instruction_address(); } } - - // Check for static or virtual call - bool is_static_call = false; - nmethod* caller_nm = CodeCache::find_nmethod(pc); // Make sure nmethod doesn't get deoptimized and removed until // this is done with it. // CLEANUP - with lazy deopt shouldn't need this lock @@ -1604,7 +1689,7 @@ ResourceMark rm(thread); tty->print("handle_wrong_method reresolving call to"); callee_method->print_short_name(tty); - tty->print_cr(" code: " INTPTR_FORMAT, callee_method->code()); + tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code())); } #endif @@ -1630,7 +1715,7 @@ for (int i = 0; i < member_arg_pos; i++) { VMReg a = regs_with_member_name[i].first(); VMReg b = regs_without_member_name[i].first(); - assert(a->value() == b->value(), err_msg_res("register allocation mismatch: a=%d, b=%d", a->value(), b->value())); + assert(a->value() == b->value(), "register allocation mismatch: a=" INTX_FORMAT ", b=" INTX_FORMAT, a->value(), b->value()); } assert(regs_with_member_name[member_arg_pos].first()->is_valid(), "bad member arg"); } @@ -1712,25 +1797,25 @@ if (callee == cb || callee->is_adapter_blob()) { // static call or optimized virtual if (TraceCallFixup) { - tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc); + tty->print("fixup callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc)); moop->print_short_name(tty); - tty->print_cr(" to " INTPTR_FORMAT, entry_point); + tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point)); } call->set_destination_mt_safe(entry_point); } else { if (TraceCallFixup) { - tty->print("failed to fixup callsite at " INTPTR_FORMAT " to compiled code for", caller_pc); + tty->print("failed to fixup callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc)); moop->print_short_name(tty); - tty->print_cr(" to " INTPTR_FORMAT, entry_point); + tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point)); } // assert is too strong could also be resolve destinations. // assert(InlineCacheBuffer::contains(destination) || VtableStubs::contains(destination), "must be"); } } else { if (TraceCallFixup) { - tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", caller_pc); + tty->print("already patched callsite at " INTPTR_FORMAT " to compiled code for", p2i(caller_pc)); moop->print_short_name(tty); - tty->print_cr(" to " INTPTR_FORMAT, entry_point); + tty->print_cr(" to " INTPTR_FORMAT, p2i(entry_point)); } } } @@ -2567,8 +2652,7 @@ // Perform the work while holding the lock, but perform any printing outside the lock MutexLocker mu(AdapterHandlerLibrary_lock); // See if somebody beat us to it - nm = method->code(); - if (nm != NULL) { + if (method->code() != NULL) { return; } @@ -2810,7 +2894,7 @@ FREE_C_HEAP_ARRAY(intptr_t, buf); JRT_END -bool AdapterHandlerLibrary::contains(CodeBlob* b) { +bool AdapterHandlerLibrary::contains(const CodeBlob* b) { AdapterHandlerTableIterator iter(_adapters); while (iter.has_next()) { AdapterHandlerEntry* a = iter.next(); @@ -2819,7 +2903,7 @@ return false; } -void AdapterHandlerLibrary::print_handler_on(outputStream* st, CodeBlob* b) { +void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b) { AdapterHandlerTableIterator iter(_adapters); while (iter.has_next()) { AdapterHandlerEntry* a = iter.next(); @@ -2834,8 +2918,8 @@ void AdapterHandlerEntry::print_adapter_on(outputStream* st) const { st->print_cr("AHE@" INTPTR_FORMAT ": %s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT, - (intptr_t) this, fingerprint()->as_string(), - get_i2c_entry(), get_c2i_entry(), get_c2i_unverified_entry()); + p2i(this), fingerprint()->as_string(), + p2i(get_i2c_entry()), p2i(get_c2i_entry()), p2i(get_c2i_unverified_entry())); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/sharedRuntime.hpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -199,6 +199,9 @@ static address continuation_for_implicit_exception(JavaThread* thread, address faulting_pc, ImplicitExceptionKind exception_kind); +#if INCLUDE_JVMCI + static address deoptimize_for_implicit_exception(JavaThread* thread, address pc, nmethod* nm, int deopt_reason); +#endif // Shared stub locations static address get_poll_stub(address pc); @@ -417,6 +420,12 @@ const VMRegPair *regs, AdapterFingerPrint* fingerprint); + static void gen_i2c_adapter(MacroAssembler *_masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs); + // OSR support // OSR_migration_begin will extract the jvm state from an interpreter @@ -475,6 +484,7 @@ // A compiled caller has just called the interpreter, but compiled code // exists. Patch the caller so he no longer calls into the interpreter. static void fixup_callers_callsite(Method* moop, address ret_pc); + static bool should_fixup_call_destination(address destination, address entry_point, address caller_pc, Method* moop, CodeBlob* cb); // Slow-path Locking and Unlocking static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread); @@ -673,9 +683,9 @@ static void create_native_wrapper(methodHandle method); static AdapterHandlerEntry* get_adapter(methodHandle method); - static void print_handler(CodeBlob* b) { print_handler_on(tty, b); } - static void print_handler_on(outputStream* st, CodeBlob* b); - static bool contains(CodeBlob* b); + static void print_handler(const CodeBlob* b) { print_handler_on(tty, b); } + static void print_handler_on(outputStream* st, const CodeBlob* b); + static bool contains(const CodeBlob* b); #ifndef PRODUCT static void print_statistics(); #endif // PRODUCT diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/signature.cpp --- a/hotspot/src/share/vm/runtime/signature.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/signature.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -32,8 +32,6 @@ #include "oops/typeArrayKlass.hpp" #include "runtime/signature.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of SignatureIterator // Signature syntax: @@ -51,7 +49,7 @@ } void SignatureIterator::expect(char c) { - if (_signature->byte_at(_index) != c) fatal(err_msg("expecting %c", c)); + if (_signature->byte_at(_index) != c) fatal("expecting %c", c); _index++; } @@ -209,7 +207,7 @@ return; break; default: - tty->print_cr("*** parameter is %d", fingerprint & parameter_feature_mask); + tty->print_cr("*** parameter is " UINT64_FORMAT, fingerprint & parameter_feature_mask); tty->print_cr("*** fingerprint is " PTR64_FORMAT, saved_fingerprint); ShouldNotReachHere(); break; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/stackValueCollection.cpp --- a/hotspot/src/share/vm/runtime/stackValueCollection.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/stackValueCollection.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -25,8 +25,6 @@ #include "precompiled.hpp" #include "runtime/stackValueCollection.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - jint StackValueCollection::int_at(int slot) const { intptr_t val = at(slot)->get_int(); jint ival = *((jint*) (&val)); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/stubRoutines.cpp --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -136,8 +136,9 @@ address StubRoutines::_sha512_implCompressMB = NULL; address StubRoutines::_updateBytesCRC32 = NULL; -address StubRoutines::_crc_table_adr = NULL; +address StubRoutines::_crc_table_adr = NULL; +address StubRoutines::_crc32c_table_addr = NULL; address StubRoutines::_updateBytesCRC32C = NULL; address StubRoutines::_updateBytesAdler32 = NULL; @@ -147,9 +148,10 @@ address StubRoutines::_montgomeryMultiply = NULL; address StubRoutines::_montgomerySquare = NULL; +address StubRoutines::_dexp = NULL; + double (* StubRoutines::_intrinsic_log )(double) = NULL; double (* StubRoutines::_intrinsic_log10 )(double) = NULL; -double (* StubRoutines::_intrinsic_exp )(double) = NULL; double (* StubRoutines::_intrinsic_pow )(double, double) = NULL; double (* StubRoutines::_intrinsic_sin )(double) = NULL; double (* StubRoutines::_intrinsic_cos )(double) = NULL; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/stubRoutines.hpp --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -197,6 +197,7 @@ static address _updateBytesCRC32; static address _crc_table_adr; + static address _crc32c_table_addr; static address _updateBytesCRC32C; static address _updateBytesAdler32; @@ -206,6 +207,8 @@ static address _montgomeryMultiply; static address _montgomerySquare; + static address _dexp; + // 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 @@ -214,7 +217,6 @@ // SharedRuntime. static double (*_intrinsic_log)(double); static double (*_intrinsic_log10)(double); - static double (*_intrinsic_exp)(double); static double (*_intrinsic_pow)(double, double); static double (*_intrinsic_sin)(double); static double (*_intrinsic_cos)(double); @@ -364,6 +366,7 @@ static address updateBytesCRC32() { return _updateBytesCRC32; } static address crc_table_addr() { return _crc_table_adr; } + static address crc32c_table_addr() { return _crc32c_table_addr; } static address updateBytesCRC32C() { return _updateBytesCRC32C; } static address updateBytesAdler32() { return _updateBytesAdler32; } @@ -373,6 +376,8 @@ static address montgomeryMultiply() { return _montgomeryMultiply; } static address montgomerySquare() { return _montgomerySquare; } + static address dexp() {return _dexp; } + static address select_fill_function(BasicType t, bool aligned, const char* &name); static address zero_aligned_words() { return _zero_aligned_words; } @@ -385,10 +390,6 @@ assert(_intrinsic_log != NULL, "must be defined"); return _intrinsic_log10(d); } - static double intrinsic_exp(double d) { - assert(_intrinsic_exp != NULL, "must be defined"); - return _intrinsic_exp(d); - } static double intrinsic_pow(double d, double d2) { assert(_intrinsic_pow != NULL, "must be defined"); return _intrinsic_pow(d, d2); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/sweeper.cpp --- a/hotspot/src/share/vm/runtime/sweeper.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/sweeper.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -43,8 +43,6 @@ #include "utilities/ticks.inline.hpp" #include "utilities/xmlstream.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef ASSERT #define SWEEP(nm) record_sweep(nm, __LINE__) @@ -62,12 +60,12 @@ void print() { tty->print_cr("traversal = %d compile_id = %d %s uep = " PTR_FORMAT " vep = " - PTR_FORMAT " state = %d traversal_mark %d line = %d", + PTR_FORMAT " state = %d traversal_mark %ld line = %d", traversal, compile_id, kind == NULL ? "" : kind, - uep, - vep, + p2i(uep), + p2i(vep), state, traversal_mark, line); @@ -223,7 +221,7 @@ _total_time_this_sweep = Tickspan(); if (PrintMethodFlushing) { - tty->print_cr("### Sweep: stack traversal %d", _traversals); + tty->print_cr("### Sweep: stack traversal %ld", _traversals); } Threads::nmethods_do(&mark_activation_closure); @@ -482,7 +480,7 @@ #ifdef ASSERT if(PrintMethodFlushing) { - tty->print_cr("### sweeper: sweep time(%d): ", (jlong)sweep_time.value()); + tty->print_cr("### sweeper: sweep time(" JLONG_FORMAT "): ", sweep_time.value()); } #endif @@ -592,14 +590,14 @@ if (nm->is_marked_for_reclamation()) { assert(!nm->is_locked_by_vm(), "must not flush locked nmethods"); if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm); + tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), p2i(nm)); } release_nmethod(nm); assert(result == None, "sanity"); result = Flushed; } else { if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm); + tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), p2i(nm)); } nm->mark_for_reclamation(); // Keep track of code cache state change @@ -619,7 +617,7 @@ nm->clear_ic_stubs(); } if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); + tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), p2i(nm)); } // Code cache state change is tracked in make_zombie() nm->make_zombie(); @@ -636,7 +634,7 @@ } else if (nm->is_unloaded()) { // Unloaded code, just make it a zombie if (PrintMethodFlushing && Verbose) { - tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm); + tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), p2i(nm)); } if (nm->is_osr_method()) { SWEEP(nm); @@ -743,7 +741,7 @@ // Code cache state change is tracked in make_not_entrant() if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %d/" PTR_FORMAT "made not-entrant: hotness counter %d/%d threshold %f", - nm->compile_id(), nm, nm->hotness_counter(), reset_val, threshold); + nm->compile_id(), p2i(nm), nm->hotness_counter(), reset_val, threshold); } } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/sweeper.hpp --- a/hotspot/src/share/vm/runtime/sweeper.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/sweeper.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -27,7 +27,9 @@ class WhiteBox; +#include "code/codeCache.hpp" #include "utilities/ticks.hpp" + // An NmethodSweeper is an incremental cleaner for: // - cleanup inline caches // - reclamation of nmethods diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/synchronizer.cpp --- a/hotspot/src/share/vm/runtime/synchronizer.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -52,8 +52,6 @@ #define NOINLINE #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // The "core" versions of monitor enter and exit reside in this file. // The interpreter and compilers contain specialized transliterated // variants of the enter-exit fast-path operations. See i486.ad fast_lock(), @@ -1417,7 +1415,7 @@ if (object->is_instance()) { ResourceMark rm; tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (void *) object, (intptr_t) object->mark(), + p2i(object), p2i(object->mark()), object->klass()->external_name()); } } @@ -1465,7 +1463,7 @@ if (object->is_instance()) { ResourceMark rm; tty->print_cr("Inflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (void *) object, (intptr_t) object->mark(), + p2i(object), p2i(object->mark()), object->klass()->external_name()); } } @@ -1529,7 +1527,7 @@ if (obj->is_instance()) { ResourceMark rm; tty->print_cr("Deflating object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s", - (void *) obj, (intptr_t) obj->mark(), obj->klass()->external_name()); + p2i(obj), p2i(obj->mark()), obj->klass()->external_name()); } } @@ -1702,9 +1700,9 @@ Handle obj((oop) mid->object()); tty->print("INFO: unexpected locked object:"); javaVFrame::print_locked_object_class_name(tty, obj, "locked"); - fatal(err_msg("exiting JavaThread=" INTPTR_FORMAT - " unexpectedly owns ObjectMonitor=" INTPTR_FORMAT, - THREAD, mid)); + fatal("exiting JavaThread=" INTPTR_FORMAT + " unexpectedly owns ObjectMonitor=" INTPTR_FORMAT, + p2i(THREAD), p2i(mid)); } (void)mid->complete_exit(CHECK); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,12 +31,14 @@ #include "code/codeCacheExtensions.hpp" #include "code/scopeDesc.hpp" #include "compiler/compileBroker.hpp" +#include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" #include "gc/shared/workgroup.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" #include "interpreter/oopMapCache.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "logging/logConfiguration.hpp" #include "memory/metaspaceShared.hpp" #include "memory/oopFactory.hpp" #include "memory/universe.inline.hpp" @@ -99,6 +101,10 @@ #include "gc/g1/concurrentMarkThread.inline.hpp" #include "gc/parallel/pcTasks.hpp" #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI +#include "jvmci/jvmciCompiler.hpp" +#include "jvmci/jvmciRuntime.hpp" +#endif #ifdef COMPILER1 #include "c1/c1_Compiler.hpp" #endif @@ -110,8 +116,6 @@ #include "runtime/rtmLocking.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef DTRACE_ENABLED // Only bother with this argument setup if dtrace is available @@ -163,7 +167,7 @@ if (TraceBiasedLocking) { if (aligned_addr != real_malloc_addr) { tty->print_cr("Aligned thread " INTPTR_FORMAT " to " INTPTR_FORMAT, - real_malloc_addr, aligned_addr); + p2i(real_malloc_addr), p2i(aligned_addr)); } } ((Thread*) aligned_addr)->_real_malloc_address = real_malloc_addr; @@ -797,7 +801,7 @@ if (os::get_native_priority(this, &os_prio) == OS_OK) { st->print("os_prio=%d ", os_prio); } - st->print("tid=" INTPTR_FORMAT " ", this); + st->print("tid=" INTPTR_FORMAT " ", p2i(this)); ext().print_on(st); osthread()->print_on(st); } @@ -816,7 +820,7 @@ else st->print("Thread"); st->print(" [stack: " PTR_FORMAT "," PTR_FORMAT "]", - _stack_base - _stack_size, _stack_base); + p2i(_stack_base - _stack_size), p2i(_stack_base)); if (osthread()) { st->print(" [id=%d]", osthread()->thread_id()); @@ -879,7 +883,7 @@ cur != VMOperationRequest_lock && cur != VMOperationQueue_lock) || cur->rank() == Mutex::special) { - fatal(err_msg("Thread holding lock at safepoint that vm can block on: %s", cur->name())); + fatal("Thread holding lock at safepoint that vm can block on: %s", cur->name()); } } } @@ -1148,6 +1152,7 @@ NamedThread::NamedThread() : Thread() { _name = NULL; _processed_thread = NULL; + _gc_id = GCId::undefined(); } NamedThread::~NamedThread() { @@ -1386,6 +1391,33 @@ // ======= JavaThread ======== +#if INCLUDE_JVMCI + +jlong* JavaThread::_jvmci_old_thread_counters; + +bool jvmci_counters_include(JavaThread* thread) { + oop threadObj = thread->threadObj(); + return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread(); +} + +void JavaThread::collect_counters(typeArrayOop array) { + if (JVMCICounterSize > 0) { + MutexLocker tl(Threads_lock); + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, _jvmci_old_thread_counters[i]); + } + for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { + if (jvmci_counters_include(tp)) { + for (int i = 0; i < array->length(); i++) { + array->long_at_put(i, array->long_at(i) + tp->_jvmci_counters[i]); + } + } + } + } +} + +#endif // INCLUDE_JVMCI + // A JavaThread is a normal Java thread void JavaThread::initialize() { @@ -1418,6 +1450,20 @@ _in_deopt_handler = 0; _doing_unsafe_access = false; _stack_guard_state = stack_guard_unused; +#if INCLUDE_JVMCI + _pending_monitorenter = false; + _pending_deoptimization = -1; + _pending_failed_speculation = NULL; + _pending_transfer_to_interpreter = false; + _jvmci._alternate_call_target = NULL; + assert(_jvmci._implicit_exception_pc == NULL, "must be"); + if (JVMCICounterSize > 0) { + _jvmci_counters = NEW_C_HEAP_ARRAY(jlong, JVMCICounterSize, mtInternal); + memset(_jvmci_counters, 0, sizeof(jlong) * JVMCICounterSize); + } else { + _jvmci_counters = NULL; + } +#endif // INCLUDE_JVMCI (void)const_cast(_exception_oop = oop(NULL)); _exception_pc = 0; _exception_handler_pc = 0; @@ -1592,6 +1638,17 @@ ThreadSafepointState::destroy(this); if (_thread_profiler != NULL) delete _thread_profiler; if (_thread_stat != NULL) delete _thread_stat; + +#if INCLUDE_JVMCI + if (JVMCICounterSize > 0) { + if (jvmci_counters_include(this)) { + for (int i = 0; i < JVMCICounterSize; i++) { + _jvmci_old_thread_counters[i] += _jvmci_counters[i]; + } + } + FREE_C_HEAP_ARRAY(jlong, _jvmci_counters); + } +#endif // INCLUDE_JVMCI } @@ -2039,10 +2096,10 @@ if (TraceExceptions) { ResourceMark rm; - tty->print("Async. exception installed at runtime exit (" INTPTR_FORMAT ")", this); + tty->print("Async. exception installed at runtime exit (" INTPTR_FORMAT ")", p2i(this)); if (has_last_Java_frame()) { frame f = last_frame(); - tty->print(" (pc: " INTPTR_FORMAT " sp: " INTPTR_FORMAT " )", f.pc(), f.sp()); + tty->print(" (pc: " INTPTR_FORMAT " sp: " INTPTR_FORMAT " )", p2i(f.pc()), p2i(f.sp())); } tty->print_cr(" of type: %s", InstanceKlass::cast(_pending_async_exception->klass())->external_name()); } @@ -2135,7 +2192,7 @@ // Do not throw asynchronous exceptions against the compiler thread // (the compiler thread should not be a Java thread -- fix in 1.4.2) - if (is_Compiler_thread()) return; + if (!can_call_java()) return; { // Actually throw the Throwable against the target Thread - however @@ -2614,12 +2671,6 @@ StackFrameStream fst(this, UseBiasedLocking); for (; !fst.is_done(); fst.next()) { if (fst.current()->should_be_deoptimized()) { - if (LogCompilation && xtty != NULL) { - nmethod* nm = fst.current()->cb()->as_nmethod_or_null(); - xtty->elem("deoptimized thread='" UINTX_FORMAT "' compile_id='%d'", - this->name(), nm != NULL ? nm->compile_id() : -1); - } - Deoptimization::deoptimize(this, *fst.current(), fst.register_map()); } } @@ -2658,6 +2709,8 @@ // Traverse the GCHandles Thread::oops_do(f, cld_f, cf); + JVMCI_ONLY(f->do_oop((oop*)&_pending_failed_speculation);) + assert((!has_last_Java_frame() && java_call_counter() == 0) || (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!"); @@ -2809,7 +2862,7 @@ st->print(", id=%d", osthread()->thread_id()); } st->print(", stack(" PTR_FORMAT "," PTR_FORMAT ")", - _stack_base - _stack_size, _stack_base); + p2i(_stack_base - _stack_size), p2i(_stack_base)); st->print("]"); return; } @@ -3047,15 +3100,15 @@ template inline void do_oop_work(T* p) { oop obj = oopDesc::load_decode_heap_oop(p); if (obj == NULL) return; - tty->print(INTPTR_FORMAT ": ", p); + tty->print(INTPTR_FORMAT ": ", p2i(p)); if (obj->is_oop_or_null()) { if (obj->is_objArray()) { - tty->print_cr("valid objArray: " INTPTR_FORMAT, (oopDesc*) obj); + tty->print_cr("valid objArray: " INTPTR_FORMAT, p2i(obj)); } else { obj->print(); } } else { - tty->print_cr("invalid oop: " INTPTR_FORMAT, (oopDesc*) obj); + tty->print_cr("invalid oop: " INTPTR_FORMAT, p2i(obj)); } tty->cr(); } @@ -3175,6 +3228,10 @@ #endif } +bool CompilerThread::can_call_java() const { + return _compiler != NULL && _compiler->is_jvmci(); +} + // Create sweeper thread CodeCacheSweeperThread::CodeCacheSweeperThread() : JavaThread(&sweeper_thread_entry) { @@ -3306,6 +3363,10 @@ // Initialize the os module before using TLS os::init(); + // Record VM creation timing statistics + TraceVmCreationTime create_vm_timer; + create_vm_timer.start(); + // Initialize system properties. Arguments::init_system_properties(); @@ -3315,6 +3376,9 @@ // Update/Initialize System properties after JDK version number is known Arguments::init_version_specific_system_properties(); + // Make sure to initialize log configuration *before* parsing arguments + LogConfiguration::initialize(create_vm_timer.begin_time()); + // Parse arguments jint parse_result = Arguments::parse(args); if (parse_result != JNI_OK) return parse_result; @@ -3341,10 +3405,6 @@ HOTSPOT_VM_INIT_BEGIN(); - // Record VM creation timing statistics - TraceVmCreationTime create_vm_timer; - create_vm_timer.start(); - // Timing (must come after argument parsing) TraceTime timer("Create VM", TraceStartupTime); @@ -3380,6 +3440,15 @@ // Initialize global data structures and create system classes in heap vm_init_globals(); +#if INCLUDE_JVMCI + if (JVMCICounterSize > 0) { + JavaThread::_jvmci_old_thread_counters = NEW_C_HEAP_ARRAY(jlong, JVMCICounterSize, mtInternal); + memset(JavaThread::_jvmci_old_thread_counters, 0, sizeof(jlong) * JVMCICounterSize); + } else { + JavaThread::_jvmci_old_thread_counters = NULL; + } +#endif // INCLUDE_JVMCI + // Attach the main thread to this os thread JavaThread* main_thread = new JavaThread(); main_thread->set_thread_state(_thread_in_vm); @@ -3492,6 +3561,7 @@ // debug stuff, that does not work until all basic classes have been initialized. set_init_completed(); + LogConfiguration::post_initialize(); Metaspace::post_initialize(); HOTSPOT_VM_INIT_END(); @@ -3506,7 +3576,7 @@ // Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and // set_init_completed has just been called, causing exceptions not to be shortcut // anymore. We call vm_exit_during_initialization directly instead. - SystemDictionary::compute_java_system_loader(CHECK_JNI_ERR); + SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR)); #if INCLUDE_ALL_GCS // Support for ConcurrentMarkSweep. This should be cleaned up @@ -3554,8 +3624,17 @@ Chunk::start_chunk_pool_cleaner_task(); } +#if INCLUDE_JVMCI + if (EnableJVMCI) { + const char* jvmciCompiler = Arguments::PropertyList_get_value(Arguments::system_properties(), "jvmci.compiler"); + if (jvmciCompiler != NULL) { + JVMCIRuntime::save_compiler(jvmciCompiler); + } + } +#endif // INCLUDE_JVMCI + // initialize compiler(s) -#if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) +#if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI CompileBroker::compilation_init(); #endif @@ -3963,9 +4042,17 @@ delete thread; +#if INCLUDE_JVMCI + if (JVMCICounterSize > 0) { + FREE_C_HEAP_ARRAY(jlong, JavaThread::_jvmci_old_thread_counters); + } +#endif + // exit_globals() will delete tty exit_globals(); + LogConfiguration::finalize(); + return true; } @@ -4007,7 +4094,7 @@ ThreadService::add_thread(p, daemon); // Possible GC point. - Events::log(p, "Thread added: " INTPTR_FORMAT, p); + Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p)); } void Threads::remove(JavaThread* p) { @@ -4053,7 +4140,7 @@ } // unlock Threads_lock // Since Events::log uses a lock, we grab it outside the Threads_lock - Events::log(p, "Thread exited: " INTPTR_FORMAT, p); + Events::log(p, "Thread exited: " INTPTR_FORMAT, p2i(p)); } // Threads_lock must be held when this is called (or must be called during a safepoint) @@ -4096,7 +4183,7 @@ ALL_JAVA_THREADS(p) { const int thread_parity = p->oops_do_parity(); assert((thread_parity == _thread_claim_parity), - err_msg("Thread " PTR_FORMAT " has incorrect parity %d != %d", p2i(p), thread_parity, _thread_claim_parity)); + "Thread " PTR_FORMAT " has incorrect parity %d != %d", p2i(p), thread_parity, _thread_claim_parity); } } #endif // ASSERT @@ -4179,7 +4266,7 @@ { MutexLockerEx ml(doLock ? Threads_lock : NULL); ALL_JAVA_THREADS(p) { - if (p->is_Compiler_thread()) continue; + if (!p->can_call_java()) continue; address pending = (address)p->current_pending_monitor(); if (pending == monitor) { // found a match @@ -4236,7 +4323,7 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format, bool print_concurrent_locks) { char buf[32]; - st->print_cr("%s", os::local_time_string(buf, sizeof(buf))); + st->print_raw_cr(os::local_time_string(buf, sizeof(buf))); st->print_cr("Full thread dump %s (%s %s):", Abstract_VM_Version::vm_name(), @@ -4296,7 +4383,7 @@ st->print("%s", is_current ? "=>" : " "); - st->print(PTR_FORMAT, thread); + st->print(PTR_FORMAT, p2i(thread)); st->print(" "); thread->print_on_error(st, buf, buflen); st->cr(); @@ -4309,7 +4396,7 @@ found_current = found_current || is_current; st->print("%s", current == VMThread::vm_thread() ? "=>" : " "); - st->print(PTR_FORMAT, VMThread::vm_thread()); + st->print(PTR_FORMAT, p2i(VMThread::vm_thread())); st->print(" "); VMThread::vm_thread()->print_on_error(st, buf, buflen); st->cr(); @@ -4320,14 +4407,14 @@ found_current = found_current || is_current; st->print("%s", is_current ? "=>" : " "); - st->print(PTR_FORMAT, wt); + st->print(PTR_FORMAT, p2i(wt)); st->print(" "); wt->print_on_error(st, buf, buflen); st->cr(); } if (!found_current) { st->cr(); - st->print("=>" PTR_FORMAT " (exited) ", current); + st->print("=>" PTR_FORMAT " (exited) ", p2i(current)); current->print_on_error(st, buf, buflen); st->cr(); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/thread.hpp --- a/hotspot/src/share/vm/runtime/thread.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/thread.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -329,6 +329,9 @@ virtual bool is_Named_thread() const { return false; } virtual bool is_Worker_thread() const { return false; } + // Can this thread make Java upcalls + virtual bool can_call_java() const { return false; } + // Casts virtual WorkerThread* as_Worker_thread() const { return NULL; } @@ -678,6 +681,7 @@ char* _name; // log JavaThread being processed by oops_do JavaThread* _processed_thread; + uint _gc_id; // The current GC id when a thread takes part in GC public: NamedThread(); @@ -690,6 +694,9 @@ JavaThread *processed_thread() { return _processed_thread; } void set_processed_thread(JavaThread *thread) { _processed_thread = thread; } virtual void print_on(outputStream* st) const; + + void set_gc_id(uint gc_id) { _gc_id = gc_id; } + uint gc_id() { return _gc_id; } }; // Worker threads are named and have an id of an assigned work. @@ -900,6 +907,43 @@ private: +#if INCLUDE_JVMCI + // The _pending_* fields below are used to communicate extra information + // from an uncommon trap in JVMCI compiled code to the uncommon trap handler. + + // Communicates the DeoptReason and DeoptAction of the uncommon trap + int _pending_deoptimization; + + // Specifies whether the uncommon trap is to bci 0 of a synchronized method + // before the monitor has been acquired. + bool _pending_monitorenter; + + // Specifies if the DeoptReason for the last uncommon trap was Reason_transfer_to_interpreter + bool _pending_transfer_to_interpreter; + + // An object that JVMCI compiled code can use to further describe and + // uniquely identify the speculative optimization guarded by the uncommon trap + oop _pending_failed_speculation; + + // These fields are mutually exclusive in terms of live ranges. + union { + // Communicates the pc at which the most recent implicit exception occurred + // from the signal handler to a deoptimization stub. + address _implicit_exception_pc; + + // Communicates an alternative call target to an i2c stub from a JavaCall . + address _alternate_call_target; + } _jvmci; + + // Support for high precision, thread sensitive counters in JVMCI compiled code. + jlong* _jvmci_counters; + + public: + static jlong* _jvmci_old_thread_counters; + static void collect_counters(typeArrayOop array); + private: +#endif // INCLUDE_JVMCI + StackGuardState _stack_guard_state; // Precompute the limit of the stack as used in stack overflow checks. @@ -914,6 +958,7 @@ volatile address _exception_handler_pc; // PC for handler of exception volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. + private: // support for JNI critical regions jint _jni_active_critical; // count of entries into JNI critical region @@ -1001,6 +1046,7 @@ // Testers virtual bool is_Java_thread() const { return true; } + virtual bool can_call_java() const { return true; } // Thread chain operations JavaThread* next() const { return _next; } @@ -1259,6 +1305,18 @@ MemRegion deferred_card_mark() const { return _deferred_card_mark; } void set_deferred_card_mark(MemRegion mr) { _deferred_card_mark = mr; } +#if INCLUDE_JVMCI + int pending_deoptimization() const { return _pending_deoptimization; } + oop pending_failed_speculation() const { return _pending_failed_speculation; } + bool has_pending_monitorenter() const { return _pending_monitorenter; } + void set_pending_monitorenter(bool b) { _pending_monitorenter = b; } + void set_pending_deoptimization(int reason) { _pending_deoptimization = reason; } + void set_pending_failed_speculation(oop failed_speculation) { _pending_failed_speculation = failed_speculation; } + void set_pending_transfer_to_interpreter(bool b) { _pending_transfer_to_interpreter = b; } + void set_jvmci_alternate_call_target(address a) { assert(_jvmci._alternate_call_target == NULL, "must be"); _jvmci._alternate_call_target = a; } + void set_jvmci_implicit_exception_pc(address a) { assert(_jvmci._implicit_exception_pc == NULL, "must be"); _jvmci._implicit_exception_pc = a; } +#endif // INCLUDE_JVMCI + // Exception handling for compiled methods oop exception_oop() const { return _exception_oop; } address exception_pc() const { return _exception_pc; } @@ -1359,6 +1417,14 @@ static ByteSize thread_state_offset() { return byte_offset_of(JavaThread, _thread_state); } static ByteSize saved_exception_pc_offset() { return byte_offset_of(JavaThread, _saved_exception_pc); } static ByteSize osthread_offset() { return byte_offset_of(JavaThread, _osthread); } +#if INCLUDE_JVMCI + static ByteSize pending_deoptimization_offset() { return byte_offset_of(JavaThread, _pending_deoptimization); } + static ByteSize pending_monitorenter_offset() { return byte_offset_of(JavaThread, _pending_monitorenter); } + static ByteSize pending_failed_speculation_offset() { return byte_offset_of(JavaThread, _pending_failed_speculation); } + static ByteSize jvmci_alternate_call_target_offset() { return byte_offset_of(JavaThread, _jvmci._alternate_call_target); } + static ByteSize jvmci_implicit_exception_pc_offset() { return byte_offset_of(JavaThread, _jvmci._implicit_exception_pc); } + static ByteSize jvmci_counters_offset() { return byte_offset_of(JavaThread, _jvmci_counters); } +#endif // INCLUDE_JVMCI static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } @@ -1828,8 +1894,11 @@ CompilerThread(CompileQueue* queue, CompilerCounters* counters); bool is_Compiler_thread() const { return true; } - // Hide this compiler thread from external view. - bool is_hidden_from_external_view() const { return true; } + + virtual bool can_call_java() const; + + // Hide native compiler threads from external view. + bool is_hidden_from_external_view() const { return !can_call_java(); } void set_compiler(AbstractCompiler* c) { _compiler = c; } AbstractCompiler* compiler() const { return _compiler; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/timer.cpp --- a/hotspot/src/share/vm/runtime/timer.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/timer.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,6 +36,22 @@ return counter_to_seconds(counter) * 1000.0; } +elapsedTimer::elapsedTimer(jlong time, jlong timeUnitsPerSecond) { + _active = false; + jlong osTimeUnitsPerSecond = os::elapsed_frequency(); + assert(osTimeUnitsPerSecond % 1000 == 0, "must be"); + assert(timeUnitsPerSecond % 1000 == 0, "must be"); + while (osTimeUnitsPerSecond < timeUnitsPerSecond) { + timeUnitsPerSecond /= 1000; + time *= 1000; + } + while (osTimeUnitsPerSecond > timeUnitsPerSecond) { + timeUnitsPerSecond *= 1000; + time /= 1000; + } + _counter = time; +} + void elapsedTimer::add(elapsedTimer t) { _counter += t._counter; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/timer.hpp --- a/hotspot/src/share/vm/runtime/timer.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/timer.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -37,6 +37,7 @@ bool _active; public: elapsedTimer() { _active = false; reset(); } + elapsedTimer(jlong time, jlong timeUnitsPerSecond); void add(elapsedTimer t); void start(); void stop(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/unhandledOops.cpp --- a/hotspot/src/share/vm/runtime/unhandledOops.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/unhandledOops.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -31,8 +31,6 @@ #include "runtime/unhandledOops.hpp" #include "utilities/globalDefinitions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #ifdef CHECK_UNHANDLED_OOPS const int free_list_size = 256; @@ -52,7 +50,7 @@ void UnhandledOops::dump_oops(UnhandledOops *list) { for (int k = 0; k < list->_oop_list->length(); k++) { UnhandledOopEntry entry = list->_oop_list->at(k); - tty->print(" " INTPTR_FORMAT, entry._oop_ptr); + tty->print(" " INTPTR_FORMAT, p2i(entry._oop_ptr)); } tty->cr(); } @@ -68,7 +66,7 @@ _level ++; if (unhandled_oop_print) { for (int i=0; i<_level; i++) tty->print(" "); - tty->print_cr("r " INTPTR_FORMAT, op); + tty->print_cr("r " INTPTR_FORMAT, p2i(op)); } UnhandledOopEntry entry(op, pc); _oop_list->push(entry); @@ -105,7 +103,7 @@ _level --; if (unhandled_oop_print) { for (int i=0; i<_level; i++) tty->print(" "); - tty->print_cr("u " INTPTR_FORMAT, op); + tty->print_cr("u " INTPTR_FORMAT, p2i(op)); } int i = _oop_list->find_from_end(op, match_oop_entry); @@ -122,9 +120,9 @@ // anymore, it must not have gotten unregistered properly and it's a bug // in the unhandled oop generator. if(!_thread->is_in_stack((address)entry._oop_ptr)) { - tty->print_cr("oop_ptr is " INTPTR_FORMAT, (address)entry._oop_ptr); + tty->print_cr("oop_ptr is " INTPTR_FORMAT, p2i(entry._oop_ptr)); tty->print_cr("thread is " INTPTR_FORMAT " from pc " INTPTR_FORMAT, - (address)_thread, (address)entry._pc); + p2i(_thread), p2i(entry._pc)); assert(false, "heap is corrupted by the unhandled oop detector"); } // Set unhandled oops to a pattern that will crash distinctively diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/vframe.cpp --- a/hotspot/src/share/vm/runtime/vframe.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vframe.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -46,8 +46,6 @@ #include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - vframe::vframe(const frame* fr, const RegisterMap* reg_map, JavaThread* thread) : _reg_map(reg_map), _thread(thread) { assert(fr != NULL, "must have frame"); @@ -146,7 +144,7 @@ void javaVFrame::print_locked_object_class_name(outputStream* st, Handle obj, const char* lock_state) { if (obj.not_null()) { - st->print("\t- %s <" INTPTR_FORMAT "> ", lock_state, (address)obj()); + st->print("\t- %s <" INTPTR_FORMAT "> ", lock_state, p2i(obj())); if (obj->klass() == SystemDictionary::Class_klass()) { st->print_cr("(a java.lang.Class for %s)", java_lang_Class::as_external_name(obj())); } else { @@ -186,7 +184,7 @@ } else if (thread()->current_park_blocker() != NULL) { oop obj = thread()->current_park_blocker(); Klass* k = obj->klass(); - st->print_cr("\t- %s <" INTPTR_FORMAT "> (a %s)", "parking to wait for ", (address)obj, k->external_name()); + st->print_cr("\t- %s <" INTPTR_FORMAT "> (a %s)", "parking to wait for ", p2i(obj), k->external_name()); } } @@ -400,7 +398,7 @@ InterpreterOopMap oop_mask; // oopmap for current bci - if (TraceDeoptimization && Verbose) { + if ((TraceDeoptimization && Verbose) JVMCI_ONLY( || PrintDeoptimizationDetails)) { methodHandle m_h(Thread::current(), method()); OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask); } else { @@ -493,7 +491,7 @@ // This function is used in Class.forName, Class.newInstance, Method.Invoke, // AccessController.doPrivileged. void vframeStreamCommon::security_get_caller_frame(int depth) { - assert(depth >= 0, err_msg("invalid depth: %d", depth)); + assert(depth >= 0, "invalid depth: %d", depth); for (int n = 0; !at_end(); security_next()) { if (!method()->is_ignored_by_security_stack_walk()) { if (n == depth) { @@ -583,7 +581,7 @@ void entryVFrame::print() { vframe::print(); tty->print_cr("C Chunk inbetween Java"); - tty->print_cr("C link " INTPTR_FORMAT, _fr.link()); + tty->print_cr("C link " INTPTR_FORMAT, p2i(_fr.link())); } @@ -620,7 +618,7 @@ tty->print("( null )"); } else { monitor->owner()->print_value(); - tty->print("(owner=" INTPTR_FORMAT ")", (address)monitor->owner()); + tty->print("(owner=" INTPTR_FORMAT ")", p2i(monitor->owner())); } if (monitor->eliminated()) { if(is_compiled_frame()) { @@ -641,7 +639,7 @@ Method* m = method(); InstanceKlass* k = m->method_holder(); tty->print_cr("frame( sp=" INTPTR_FORMAT ", unextended_sp=" INTPTR_FORMAT ", fp=" INTPTR_FORMAT ", pc=" INTPTR_FORMAT ")", - _fr.sp(), _fr.unextended_sp(), _fr.fp(), _fr.pc()); + p2i(_fr.sp()), p2i(_fr.unextended_sp()), p2i(_fr.fp()), p2i(_fr.pc())); tty->print("%s.%s", k->internal_name(), m->name()->as_C_string()); if (!m->is_native()) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/vframeArray.cpp --- a/hotspot/src/share/vm/runtime/vframeArray.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vframeArray.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -44,8 +44,6 @@ #include "opto/runtime.hpp" #endif -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - int vframeArrayElement:: bci(void) const { return (_bci == SynchronizationEntryBCI ? 0 : _bci); } void vframeArrayElement::free_monitors(JavaThread* jt) { @@ -294,7 +292,7 @@ _frame.patch_pc(thread, pc); - assert (!method()->is_synchronized() || locks > 0 || _removed_monitors, "synchronized methods must have monitors"); + assert (!method()->is_synchronized() || locks > 0 || _removed_monitors || raw_bci() == SynchronizationEntryBCI, "synchronized methods must have monitors"); BasicObjectLock* top = iframe()->interpreter_frame_monitor_begin(); for (int index = 0; index < locks; index++) { @@ -317,6 +315,10 @@ } } + if (PrintDeoptimizationDetails) { + tty->print_cr("Expressions size: %d", expressions()->size()); + } + // Unpack expression stack // If this is an intermediate frame (i.e. not top frame) then this // only unpacks the part of the expression stack not used by callee @@ -329,9 +331,26 @@ switch(value->type()) { case T_INT: *addr = value->get_int(); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print_cr("Reconstructed expression %d (INT): %d", i, (int)(*addr)); + } +#endif break; case T_OBJECT: *addr = value->get_int(T_OBJECT); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print("Reconstructed expression %d (OBJECT): ", i); + oop o = (oop)(address)(*addr); + if (o == NULL) { + tty->print_cr("NULL"); + } else { + ResourceMark rm; + tty->print_raw_cr(o->klass()->name()->as_C_string()); + } + } +#endif break; case T_CONFLICT: // A dead stack slot. Initialize to null in case it is an oop. @@ -350,9 +369,26 @@ switch(value->type()) { case T_INT: *addr = value->get_int(); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print_cr("Reconstructed local %d (INT): %d", i, (int)(*addr)); + } +#endif break; case T_OBJECT: *addr = value->get_int(T_OBJECT); +#ifndef PRODUCT + if (PrintDeoptimizationDetails) { + tty->print("Reconstructed local %d (OBJECT): ", i); + oop o = (oop)(address)(*addr); + if (o == NULL) { + tty->print_cr("NULL"); + } else { + ResourceMark rm; + tty->print_raw_cr(o->klass()->name()->as_C_string()); + } + } +#endif break; case T_CONFLICT: // A dead location. If it is an oop then we need a NULL to prevent GC from following it @@ -394,7 +430,7 @@ } #ifndef PRODUCT - if (TraceDeoptimization && Verbose) { + if (PrintDeoptimizationDetails) { ttyLocker ttyl; tty->print_cr("[%d Interpreted Frame]", ++unpack_counter); iframe()->print_on(tty); @@ -415,7 +451,7 @@ int bci = method()->bci_from(bcp); tty->print(" - %s", Bytecodes::name(code)); tty->print(" @ bci %d ", bci); - tty->print_cr("sp = " PTR_FORMAT, iframe()->sp()); + tty->print_cr("sp = " PTR_FORMAT, p2i(iframe()->sp())); } #endif // PRODUCT @@ -605,7 +641,7 @@ // Note: we cannot have print_on as const, as we allocate inside the method void vframeArray::print_on_2(outputStream* st) { - st->print_cr(" - sp: " INTPTR_FORMAT, sp()); + st->print_cr(" - sp: " INTPTR_FORMAT, p2i(sp())); st->print(" - thread: "); Thread::current()->print(); st->print_cr(" - frame size: %d", frame_size()); @@ -615,7 +651,7 @@ } void vframeArrayElement::print(outputStream* st) { - st->print_cr(" - interpreter_frame -> sp: " INTPTR_FORMAT, iframe()->sp()); + st->print_cr(" - interpreter_frame -> sp: " INTPTR_FORMAT, p2i(iframe()->sp())); } void vframeArray::print_value_on(outputStream* st) const { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -107,6 +107,22 @@ #include "utilities/hashtable.hpp" #include "utilities/macros.hpp" +#ifdef TARGET_OS_FAMILY_linux +# include "vmStructs_linux.hpp" +#endif +#ifdef TARGET_OS_FAMILY_solaris +# include "vmStructs_solaris.hpp" +#endif +#ifdef TARGET_OS_FAMILY_windows +# include "vmStructs_windows.hpp" +#endif +#ifdef TARGET_OS_FAMILY_aix +# include "vmStructs_aix.hpp" +#endif +#ifdef TARGET_OS_FAMILY_bsd +# include "vmStructs_bsd.hpp" +#endif + #ifdef TARGET_ARCH_x86 # include "vmStructs_x86.hpp" #endif @@ -125,6 +141,7 @@ #ifdef TARGET_ARCH_aarch64 # include "vmStructs_aarch64.hpp" #endif + #ifdef TARGET_OS_ARCH_linux_x86 # include "vmStructs_linux_x86.hpp" #endif @@ -161,6 +178,7 @@ #ifdef TARGET_OS_ARCH_bsd_zero # include "vmStructs_bsd_zero.hpp" #endif + #if INCLUDE_ALL_GCS #include "gc/cms/compactibleFreeListSpace.hpp" #include "gc/cms/concurrentMarkSweepGeneration.hpp" @@ -178,6 +196,10 @@ #include "gc/parallel/vmStructs_parallelgc.hpp" #endif // INCLUDE_ALL_GCS +#if INCLUDE_JVMCI +# include "jvmci/vmStructs_jvmci.hpp" +#endif + #if INCLUDE_TRACE #include "runtime/vmStructs_trace.hpp" #endif @@ -311,6 +333,7 @@ nonstatic_field(InstanceKlass, _static_oop_field_count, u2) \ nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \ nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \ + nonstatic_field(InstanceKlass, _misc_flags, u2) \ nonstatic_field(InstanceKlass, _minor_version, u2) \ nonstatic_field(InstanceKlass, _major_version, u2) \ nonstatic_field(InstanceKlass, _init_state, u1) \ @@ -384,6 +407,7 @@ nonstatic_field(Method, _vtable_index, int) \ nonstatic_field(Method, _method_size, u2) \ nonstatic_field(Method, _intrinsic_id, u2) \ + nonstatic_field(Method, _flags, u1) \ nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \ volatile_nonstatic_field(Method, _code, nmethod*) \ nonstatic_field(Method, _i2i_entry, address) \ @@ -408,6 +432,7 @@ nonstatic_field(Symbol, _identity_hash, short) \ nonstatic_field(Symbol, _length, unsigned short) \ unchecked_nonstatic_field(Symbol, _body, sizeof(jbyte)) /* NOTE: no type */ \ + nonstatic_field(Symbol, _body[0], jbyte) \ nonstatic_field(TypeArrayKlass, _max_length, int) \ \ /***********************/ \ @@ -470,6 +495,8 @@ static_field(Universe, _bootstrapping, bool) \ static_field(Universe, _fully_initialized, bool) \ static_field(Universe, _verify_count, int) \ + static_field(Universe, _verify_oop_mask, uintptr_t) \ + static_field(Universe, _verify_oop_bits, uintptr_t) \ static_field(Universe, _non_oop_bits, intptr_t) \ static_field(Universe, _narrow_oop._base, address) \ static_field(Universe, _narrow_oop._shift, int) \ @@ -489,6 +516,10 @@ \ unchecked_nonstatic_field(ageTable, sizes, sizeof(ageTable::sizes)) \ \ + nonstatic_field(BarrierSet, _fake_rtti, BarrierSet::FakeRtti) \ + \ + nonstatic_field(BarrierSet::FakeRtti, _concrete_tag, BarrierSet::Name) \ + \ nonstatic_field(BlockOffsetTable, _bottom, HeapWord*) \ nonstatic_field(BlockOffsetTable, _end, HeapWord*) \ \ @@ -578,6 +609,7 @@ nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ static_field(ThreadLocalAllocBuffer, _target_refills, unsigned) \ @@ -787,6 +819,8 @@ /********************************/ \ \ static_field(CodeCache, _heaps, GrowableArray*) \ + static_field(CodeCache, _low_bound, address) \ + static_field(CodeCache, _high_bound, address) \ static_field(CodeCache, _scavenge_root_nmethods, nmethod*) \ \ /*******************************/ \ @@ -832,16 +866,48 @@ static_field(StubRoutines, _ghash_processBlocks, address) \ static_field(StubRoutines, _updateBytesCRC32, address) \ static_field(StubRoutines, _crc_table_adr, address) \ + static_field(StubRoutines, _crc32c_table_addr, address) \ static_field(StubRoutines, _updateBytesCRC32C, address) \ static_field(StubRoutines, _multiplyToLen, address) \ static_field(StubRoutines, _squareToLen, address) \ static_field(StubRoutines, _mulAdd, address) \ + static_field(StubRoutines, _dexp, address) \ + static_field(StubRoutines, _jbyte_arraycopy, address) \ + static_field(StubRoutines, _jshort_arraycopy, address) \ + static_field(StubRoutines, _jint_arraycopy, address) \ + static_field(StubRoutines, _jlong_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _checkcast_arraycopy, address) \ + static_field(StubRoutines, _checkcast_arraycopy_uninit, address) \ + static_field(StubRoutines, _unsafe_arraycopy, address) \ + static_field(StubRoutines, _generic_arraycopy, address) \ \ /*****************/ \ /* SharedRuntime */ \ /*****************/ \ \ + static_field(SharedRuntime, _wrong_method_blob, RuntimeStub*) \ static_field(SharedRuntime, _ic_miss_blob, RuntimeStub*) \ + static_field(SharedRuntime, _deopt_blob, DeoptimizationBlob*) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ @@ -856,16 +922,18 @@ /* CodeBlobs (NOTE: incomplete, but only a little) */ \ /***************************************************/ \ \ - nonstatic_field(CodeBlob, _name, const char*) \ - nonstatic_field(CodeBlob, _size, int) \ - nonstatic_field(CodeBlob, _header_size, int) \ - nonstatic_field(CodeBlob, _relocation_size, 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) \ - nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \ + nonstatic_field(CodeBlob, _name, const char*) \ + nonstatic_field(CodeBlob, _size, int) \ + nonstatic_field(CodeBlob, _header_size, int) \ + nonstatic_field(CodeBlob, _relocation_size, 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) \ + nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \ + \ + nonstatic_field(DeoptimizationBlob, _unpack_offset, int) \ \ nonstatic_field(RuntimeStub, _caller_must_gc_arguments, bool) \ \ @@ -905,6 +973,17 @@ \ unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \ \ + nonstatic_field(Deoptimization::UnrollBlock, _size_of_deoptimized_frame, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _caller_adjustment, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _number_of_frames, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _total_frame_sizes, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_sizes, intptr_t*) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_pcs, address*) \ + nonstatic_field(Deoptimization::UnrollBlock, _register_block, intptr_t*) \ + nonstatic_field(Deoptimization::UnrollBlock, _return_type, BasicType) \ + nonstatic_field(Deoptimization::UnrollBlock, _initial_info, intptr_t) \ + nonstatic_field(Deoptimization::UnrollBlock, _caller_actual_parameters, int) \ + \ /********************************/ \ /* JavaCalls (NOTE: incomplete) */ \ /********************************/ \ @@ -1294,6 +1373,7 @@ nonstatic_field(CompileTask, _osr_bci, int) \ nonstatic_field(CompileTask, _comp_level, int) \ nonstatic_field(CompileTask, _compile_id, uint) \ + nonstatic_field(CompileTask, _num_inlined_bytecodes, int) \ nonstatic_field(CompileTask, _next, CompileTask*) \ nonstatic_field(CompileTask, _prev, CompileTask*) \ \ @@ -1473,6 +1553,8 @@ declare_type(MethodCounters, MetaspaceObj) \ declare_type(ConstMethod, MetaspaceObj) \ \ + declare_toplevel_type(narrowKlass) \ + \ declare_toplevel_type(vtableEntry) \ \ declare_toplevel_type(Symbol) \ @@ -1572,6 +1654,8 @@ declare_toplevel_type(TenuredGeneration*) \ declare_toplevel_type(ThreadLocalAllocBuffer*) \ \ + declare_toplevel_type(BarrierSet::FakeRtti) \ + \ /************************/ \ /* PerfMemory - jvmstat */ \ /************************/ \ @@ -1694,6 +1778,7 @@ declare_toplevel_type(Dependencies) \ declare_toplevel_type(CompileTask) \ declare_toplevel_type(Deoptimization) \ + declare_toplevel_type(Deoptimization::UnrollBlock) \ \ /************************/ \ /* OopMap and OopMapSet */ \ @@ -1991,7 +2076,6 @@ declare_c2_type(TanDNode, Node) \ declare_c2_type(AtanDNode, Node) \ declare_c2_type(SqrtDNode, Node) \ - declare_c2_type(ExpDNode, Node) \ declare_c2_type(LogDNode, Node) \ declare_c2_type(Log10DNode, Node) \ declare_c2_type(PowDNode, Node) \ @@ -2276,6 +2360,8 @@ \ declare_constant(CardTableRS::youngergen_card) \ \ + declare_constant(G1SATBCardTableModRefBS::g1_young_gen) \ + \ declare_constant(CollectedHeap::GenCollectedHeap) \ declare_constant(CollectedHeap::ParallelScavengeHeap) \ declare_constant(CollectedHeap::G1CollectedHeap) \ @@ -2334,6 +2420,36 @@ declare_constant(JVM_ACC_PROMOTED_FLAGS) \ declare_constant(JVM_ACC_FIELD_ACCESS_WATCHED) \ declare_constant(JVM_ACC_FIELD_MODIFICATION_WATCHED) \ + declare_constant(JVM_ACC_FIELD_INTERNAL) \ + declare_constant(JVM_ACC_FIELD_STABLE) \ + declare_constant(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) \ + \ + declare_constant(JVM_CONSTANT_Utf8) \ + declare_constant(JVM_CONSTANT_Unicode) \ + declare_constant(JVM_CONSTANT_Integer) \ + declare_constant(JVM_CONSTANT_Float) \ + declare_constant(JVM_CONSTANT_Long) \ + declare_constant(JVM_CONSTANT_Double) \ + declare_constant(JVM_CONSTANT_Class) \ + declare_constant(JVM_CONSTANT_String) \ + declare_constant(JVM_CONSTANT_Fieldref) \ + declare_constant(JVM_CONSTANT_Methodref) \ + declare_constant(JVM_CONSTANT_InterfaceMethodref) \ + declare_constant(JVM_CONSTANT_NameAndType) \ + declare_constant(JVM_CONSTANT_MethodHandle) \ + declare_constant(JVM_CONSTANT_MethodType) \ + declare_constant(JVM_CONSTANT_InvokeDynamic) \ + declare_constant(JVM_CONSTANT_ExternalMax) \ + \ + declare_constant(JVM_CONSTANT_Invalid) \ + declare_constant(JVM_CONSTANT_InternalMin) \ + declare_constant(JVM_CONSTANT_UnresolvedClass) \ + declare_constant(JVM_CONSTANT_ClassIndex) \ + declare_constant(JVM_CONSTANT_StringIndex) \ + declare_constant(JVM_CONSTANT_UnresolvedClassInError) \ + declare_constant(JVM_CONSTANT_MethodHandleInError) \ + declare_constant(JVM_CONSTANT_MethodTypeInError) \ + declare_constant(JVM_CONSTANT_InternalMax) \ \ /*****************************/ \ /* Thread::SuspendFlags enum */ \ @@ -2364,6 +2480,7 @@ /******************************/ \ \ declare_constant(Klass::_primary_super_limit) \ + declare_constant(Klass::_lh_neutral_value) \ declare_constant(Klass::_lh_instance_slow_path_bit) \ declare_constant(Klass::_lh_log2_element_size_shift) \ declare_constant(Klass::_lh_log2_element_size_mask) \ @@ -2385,6 +2502,10 @@ declare_constant(Method::_dont_inline) \ declare_constant(Method::_hidden) \ \ + declare_constant(Method::nonvirtual_vtable_index) \ + \ + declare_constant(Method::extra_stack_entries_for_jsr292) \ + \ declare_constant(ConstMethod::_has_linenumber_table) \ declare_constant(ConstMethod::_has_checked_exceptions) \ declare_constant(ConstMethod::_has_localvariable_table) \ @@ -2401,6 +2522,20 @@ /**************/ \ \ declare_constant(DataLayout::cell_size) \ + declare_constant(DataLayout::no_tag) \ + declare_constant(DataLayout::bit_data_tag) \ + declare_constant(DataLayout::counter_data_tag) \ + declare_constant(DataLayout::jump_data_tag) \ + declare_constant(DataLayout::receiver_type_data_tag) \ + declare_constant(DataLayout::virtual_call_data_tag) \ + declare_constant(DataLayout::ret_data_tag) \ + declare_constant(DataLayout::branch_data_tag) \ + declare_constant(DataLayout::multi_branch_data_tag) \ + declare_constant(DataLayout::arg_info_data_tag) \ + declare_constant(DataLayout::call_type_data_tag) \ + declare_constant(DataLayout::virtual_call_type_data_tag) \ + declare_constant(DataLayout::parameters_type_data_tag) \ + declare_constant(DataLayout::speculative_trap_data_tag) \ \ /*************************************/ \ /* InstanceKlass enum */ \ @@ -2454,13 +2589,14 @@ \ declare_constant(Symbol::max_symbol_length) \ \ - /*************************************************/ \ - /* ConstantPool* layout enum for InvokeDynamic */ \ - /*************************************************/ \ + /***********************************************/ \ + /* ConstantPool* layout enum for InvokeDynamic */ \ + /***********************************************/ \ \ - declare_constant(ConstantPool::_indy_bsm_offset) \ - declare_constant(ConstantPool::_indy_argc_offset) \ - declare_constant(ConstantPool::_indy_argv_offset) \ + declare_constant(ConstantPool::_indy_bsm_offset) \ + declare_constant(ConstantPool::_indy_argc_offset) \ + declare_constant(ConstantPool::_indy_argv_offset) \ + declare_constant(ConstantPool::CPCACHE_INDEX_TAG) \ \ /********************************/ \ /* ConstantPoolCacheEntry enums */ \ @@ -2555,6 +2691,18 @@ \ declare_constant(DEFAULT_CACHE_LINE_SIZE) \ \ + declare_constant(Deoptimization::Unpack_deopt) \ + declare_constant(Deoptimization::Unpack_exception) \ + declare_constant(Deoptimization::Unpack_uncommon_trap) \ + declare_constant(Deoptimization::Unpack_reexecute) \ + \ + declare_constant(Deoptimization::_action_bits) \ + declare_constant(Deoptimization::_reason_bits) \ + declare_constant(Deoptimization::_debug_id_bits) \ + declare_constant(Deoptimization::_action_shift) \ + declare_constant(Deoptimization::_reason_shift) \ + declare_constant(Deoptimization::_debug_id_shift) \ + \ /*********************/ \ /* Matcher (C2 only) */ \ /*********************/ \ @@ -2567,6 +2715,18 @@ \ declare_constant(InvocationEntryBci) \ \ + /*************/ \ + /* CompLevel */ \ + /*************/ \ + \ + declare_constant(CompLevel_any) \ + declare_constant(CompLevel_all) \ + declare_constant(CompLevel_none) \ + declare_constant(CompLevel_simple) \ + declare_constant(CompLevel_limited_profile) \ + declare_constant(CompLevel_full_profile) \ + declare_constant(CompLevel_full_optimization) \ + \ /***************/ \ /* OopMapValue */ \ /***************/ \ @@ -2581,7 +2741,6 @@ declare_constant(OopMapValue::register_mask_in_place) \ declare_constant(OopMapValue::unused_value) \ declare_constant(OopMapValue::oop_value) \ - declare_constant(OopMapValue::value_value) \ declare_constant(OopMapValue::narrowoop_value) \ declare_constant(OopMapValue::callee_saved_value) \ declare_constant(OopMapValue::derived_oop_value) \ @@ -2698,8 +2857,38 @@ /* Constants in markOop used by CMS. */ \ declare_constant(markOopDesc::cms_shift) \ declare_constant(markOopDesc::cms_mask) \ - declare_constant(markOopDesc::size_shift) + declare_constant(markOopDesc::size_shift) \ + \ + /* InvocationCounter constants */ \ + declare_constant(InvocationCounter::count_increment) \ + declare_constant(InvocationCounter::count_shift) + + +//-------------------------------------------------------------------------------- +// VM_ADDRESSES +// +#define VM_ADDRESSES(declare_address, declare_preprocessor_address, declare_function) \ + \ + declare_function(SharedRuntime::register_finalizer) \ + declare_function(SharedRuntime::exception_handler_for_return_address) \ + declare_function(SharedRuntime::OSR_migration_end) \ + declare_function(SharedRuntime::dsin) \ + declare_function(SharedRuntime::dcos) \ + declare_function(SharedRuntime::dtan) \ + declare_function(SharedRuntime::dexp) \ + declare_function(SharedRuntime::dlog) \ + declare_function(SharedRuntime::dlog10) \ + declare_function(SharedRuntime::dpow) \ + \ + declare_function(os::dll_load) \ + declare_function(os::dll_lookup) \ + declare_function(os::javaTimeMillis) \ + declare_function(os::javaTimeNanos) \ + \ + declare_function(Deoptimization::fetch_unroll_info) \ + COMPILER2_PRESENT(declare_function(Deoptimization::uncommon_trap)) \ + declare_function(Deoptimization::unpack_frames) //-------------------------------------------------------------------------------- // Macros operating on the above lists @@ -2932,6 +3121,23 @@ # define GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) #endif /* COMPILER1 */ +//-------------------------------------------------------------------------------- +// VMAddressEntry macros +// + +#define GENERATE_VM_ADDRESS_ENTRY(name) \ + { QUOTE(name), (void*) (name) }, + +#define GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY(name, value) \ + { name, (void*) (value) }, + +#define GENERATE_VM_FUNCTION_ENTRY(name) \ + { QUOTE(name), CAST_FROM_FN_PTR(void*, &(name)) }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_ADDRESS_LAST_ENTRY() \ + { NULL, NULL } + // // Instantiation of VMStructEntries, VMTypeEntries and VMIntConstantEntries // @@ -2950,6 +3156,11 @@ GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) +#if INCLUDE_JVMCI + VM_STRUCTS_JVMCI(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY) +#endif + #if INCLUDE_ALL_GCS VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) @@ -2970,6 +3181,15 @@ VM_STRUCTS_EXT(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) + VM_STRUCTS_OS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, @@ -3002,6 +3222,11 @@ GENERATE_C2_VM_TYPE_ENTRY, GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) +#if INCLUDE_JVMCI + VM_TYPES_JVMCI(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY) +#endif + #if INCLUDE_ALL_GCS VM_TYPES_PARALLELGC(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) @@ -3023,6 +3248,15 @@ VM_TYPES_EXT(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) + VM_TYPES_OS(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_OOP_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY, + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, + GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_C2_VM_TYPE_ENTRY, + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY, GENERATE_OOP_VM_TYPE_ENTRY, @@ -3052,6 +3286,12 @@ GENERATE_C2_VM_INT_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) +#if INCLUDE_JVMCI + VM_INT_CONSTANTS_JVMCI(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + +#endif + #if INCLUDE_ALL_GCS VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) @@ -3062,6 +3302,12 @@ VM_INT_CONSTANTS_TRACE(GENERATE_VM_INT_CONSTANT_ENTRY) #endif + VM_INT_CONSTANTS_OS(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, + GENERATE_C1_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, GENERATE_C1_VM_INT_CONSTANT_ENTRY, @@ -3085,6 +3331,12 @@ GENERATE_C2_VM_LONG_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + VM_LONG_CONSTANTS_OS(GENERATE_VM_LONG_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, + GENERATE_C1_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + VM_LONG_CONSTANTS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, GENERATE_C1_VM_LONG_CONSTANT_ENTRY, @@ -3100,6 +3352,25 @@ GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() }; +VMAddressEntry VMStructs::localHotSpotVMAddresses[] = { + + VM_ADDRESSES(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + + VM_ADDRESSES_OS(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + +#if INCLUDE_JVMCI + VM_ADDRESSES_JVMCI(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) +#endif + + GENERATE_VM_ADDRESS_LAST_ENTRY() +}; + // This is used both to check the types of referenced fields and, in // debug builds, to ensure that all of the field types are present. void @@ -3308,6 +3579,11 @@ ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMLongConstantEntryNameOffset, VMLongConstantEntry, name); ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMLongConstantEntryValueOffset, VMLongConstantEntry, value); ASSIGN_STRIDE_TO_64BIT_VAR(gHotSpotVMLongConstantEntryArrayStride, gHotSpotVMLongConstants); + +JNIEXPORT VMAddressEntry* gHotSpotVMAddresses = VMStructs::localHotSpotVMAddresses; +ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMAddressEntryNameOffset, VMAddressEntry, name); +ASSIGN_OFFSET_TO_64BIT_VAR(gHotSpotVMAddressEntryValueOffset, VMAddressEntry, value); +ASSIGN_STRIDE_TO_64BIT_VAR(gHotSpotVMAddressEntryArrayStride, gHotSpotVMAddresses); } #ifdef ASSERT @@ -3415,6 +3691,11 @@ &long_last_entry, sizeof(VMLongConstantEntry)) == 0, "Incorrect last entry in localHotSpotVMLongConstants"); + static VMAddressEntry address_last_entry = GENERATE_VM_ADDRESS_LAST_ENTRY(); + assert(memcmp(&localHotSpotVMAddresses[sizeof(localHotSpotVMAddresses) / sizeof(VMAddressEntry) - 1], + &address_last_entry, + sizeof(VMAddressEntry)) == 0, "Incorrect last entry in localHotSpotVMAddresses"); + // Check for duplicate entries in type array for (int i = 0; localHotSpotVMTypes[i].typeName != NULL; i++) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/vmStructs.hpp --- a/hotspot/src/share/vm/runtime/vmStructs.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vmStructs.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -95,6 +95,11 @@ uint64_t value; // Value of constant } VMLongConstantEntry; +typedef struct { + const char* name; // Name of address (example: "SharedRuntime::register_finalizer") + void* value; // Value of address +} VMAddressEntry; + // This class is a friend of most classes, to be able to access // private fields class VMStructs { @@ -117,6 +122,11 @@ // the fact that it has a NULL typeName static VMLongConstantEntry localHotSpotVMLongConstants[]; + /** + * Table of addresses. + */ + static VMAddressEntry localHotSpotVMAddresses[]; + // This is used to run any checking code necessary for validation of // the data structure (debug build only) static void init(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/vmThread.cpp --- a/hotspot/src/share/vm/runtime/vmThread.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vmThread.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -41,8 +41,6 @@ #include "utilities/events.hpp" #include "utilities/xmlstream.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Dummy VM operation to act as first element in our circular double-linked list class VM_Dummy: public VM_Operation { VMOp_Type type() const { return VMOp_Dummy; } @@ -410,7 +408,7 @@ !_cur_vm_operation->evaluate_concurrently()) { long stall = os::javaTimeMillis() - _cur_vm_operation->timestamp(); if (stall > 0) - tty->print_cr("%s stall: %Ld", _cur_vm_operation->name(), stall); + tty->print_cr("%s stall: %ld", _cur_vm_operation->name(), stall); } while (!should_terminate() && _cur_vm_operation == NULL) { @@ -630,8 +628,8 @@ // Check the VM operation allows nested VM operation. This normally not the case, e.g., the compiler // does not allow nested scavenges or compiles. if (!prev_vm_operation->allow_nested_vm_operations()) { - fatal(err_msg("Nested VM operation %s requested by operation %s", - op->name(), vm_operation()->name())); + fatal("Nested VM operation %s requested by operation %s", + op->name(), vm_operation()->name()); } op->set_calling_thread(prev_vm_operation->calling_thread(), prev_vm_operation->priority()); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/vm_operations.cpp --- a/hotspot/src/share/vm/runtime/vm_operations.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -42,8 +42,6 @@ #include "services/threadService.hpp" #include "trace/tracing.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - #define VM_OP_NAME_INITIALIZE(name) #name, const char* VM_Operation::_names[VM_Operation::VMOp_Terminating] = \ @@ -79,14 +77,14 @@ } // Called by fatal error handler. void VM_Operation::print_on_error(outputStream* st) const { - st->print("VM_Operation (" PTR_FORMAT "): ", this); + st->print("VM_Operation (" PTR_FORMAT "): ", p2i(this)); st->print("%s", name()); const char* mode = mode_to_string(evaluation_mode()); st->print(", mode: %s", mode); if (calling_thread()) { - st->print(", requested by thread " PTR_FORMAT, calling_thread()); + st->print(", requested by thread " PTR_FORMAT, p2i(calling_thread())); } } @@ -117,14 +115,16 @@ NMethodSweeper::mark_active_nmethods(); } -VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id) { +VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason) { _thread = thread; _id = id; + _reason = reason; } void VM_DeoptimizeFrame::doit() { - Deoptimization::deoptimize_frame_internal(_thread, _id); + assert(_reason > Deoptimization::Reason_none && _reason < Deoptimization::Reason_LIMIT, "invalid deopt reason"); + Deoptimization::deoptimize_frame_internal(_thread, _id, (Deoptimization::DeoptReason)_reason); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/vm_operations.hpp --- a/hotspot/src/share/vm/runtime/vm_operations.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -272,7 +272,8 @@ private: JavaThread* _thread; intptr_t* _id; - VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id); + int _reason; + VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason); public: VMOp_Type type() const { return VMOp_DeoptimizeFrame; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/runtime/vm_version.cpp --- a/hotspot/src/share/vm/runtime/vm_version.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/runtime/vm_version.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -85,7 +85,7 @@ #ifdef ASSERT static void assert_digits(const char * s, const char * message) { for (int i = 0; s[i] != '\0'; i++) { - assert(isdigit(s[i]), message); + assert(isdigit(s[i]), "%s", message); } } #endif @@ -154,7 +154,6 @@ #endif } - const char* Abstract_VM_Version::vm_info_string() { if (CodeCacheExtensions::use_pregenerated_interpreter()) { return "interpreted mode, pregenerated"; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/classLoadingService.cpp --- a/hotspot/src/share/vm/services/classLoadingService.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/services/classLoadingService.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -182,7 +182,7 @@ // verbose will be set to the previous value Flag::Error error = CommandLineFlags::boolAtPut("TraceClassLoading", &verbose, Flag::MANAGEMENT); - assert(error==Flag::SUCCESS, err_msg("Setting TraceClassLoading flag failed with error %s", Flag::flag_error_str(error))); + assert(error==Flag::SUCCESS, "Setting TraceClassLoading flag failed with error %s", Flag::flag_error_str(error)); reset_trace_class_unloading(); return verbose; @@ -193,7 +193,7 @@ assert(Management_lock->owned_by_self(), "Must own the Management_lock"); bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose(); Flag::Error error = CommandLineFlags::boolAtPut("TraceClassUnloading", &value, Flag::MANAGEMENT); - assert(error==Flag::SUCCESS, err_msg("Setting TraceClassUnLoading flag failed with error %s", Flag::flag_error_str(error))); + assert(error==Flag::SUCCESS, "Setting TraceClassUnLoading flag failed with error %s", Flag::flag_error_str(error)); } GrowableArray* LoadedClassesEnumerator::_loaded_classes = NULL; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/diagnosticCommand.cpp --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -39,8 +39,6 @@ #include "utilities/macros.hpp" #include "oops/objArrayOop.inline.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - void DCmdRegistrant::register_dcmds(){ // Registration of the diagnostic commands // First argument specifies which interfaces will export the command @@ -695,12 +693,17 @@ // command line with -D or by managmenent.properties // file. #define PUT_OPTION(a) \ - if ( (a).is_set() ){ \ - options.print(\ - ( *((a).type()) == 'I' ) ? "%scom.sun.management.%s=%d" : "%scom.sun.management.%s=%s",\ - comma, (a).name(), (a).value()); \ - comma[0] = ','; \ - } + do { \ + if ( (a).is_set() ){ \ + if ( *((a).type()) == 'I' ) { \ + options.print("%scom.sun.management.%s=" JLONG_FORMAT, comma, (a).name(), (jlong)((a).value())); \ + } else { \ + options.print("%scom.sun.management.%s=%s", comma, (a).name(), (char*)((a).value())); \ + } \ + comma[0] = ','; \ + }\ + } while(0); + PUT_OPTION(_config_file); PUT_OPTION(_jmxremote_port); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/heapDumper.cpp --- a/hotspot/src/share/vm/services/heapDumper.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/services/heapDumper.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -724,7 +724,7 @@ // reflection and sun.misc.Unsafe classes may have a reference to a // Klass* so filter it out. - assert(o->is_oop_or_null(), err_msg("Expected an oop or NULL at " PTR_FORMAT, p2i(o))); + assert(o->is_oop_or_null(), "Expected an oop or NULL at " PTR_FORMAT, p2i(o)); writer->write_objectID(o); break; } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/management.cpp --- a/hotspot/src/share/vm/services/management.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/services/management.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -58,8 +58,6 @@ #include "services/threadService.hpp" #include "utilities/macros.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - PerfVariable* Management::_begin_vm_creation_time = NULL; PerfVariable* Management::_end_vm_creation_time = NULL; PerfVariable* Management::_vm_init_done_time = NULL; @@ -752,7 +750,7 @@ if ((size_t)threshold > max_uintx) { stringStream st; - st.print("Invalid valid threshold value. Threshold value (" UINT64_FORMAT ") > max value of size_t (" SIZE_FORMAT ")", (size_t)threshold, max_uintx); + st.print("Invalid valid threshold value. Threshold value (" JLONG_FORMAT ") > max value of size_t (" UINTX_FORMAT ")", threshold, max_uintx); THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), st.as_string(), -1); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/management.hpp --- a/hotspot/src/share/vm/services/management.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/services/management.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -118,6 +118,10 @@ void start() { _timer.update_to(0); _begin_time = os::javaTimeMillis(); } + jlong begin_time() const { + return _begin_time; + } + /** * Only call this if initialization completes successfully; it will * crash if PerfMemory_exit() has already been called (usually by diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/memoryService.cpp --- a/hotspot/src/share/vm/services/memoryService.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/services/memoryService.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -518,7 +518,7 @@ MutexLocker m(Management_lock); // verbose will be set to the previous value Flag::Error error = CommandLineFlags::boolAtPut("PrintGC", &verbose, Flag::MANAGEMENT); - assert(error==Flag::SUCCESS, err_msg("Setting PrintGC flag failed with error %s", Flag::flag_error_str(error))); + assert(error==Flag::SUCCESS, "Setting PrintGC flag failed with error %s", Flag::flag_error_str(error)); ClassLoadingService::reset_trace_class_unloading(); return verbose; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/nmtCommon.cpp --- a/hotspot/src/share/vm/services/nmtCommon.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/services/nmtCommon.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -40,6 +40,7 @@ "Arena Chunk", "Test", "Tracing", + "Logging", "Unknown" }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/threadService.cpp --- a/hotspot/src/share/vm/services/threadService.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/services/threadService.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -39,8 +39,6 @@ #include "runtime/vm_operations.hpp" #include "services/threadService.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // TODO: we need to define a naming convention for perf counters // to distinguish counters for: // - standard JSR174 use @@ -508,7 +506,7 @@ for (int i = 0; i < len; i++) { oop o = _locked_monitors->at(i); InstanceKlass* ik = InstanceKlass::cast(o->klass()); - st->print_cr("\t- locked <" INTPTR_FORMAT "> (a %s)", (address)o, ik->external_name()); + st->print_cr("\t- locked <" INTPTR_FORMAT "> (a %s)", p2i(o), ik->external_name()); } } @@ -732,7 +730,7 @@ for (int i = 0; i < locks->length(); i++) { instanceOop obj = locks->at(i); InstanceKlass* ik = InstanceKlass::cast(obj->klass()); - st->print_cr("\t- <" INTPTR_FORMAT "> (a %s)", (address)obj, ik->external_name()); + st->print_cr("\t- <" INTPTR_FORMAT "> (a %s)", p2i(obj), ik->external_name()); } st->cr(); } @@ -885,10 +883,10 @@ st->print_cr("\"%s\":", currentThread->get_thread_name()); const char* owner_desc = ",\n which is held by"; if (waitingToLockMonitor != NULL) { - st->print(" waiting to lock monitor " INTPTR_FORMAT, waitingToLockMonitor); + st->print(" waiting to lock monitor " INTPTR_FORMAT, p2i(waitingToLockMonitor)); oop obj = (oop)waitingToLockMonitor->object(); if (obj != NULL) { - st->print(" (object " INTPTR_FORMAT ", a %s)", (address)obj, + st->print(" (object " INTPTR_FORMAT ", a %s)", p2i(obj), (InstanceKlass::cast(obj->klass()))->external_name()); if (!currentThread->current_pending_monitor_is_from_java()) { @@ -907,12 +905,12 @@ // if it is not findable, then the previous currentThread is // blocked permanently. st->print("%s UNKNOWN_owner_addr=" PTR_FORMAT, owner_desc, - (address)waitingToLockMonitor->owner()); + p2i(waitingToLockMonitor->owner())); continue; } } else { st->print(" waiting for ownable synchronizer " INTPTR_FORMAT ", (a %s)", - (address)waitingToLockBlocker, + p2i(waitingToLockBlocker), (InstanceKlass::cast(waitingToLockBlocker->klass()))->external_name()); assert(waitingToLockBlocker->is_a(SystemDictionary::abstract_ownable_synchronizer_klass()), "Must be an AbstractOwnableSynchronizer"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/virtualMemoryTracker.cpp diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/services/writeableFlags.cpp --- a/hotspot/src/share/vm/services/writeableFlags.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/services/writeableFlags.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -89,10 +89,7 @@ break; } - PRAGMA_DIAG_PUSH - PRAGMA_FORMAT_NONLITERAL_IGNORED_INTERNAL - err_msg.print(buffer); - PRAGMA_DIAG_POP + err_msg.print("%s", buffer); } // set a boolean global flag @@ -295,7 +292,8 @@ } // a writeable flag setter accepting 'jvalue' values -Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) { +Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, + FormatBuffer<80>& err_msg) { jvalue new_value = *(jvalue*)value; if (f->is_bool()) { bool bvalue = (new_value.z == JNI_TRUE ? true : false); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/shark/sharkCacheDecache.cpp --- a/hotspot/src/share/vm/shark/sharkCacheDecache.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/shark/sharkCacheDecache.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -150,8 +150,10 @@ void SharkDecacher::end_frame() { // Record the scope + methodHandle null_mh; debug_info()->describe_scope( pc_offset(), + null_mh, target(), bci(), true, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/array.hpp --- a/hotspot/src/share/vm/utilities/array.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/array.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -341,13 +341,13 @@ assert(is_size_aligned(left, sizeof(T)), "Must be"); size_t elements = left / sizeof(T); - assert(elements <= (size_t)INT_MAX, err_msg("number of elements " SIZE_FORMAT "doesn't fit into an int.", elements)); + assert(elements <= (size_t)INT_MAX, "number of elements " SIZE_FORMAT "doesn't fit into an int.", elements); int length = (int)elements; assert((size_t)size(length) * BytesPerWord == bytes, - err_msg("Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, - bytes, (size_t)size(length) * BytesPerWord)); + "Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, + bytes, (size_t)size(length) * BytesPerWord); return length; } @@ -380,9 +380,9 @@ // sort the array. bool contains(const T& x) const { return index_of(x) >= 0; } - T at(int i) const { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); return _data[i]; } - void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); _data[i] = x; } - T* adr_at(const int i) { assert(i >= 0 && i< _length, err_msg("oob: 0 <= %d < %d", i, _length)); return &_data[i]; } + T at(int i) const { assert(i >= 0 && i< _length, "oob: 0 <= %d < %d", i, _length); return _data[i]; } + void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, "oob: 0 <= %d < %d", i, _length); _data[i] = x; } + T* adr_at(const int i) { assert(i >= 0 && i< _length, "oob: 0 <= %d < %d", i, _length); return &_data[i]; } int find(const T& x) { return index_of(x); } T at_acquire(const int which) { return OrderAccess::load_acquire(adr_at(which)); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/chunkedList.hpp --- a/hotspot/src/share/vm/utilities/chunkedList.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/chunkedList.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -73,7 +73,7 @@ } T at(size_t i) { - assert(i < size(), err_msg("IOOBE i: " SIZE_FORMAT " size(): " SIZE_FORMAT, i, size())); + assert(i < size(), "IOOBE i: " SIZE_FORMAT " size(): " SIZE_FORMAT, i, size()); return _values[i]; } }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/debug.cpp --- a/hotspot/src/share/vm/utilities/debug.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/debug.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -78,13 +78,11 @@ # endif #endif // PRODUCT -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - FormatBufferResource::FormatBufferResource(const char * format, ...) - : FormatBufferBase((char*)resource_allocate_bytes(RES_BUFSZ)) { + : FormatBufferBase((char*)resource_allocate_bytes(FormatBufferBase::BufferSize)) { va_list argp; va_start(argp, format); - jio_vsnprintf(_buf, RES_BUFSZ, format, argp); + jio_vsnprintf(_buf, FormatBufferBase::BufferSize, format, argp); va_end(argp); } @@ -207,26 +205,36 @@ #endif // !PRODUCT -void report_vm_error(const char* file, int line, const char* error_msg, - const char* detail_msg) +void report_vm_error(const char* file, int line, const char* error_msg) +{ + report_vm_error(file, line, error_msg, "%s", ""); +} + +void report_vm_error(const char* file, int line, const char* error_msg, const char* detail_fmt, ...) { if (Debugging || error_is_suppressed(file, line)) return; - Thread* const thread = ThreadLocalStorage::get_thread_slow(); - VMError err(thread, file, line, error_msg, detail_msg); - err.report_and_die(); + va_list detail_args; + va_start(detail_args, detail_fmt); + VMError::report_and_die(ThreadLocalStorage::get_thread_slow(), file, line, error_msg, detail_fmt, detail_args); + va_end(detail_args); } -void report_fatal(const char* file, int line, const char* message) +void report_fatal(const char* file, int line, const char* detail_fmt, ...) { - report_vm_error(file, line, "fatal error", message); + if (Debugging || error_is_suppressed(file, line)) return; + va_list detail_args; + va_start(detail_args, detail_fmt); + VMError::report_and_die(ThreadLocalStorage::get_thread_slow(), file, line, "fatal error", detail_fmt, detail_args); + va_end(detail_args); } void report_vm_out_of_memory(const char* file, int line, size_t size, - VMErrorType vm_err_type, const char* message) { + VMErrorType vm_err_type, const char* detail_fmt, ...) { if (Debugging) return; - - Thread* thread = ThreadLocalStorage::get_thread_slow(); - VMError(thread, file, line, size, vm_err_type, message).report_and_die(); + va_list detail_args; + va_start(detail_args, detail_fmt); + VMError::report_and_die(ThreadLocalStorage::get_thread_slow(), file, line, size, vm_err_type, detail_fmt, detail_args); + va_end(detail_args); // The UseOSErrorReporting option in report_and_die() may allow a return // to here. If so then we'll have to figure out how to handle it. @@ -295,8 +303,7 @@ } if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { - VMError err(message); - err.report_java_out_of_memory(); + VMError::report_java_out_of_memory(message); } } } @@ -365,22 +372,22 @@ char * const dataPtr = NULL; // bad data pointer const void (*funcPtr)(void) = (const void(*)()) 0xF; // bad function pointer - // Keep this in sync with test/runtime/6888954/vmerrors.sh. + // Keep this in sync with test/runtime/ErrorHandling/ErrorHandler.java switch (how) { case 1: vmassert(str == NULL, "expected null"); case 2: vmassert(num == 1023 && *str == 'X', - err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); + "num=" SIZE_FORMAT " str=\"%s\"", num, str); case 3: guarantee(str == NULL, "expected null"); case 4: guarantee(num == 1023 && *str == 'X', - err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); + "num=" SIZE_FORMAT " str=\"%s\"", num, str); case 5: fatal("expected null"); - case 6: fatal(err_msg("num=" SIZE_FORMAT " str=\"%s\"", num, str)); - case 7: fatal(err_msg("%s%s# %s%s# %s%s# %s%s# %s%s# " - "%s%s# %s%s# %s%s# %s%s# %s%s# " - "%s%s# %s%s# %s%s# %s%s# %s", - msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, - msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, - msg, eol, msg, eol, msg, eol, msg, eol, msg)); + case 6: fatal("num=" SIZE_FORMAT " str=\"%s\"", num, str); + case 7: fatal("%s%s# %s%s# %s%s# %s%s# %s%s# " + "%s%s# %s%s# %s%s# %s%s# %s%s# " + "%s%s# %s%s# %s%s# %s%s# %s", + msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, + msg, eol, msg, eol, msg, eol, msg, eol, msg, eol, + msg, eol, msg, eol, msg, eol, msg, eol, msg); case 8: vm_exit_out_of_memory(num, OOM_MALLOC_ERROR, "ChunkPool::allocate"); case 9: ShouldNotCallThis(); case 10: ShouldNotReachHere(); @@ -515,7 +522,7 @@ oop obj = oop(p); obj->print(); } else { - tty->print(PTR_FORMAT, p); + tty->print(PTR_FORMAT, p2i(p)); } } @@ -550,7 +557,7 @@ frame f = os::current_frame(); RegisterMap reg_map(p); f = f.sender(®_map); - tty->print("(guessing starting frame id=%#p based on current fp)\n", f.id()); + tty->print("(guessing starting frame id=" PTR_FORMAT " based on current fp)\n", p2i(f.id())); p->trace_stack_from(vframe::new_vframe(&f, ®_map, p)); pd_ps(f); #endif // PRODUCT diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/debug.hpp --- a/hotspot/src/share/vm/utilities/debug.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/debug.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -36,21 +36,21 @@ char* _buf; inline FormatBufferBase(char* buf) : _buf(buf) {} public: + static const int BufferSize = 256; operator const char *() const { return _buf; } }; // Use resource area for buffer -#define RES_BUFSZ 256 class FormatBufferResource : public FormatBufferBase { public: FormatBufferResource(const char * format, ...) ATTRIBUTE_PRINTF(2, 3); }; // Use stack for buffer -template +template class FormatBuffer : public FormatBufferBase { public: - inline FormatBuffer(const char * format, ...) ATTRIBUTE_PRINTF(2, 3); + inline FormatBuffer(const char* format, ...) ATTRIBUTE_PRINTF(2, 3); inline void append(const char* format, ...) ATTRIBUTE_PRINTF(2, 3); inline void print(const char* format, ...) ATTRIBUTE_PRINTF(2, 3); inline void printv(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0); @@ -105,27 +105,29 @@ va_end(argp); } -// Used to format messages for vmassert(), guarantee(), fatal(), etc. +// Used to format messages. typedef FormatBuffer<> err_msg; -typedef FormatBufferResource err_msg_res; // assertions #ifndef ASSERT -#define vmassert(p, msg) +#define vmassert(p, ...) #else // Note: message says "assert" rather than "vmassert" for backward // compatibility with tools that parse/match the message text. -#define vmassert(p, msg) \ -do { \ - if (!(p)) { \ - report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg); \ - BREAKPOINT; \ - } \ +// Note: The signature is vmassert(p, format, ...), but the solaris +// compiler can't handle an empty ellipsis in a macro without a warning. +#define vmassert(p, ...) \ +do { \ + if (!(p)) { \ + report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", __VA_ARGS__); \ + BREAKPOINT; \ + } \ } while (0) + #endif // For backward compatibility. -#define assert(p, msg) vmassert(p, msg) +#define assert(p, ...) vmassert(p, __VA_ARGS__) // This version of vmassert is for use with checking return status from // library calls that return actual error values eg. EINVAL, @@ -135,7 +137,7 @@ // an extra arg and use strerror to convert it to a meaningful string // like "Invalid argument", "out of memory" etc #define vmassert_status(p, status, msg) \ - vmassert(p, err_msg("error %s(%d), %s", strerror(status), status, msg)) + vmassert(p, "error %s(%d), %s", strerror(status), status, msg) // For backward compatibility. #define assert_status(p, status, msg) vmassert_status(p, status, msg) @@ -143,49 +145,49 @@ // guarantee is like vmassert except it's always executed -- use it for // cheap tests that catch errors that would otherwise be hard to find. // guarantee is also used for Verify options. -#define guarantee(p, msg) \ -do { \ - if (!(p)) { \ - report_vm_error(__FILE__, __LINE__, "guarantee(" #p ") failed", msg); \ - BREAKPOINT; \ - } \ +#define guarantee(p, ...) \ +do { \ + if (!(p)) { \ + report_vm_error(__FILE__, __LINE__, "guarantee(" #p ") failed", __VA_ARGS__); \ + BREAKPOINT; \ + } \ } while (0) -#define fatal(msg) \ -do { \ - report_fatal(__FILE__, __LINE__, msg); \ - BREAKPOINT; \ +#define fatal(...) \ +do { \ + report_fatal(__FILE__, __LINE__, __VA_ARGS__); \ + BREAKPOINT; \ } while (0) // out of memory -#define vm_exit_out_of_memory(size, vm_err_type, msg) \ -do { \ - report_vm_out_of_memory(__FILE__, __LINE__, size, vm_err_type, msg); \ - BREAKPOINT; \ +#define vm_exit_out_of_memory(size, vm_err_type, ...) \ +do { \ + report_vm_out_of_memory(__FILE__, __LINE__, size, vm_err_type, __VA_ARGS__); \ + BREAKPOINT; \ } while (0) -#define ShouldNotCallThis() \ -do { \ - report_should_not_call(__FILE__, __LINE__); \ - BREAKPOINT; \ +#define ShouldNotCallThis() \ +do { \ + report_should_not_call(__FILE__, __LINE__); \ + BREAKPOINT; \ } while (0) -#define ShouldNotReachHere() \ -do { \ - report_should_not_reach_here(__FILE__, __LINE__); \ - BREAKPOINT; \ +#define ShouldNotReachHere() \ +do { \ + report_should_not_reach_here(__FILE__, __LINE__); \ + BREAKPOINT; \ } while (0) -#define Unimplemented() \ -do { \ - report_unimplemented(__FILE__, __LINE__); \ - BREAKPOINT; \ +#define Unimplemented() \ +do { \ + report_unimplemented(__FILE__, __LINE__); \ + BREAKPOINT; \ } while (0) -#define Untested(msg) \ -do { \ - report_untested(__FILE__, __LINE__, msg); \ - BREAKPOINT; \ +#define Untested(msg) \ +do { \ + report_untested(__FILE__, __LINE__, msg); \ + BREAKPOINT; \ } while (0); @@ -197,11 +199,19 @@ }; // error reporting helper functions +void report_vm_error(const char* file, int line, const char* error_msg); +#if !defined(__GNUC__) || defined (__clang_major__) || (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || __GNUC__ > 4) +// ATTRIBUTE_PRINTF works with gcc >= 4.8 and any other compiler. void report_vm_error(const char* file, int line, const char* error_msg, - const char* detail_msg = NULL); -void report_fatal(const char* file, int line, const char* message); -void report_vm_out_of_memory(const char* file, int line, size_t size, - VMErrorType vm_err_type, const char* message); + const char* detail_fmt, ...) ATTRIBUTE_PRINTF(4, 5); +#else +// GCC < 4.8 warns because of empty format string. Warning can not be switched off selectively. +void report_vm_error(const char* file, int line, const char* error_msg, + const char* detail_fmt, ...); +#endif +void report_fatal(const char* file, int line, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(3, 4); +void report_vm_out_of_memory(const char* file, int line, size_t size, VMErrorType vm_err_type, + const char* detail_fmt, ...) ATTRIBUTE_PRINTF(5, 6); void report_should_not_call(const char* file, int line); void report_should_not_reach_here(const char* file, int line); void report_unimplemented(const char* file, int line); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/exceptions.cpp --- a/hotspot/src/share/vm/utilities/exceptions.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/exceptions.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -35,8 +35,6 @@ #include "utilities/events.hpp" #include "utilities/exceptions.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // Implementation of ThreadShadow void check_ThreadShadow() { const ByteSize offset1 = byte_offset_of(ThreadShadow, _pending_exception); @@ -85,7 +83,7 @@ #endif // ASSERT if (thread->is_VM_thread() - || thread->is_Compiler_thread() + || !thread->can_call_java() || DumpSharedSpaces ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object @@ -112,7 +110,7 @@ } if (thread->is_VM_thread() - || thread->is_Compiler_thread() + || !thread->can_call_java() || DumpSharedSpaces ) { // We do not care what kind of exception we get for the vm-thread or a thread which // is compiling. We just install a dummy exception object @@ -144,7 +142,7 @@ "thrown [%s, line %d]\nfor thread " INTPTR_FORMAT, h_exception->print_value_string(), message ? ": " : "", message ? message : "", - (address)h_exception(), file, line, thread); + p2i(h_exception()), file, line, p2i(thread)); } // for AbortVMOnException flag NOT_PRODUCT(Exceptions::debug_check_abort(h_exception, message)); @@ -167,7 +165,7 @@ if (LogEvents){ Events::log_exception(thread, "Exception <%s%s%s> (" INTPTR_FORMAT ") thrown at [%s, line %d]", h_exception->print_value_string(), message ? ": " : "", message ? message : "", - (address)h_exception(), file, line); + p2i(h_exception()), file, line); } } @@ -486,7 +484,7 @@ strstr(value_string, AbortVMOnException)) { if (AbortVMOnExceptionMessage == NULL || message == NULL || strcmp(message, AbortVMOnExceptionMessage) == 0) { - fatal(err_msg("Saw %s, aborting", value_string)); + fatal("Saw %s, aborting", value_string); } } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/fakeRttiSupport.hpp --- a/hotspot/src/share/vm/utilities/fakeRttiSupport.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/fakeRttiSupport.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -50,6 +50,7 @@ // with. template class FakeRttiSupport VALUE_OBJ_CLASS_SPEC { + friend class VMStructs; public: // Construct with the indicated concrete tag, and include the // concrete tag in the associated tag set. @@ -76,8 +77,8 @@ FakeRttiSupport add_tag(TagType tag) const { uintx tbit = tag_bit(tag); assert((_tag_set & tbit) == 0, - err_msg("Tag " UINTX_FORMAT " is already present in tag set: " UINTX_FORMAT, - (uintx)tag, _tag_set)); + "Tag " UINTX_FORMAT " is already present in tag set: " UINTX_FORMAT, + (uintx)tag, _tag_set); return FakeRttiSupport(_concrete_tag, _tag_set | tbit); } @@ -90,9 +91,9 @@ } static TagType validate_tag(TagType tag) { - assert(0 <= tag, err_msg("Tag " INTX_FORMAT " is negative", (intx)tag)); + assert(0 <= tag, "Tag " INTX_FORMAT " is negative", (intx)tag); assert(tag < BitsPerWord, - err_msg("Tag " UINTX_FORMAT " is too large", (uintx)tag)); + "Tag " UINTX_FORMAT " is too large", (uintx)tag); return tag; } }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/globalDefinitions.cpp --- a/hotspot/src/share/vm/utilities/globalDefinitions.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -50,7 +50,7 @@ uint64_t OopEncodingHeapMax = 0; void basic_fatal(const char* msg) { - fatal(msg); + fatal("%s", msg); } // Something to help porters sleep at night diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/globalDefinitions.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -60,9 +60,6 @@ #ifndef PRAGMA_FORMAT_NONLITERAL_IGNORED_EXTERNAL #define PRAGMA_FORMAT_NONLITERAL_IGNORED_EXTERNAL #endif -#ifndef PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -#define PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC -#endif #ifndef ATTRIBUTE_PRINTF #define ATTRIBUTE_PRINTF(fmt, vargs) #endif @@ -903,20 +900,20 @@ 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 or Shark + CompLevel_full_optimization = 4, // C2, Shark or JVMCI -#if defined(COMPILER2) || defined(SHARK) - CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered +#if defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI + CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered or JVMCI and tiered #elif defined(COMPILER1) - CompLevel_highest_tier = CompLevel_simple, // pure C1 + CompLevel_highest_tier = CompLevel_simple, // pure C1 or JVMCI #else 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(COMPILER1) || INCLUDE_JVMCI + CompLevel_initial_compile = CompLevel_simple // pure C1 or JVMCI #elif defined(COMPILER2) || defined(SHARK) CompLevel_initial_compile = CompLevel_full_optimization // pure C2 #else @@ -1413,14 +1410,6 @@ #define UINTX_FORMAT_W(width) "%" #width PRIuPTR -// Enable zap-a-lot if in debug version. - -# ifdef ASSERT -# ifdef COMPILER2 -# define ENABLE_ZAP_DEAD_LOCALS -#endif /* COMPILER2 */ -# endif /* ASSERT */ - #define ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0])) // Dereference vptr diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -301,10 +301,6 @@ #define PRAGMA_FORMAT_NONLITERAL_IGNORED_INTERNAL #endif -#ifndef __clang_major__ -#define PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC _Pragma("GCC diagnostic ignored \"-Wformat\"") _Pragma("GCC diagnostic error \"-Wformat-nonliteral\"") _Pragma("GCC diagnostic error \"-Wformat-security\"") -#endif - #if (__GNUC__ == 2) && (__GNUC_MINOR__ < 95) #define TEMPLATE_TABLE_BUG #endif diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp --- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -171,6 +171,12 @@ #define strdup _strdup #endif +// Visual Studio 2013 introduced strtoull(); before, one has to use _strtoui64() instead. +#if _MSC_VER < 1800 +#define strtoull _strtoui64 +#endif + + #pragma warning( disable : 4100 ) // unreferenced formal parameter #pragma warning( disable : 4127 ) // conditional expression is constant #pragma warning( disable : 4514 ) // unreferenced inline function has been removed diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/growableArray.hpp --- a/hotspot/src/share/vm/utilities/growableArray.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/growableArray.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -374,6 +374,40 @@ void sort(int f(E*,E*), int stride) { qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); } + + // Binary search and insertion utility. Search array for element + // matching key according to the static compare function. Insert + // that element is not already in the list. Assumes the list is + // already sorted according to compare function. + template E insert_sorted(E& key) { + bool found; + int location = find_sorted(key, found); + if (!found) { + insert_before(location, key); + } + return at(location); + } + + template int find_sorted(const K& key, bool& found) { + found = false; + int min = 0; + int max = length() - 1; + + while (max >= min) { + int mid = (max + min) / 2; + E value = at(mid); + int diff = compare(key, value); + if (diff > 0) { + min = mid + 1; + } else if (diff < 0) { + max = mid - 1; + } else { + found = true; + return mid; + } + } + return min; + } }; // Global GrowableArray methods (one instance in the library per each 'E' type). diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/macros.hpp --- a/hotspot/src/share/vm/utilities/macros.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/macros.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -173,6 +173,20 @@ #define INCLUDE_TRACE 1 #endif // INCLUDE_TRACE +#ifndef INCLUDE_JVMCI +#define INCLUDE_JVMCI 1 +#endif + +#if INCLUDE_JVMCI +#define JVMCI_ONLY(code) code +#define NOT_JVMCI(code) +#define NOT_JVMCI_RETURN /* next token must be ; */ +#else +#define JVMCI_ONLY(code) +#define NOT_JVMCI(code) code +#define NOT_JVMCI_RETURN {} +#endif // INCLUDE_JVMCI + // COMPILER1 variant #ifdef COMPILER1 #ifdef COMPILER2 @@ -195,7 +209,7 @@ #ifdef TIERED #define TIERED_ONLY(code) code #define NOT_TIERED(code) -#else +#else // TIERED #define TIERED_ONLY(code) #define NOT_TIERED(code) code #endif // TIERED diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/ostream.cpp --- a/hotspot/src/share/vm/utilities/ostream.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/ostream.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "compiler/compileLog.hpp" #include "gc/shared/gcId.hpp" +#include "gc/shared/gcId.hpp" #include "oops/oop.inline.hpp" #include "runtime/arguments.hpp" #include "runtime/os.hpp" @@ -238,11 +239,11 @@ return; } -void outputStream::gclog_stamp(const GCId& gc_id) { +void outputStream::gclog_stamp() { date_stamp(PrintGCDateStamps); stamp(PrintGCTimeStamps); if (PrintGCID) { - print("#%u: ", gc_id.id()); + print("#%u: ", GCId::current()); } } @@ -543,7 +544,7 @@ memset(longest_name, 'a', sizeof(longest_name)); longest_name[JVM_MAXPATHLEN - 1] = '\0'; o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); - assert(strcmp(longest_name, o_result) == 0, err_msg("longest name does not match. expected '%s' but got '%s'", longest_name, o_result)); + assert(strcmp(longest_name, o_result) == 0, "longest name does not match. expected '%s' but got '%s'", longest_name, o_result); FREE_C_HEAP_ARRAY(char, o_result); } @@ -554,7 +555,7 @@ memset(too_long_name, 'a', too_long_length); too_long_name[too_long_length - 1] = '\0'; o_result = make_log_name_internal((const char*)&too_long_name, NULL, pid, tms); - assert(o_result == NULL, err_msg("Too long file name should return NULL, but got '%s'", o_result)); + assert(o_result == NULL, "Too long file name should return NULL, but got '%s'", o_result); } { @@ -565,7 +566,7 @@ longest_name[JVM_MAXPATHLEN - 2] = 't'; longest_name[JVM_MAXPATHLEN - 1] = '\0'; o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); - assert(o_result == NULL, err_msg("Too long file name after timestamp expansion should return NULL, but got '%s'", o_result)); + assert(o_result == NULL, "Too long file name after timestamp expansion should return NULL, but got '%s'", o_result); } { @@ -576,7 +577,7 @@ longest_name[JVM_MAXPATHLEN - 2] = 'p'; longest_name[JVM_MAXPATHLEN - 1] = '\0'; o_result = make_log_name_internal((const char*)&longest_name, NULL, pid, tms); - assert(o_result == NULL, err_msg("Too long file name after pid expansion should return NULL, but got '%s'", o_result)); + assert(o_result == NULL, "Too long file name after pid expansion should return NULL, but got '%s'", o_result); } } #endif // PRODUCT @@ -1440,3 +1441,14 @@ } #endif + +void logStream::write(const char* s, size_t len) { + if (len > 0 && s[len - 1] == '\n') { + _current_line.write(s, len - 1); + _log_func(_current_line.as_string()); + _current_line.reset(); + } else { + _current_line.write(s, len); + update_position(s, len); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/ostream.hpp --- a/hotspot/src/share/vm/utilities/ostream.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/ostream.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -108,7 +108,7 @@ void date_stamp(bool guard) { date_stamp(guard, "", ": "); } - void gclog_stamp(const GCId& gc_id); + void gclog_stamp(); // portable printing of 64 bit integers void print_jlong(jlong value); @@ -235,6 +235,18 @@ void flush() {}; }; +class logStream : public outputStream { +private: + stringStream _current_line; + void (*_log_func)(const char* fmt, ...); +public: + void write(const char* s, size_t len); + logStream(void (*log_func)(const char* fmt, ...)) : _log_func(log_func) {} + ~logStream() { + guarantee(_current_line.size() == 0, "Buffer not flushed. Missing call to print_cr()?"); + } +}; + class gcLogFileStream : public fileStream { protected: const char* _file_name; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/top.hpp --- a/hotspot/src/share/vm/utilities/top.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/top.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -42,6 +42,9 @@ #ifdef COMPILER2 #include "opto/c2_globals.hpp" #endif +#if INCLUDE_JVMCI +#include "jvmci/jvmci_globals.hpp" +#endif // THIS FILE IS INTESIONALLY LEFT EMPTY // IT IS USED TO MINIMIZE THE NUMBER OF DEPENDENCIES IN includeDB diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/vmError.cpp --- a/hotspot/src/share/vm/utilities/vmError.cpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/vmError.cpp Thu Oct 22 11:13:08 2015 -0700 @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" #include "compiler/compileBroker.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/collectedHeap.hpp" #include "prims/whitebox.hpp" #include "runtime/arguments.hpp" @@ -45,8 +46,6 @@ #include "utilities/top.hpp" #include "utilities/vmError.hpp" -PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC - // List of environment variables that should be reported in error log file. const char *env_list[] = { // All platforms @@ -71,108 +70,6 @@ (const char *)0 }; -// Fatal error handler for internal errors and crashes. -// -// The default behavior of fatal error handler is to print a brief message -// to standard out (defaultStream::output_fd()), then save detailed information -// into an error report file (hs_err_pid.log) and abort VM. If multiple -// threads are having troubles at the same time, only one error is reported. -// The thread that is reporting error will abort VM when it is done, all other -// threads are blocked forever inside report_and_die(). - -// Constructor for crashes -VMError::VMError(Thread* thread, unsigned int sig, address pc, void* siginfo, void* context) { - _thread = thread; - _id = sig; - _pc = pc; - _siginfo = siginfo; - _context = context; - - _verbose = false; - _current_step = 0; - _current_step_info = NULL; - - _message = NULL; - _detail_msg = NULL; - _filename = NULL; - _lineno = 0; - - _size = 0; -} - -// Constructor for internal errors -VMError::VMError(Thread* thread, const char* filename, int lineno, - const char* message, const char * detail_msg) -{ - _thread = thread; - _id = INTERNAL_ERROR; // Value that's not an OS exception/signal - _filename = filename; - _lineno = lineno; - _message = message; - _detail_msg = detail_msg; - - _verbose = false; - _current_step = 0; - _current_step_info = NULL; - - _pc = NULL; - _siginfo = NULL; - _context = NULL; - - _size = 0; -} - -// Constructor for OOM errors -VMError::VMError(Thread* thread, const char* filename, int lineno, size_t size, - VMErrorType vm_err_type, const char* message) { - _thread = thread; - _id = vm_err_type; // Value that's not an OS exception/signal - _filename = filename; - _lineno = lineno; - _message = message; - _detail_msg = NULL; - - _verbose = false; - _current_step = 0; - _current_step_info = NULL; - - _pc = NULL; - _siginfo = NULL; - _context = NULL; - - _size = size; -} - - -// Constructor for non-fatal errors -VMError::VMError(const char* message) { - _thread = NULL; - _id = INTERNAL_ERROR; // Value that's not an OS exception/signal - _filename = NULL; - _lineno = 0; - _message = message; - _detail_msg = NULL; - - _verbose = false; - _current_step = 0; - _current_step_info = NULL; - - _pc = NULL; - _siginfo = NULL; - _context = NULL; - - _size = 0; -} - -// -XX:OnError=, where can be a list of commands, separated -// by ';'. "%p" is replaced by current process id (pid); "%%" is replaced by -// a single "%". Some examples: -// -// -XX:OnError="pmap %p" // show memory map -// -XX:OnError="gcore %p; dbx - %p" // dump core and launch debugger -// -XX:OnError="cat hs_err_pid%p.log | mail my_email@sun.com" -// -XX:OnError="kill -9 %p" // ?#!@# - // A simple parser for -XX:OnError, usage: // ptr = OnError; // while ((cmd = next_OnError_command(buffer, sizeof(buffer), &ptr) != NULL) @@ -196,7 +93,6 @@ return buf; } - static void print_bug_submit_message(outputStream *out, Thread *thread) { if (out == NULL) return; out->print_raw_cr("# If you would like to submit a bug report, please visit:"); @@ -223,7 +119,6 @@ coredump_message[sizeof(coredump_message)-1] = 0; } - // Return a string to describe the error char* VMError::error_string(char* buf, int buflen) { char signame_buf[64]; @@ -243,9 +138,9 @@ p ? p + 1 : _filename, _lineno, os::current_process_id(), os::current_thread_id()); if (n >= 0 && n < buflen && _message) { - if (_detail_msg) { + if (strlen(_detail_msg) > 0) { jio_snprintf(buf + n, buflen - n, "%s%s: %s", - os::line_separator(), _message, _detail_msg); + os::line_separator(), _message, _detail_msg); } else { jio_snprintf(buf + n, buflen - n, "%sError: %s", os::line_separator(), _message); @@ -357,7 +252,11 @@ // thread can report error, so large buffers are statically allocated in data // segment. -void VMError::report(outputStream* st) { +int VMError::_current_step; +const char* VMError::_current_step_info; + +void VMError::report(outputStream* st, bool _verbose) { + # define BEGIN if (_current_step == 0) { _current_step = 1; # define STEP(n, s) } if (_current_step < n) { _current_step = n; _current_step_info = s; # define END } @@ -384,14 +283,14 @@ // error handler after a secondary crash works. STEP(20, "(test secondary crash 1)") if (_verbose && TestCrashInErrorHandler != 0) { - st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", + st->print_cr("Will crash now (TestCrashInErrorHandler=" UINTX_FORMAT ")...", TestCrashInErrorHandler); controlled_crash(TestCrashInErrorHandler); } STEP(30, "(test secondary crash 2)") if (_verbose && TestCrashInErrorHandler != 0) { - st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...", + st->print_cr("Will crash now (TestCrashInErrorHandler=" UINTX_FORMAT ")...", TestCrashInErrorHandler); controlled_crash(TestCrashInErrorHandler); } @@ -429,15 +328,15 @@ jio_snprintf(buf, sizeof(buf), SIZE_FORMAT, _size); st->print("%s", buf); st->print(" bytes"); - if (_message != NULL) { + if (strlen(_detail_msg) > 0) { st->print(" for "); - st->print("%s", _message); + st->print("%s", _detail_msg); } st->cr(); } else { - if (_message != NULL) { + if (strlen(_detail_msg) > 0) { st->print("# "); - st->print_cr("%s", _message); + st->print_cr("%s", _detail_msg); } } // In error file give some solutions @@ -460,7 +359,7 @@ if (os::exception_name(_id, buf, sizeof(buf))) { st->print("%s", buf); st->print(" (0x%x)", _id); // signal number - st->print(" at pc=" PTR_FORMAT, _pc); + st->print(" at pc=" PTR_FORMAT, p2i(_pc)); } else { if (should_report_bug(_id)) { st->print("Internal Error"); @@ -493,12 +392,12 @@ if (should_report_bug(_id)) { // already printed the message. // error message - if (_detail_msg) { + if (strlen(_detail_msg) > 0) { st->print_cr("# %s: %s", _message ? _message : "Error", _detail_msg); } else if (_message) { st->print_cr("# Error: %s", _message); } - } + } STEP(90, "(printing Java version string)") @@ -511,11 +410,17 @@ JDK_Version::runtime_version() : ""; st->print_cr("# JRE version: %s (%s) (build %s)", runtime_name, buf, runtime_version); // This is the long version with some default settings added - st->print_cr("# Java VM: %s (%s, %s%s%s, %s, %s)", + st->print_cr("# Java VM: %s (%s, %s%s%s%s%s, %s, %s)", Abstract_VM_Version::vm_name(), Abstract_VM_Version::vm_release(), Abstract_VM_Version::vm_info_string(), TieredCompilation ? ", tiered" : "", +#if INCLUDE_JVMCI + EnableJVMCI ? ", jvmci" : "", + UseJVMCICompiler ? ", jvmci compiler" : "", +#else + "", "", +#endif UseCompressedOops ? ", compressed oops" : "", gc_mode(), Abstract_VM_Version::vm_platform_string() @@ -595,7 +500,7 @@ // current thread if (_verbose) { if (_thread) { - st->print("Current thread (" PTR_FORMAT "): ", _thread); + st->print("Current thread (" PTR_FORMAT "): ", p2i(_thread)); _thread->print_on_error(st, buf, sizeof(buf)); st->cr(); } else { @@ -634,13 +539,13 @@ } address stack_bottom = stack_top - stack_size; - st->print("[" PTR_FORMAT "," PTR_FORMAT "]", stack_bottom, stack_top); + st->print("[" PTR_FORMAT "," PTR_FORMAT "]", p2i(stack_bottom), p2i(stack_top)); frame fr = _context ? os::fetch_frame_from_context(_context) : os::current_frame(); if (fr.sp()) { - st->print(", sp=" PTR_FORMAT, fr.sp()); + st->print(", sp=" PTR_FORMAT, p2i(fr.sp())); size_t free_stack_size = pointer_delta(fr.sp(), stack_bottom, 1024); st->print(", free space=" SIZE_FORMAT "k", free_stack_size); } @@ -674,7 +579,7 @@ if (_verbose && _thread && (_thread->is_Named_thread())) { JavaThread* jt = ((NamedThread *)_thread)->processed_thread(); if (jt != NULL) { - st->print_cr("JavaThread " PTR_FORMAT " (nid = " UINTX_FORMAT ") was being processed", jt, jt->osthread()->thread_id()); + st->print_cr("JavaThread " PTR_FORMAT " (nid = %d) was being processed", p2i(jt), jt->osthread()->thread_id()); print_stack_trace(st, jt, buf, sizeof(buf), true); } } @@ -704,6 +609,31 @@ st->cr(); } + STEP(265, "(printing code blob if possible)") + + if (_verbose && _context) { + CodeBlob* cb = CodeCache::find_blob(_pc); + if (cb != NULL) { + if (Interpreter::contains(_pc)) { + // The interpreter CodeBlob is very large so try to print the codelet instead. + InterpreterCodelet* codelet = Interpreter::codelet_containing(_pc); + if (codelet != NULL) { + codelet->print_on(st); + Disassembler::decode(codelet->code_begin(), codelet->code_end(), st); + } + } else { + StubCodeDesc* desc = StubCodeDesc::desc_for(_pc); + if (desc != NULL) { + desc->print_on(st); + Disassembler::decode(desc->begin(), desc->end(), st); + } else { + Disassembler::decode(cb, st); + st->cr(); + } + } + } + } + STEP(270, "(printing VM operation)" ) if (_verbose && _thread && _thread->is_VM_thread()) { @@ -786,7 +716,7 @@ Universe::heap()->print_on_error(st); st->cr(); - st->print_cr("Polling page: " INTPTR_FORMAT, os::get_polling_page()); + st->print_cr("Polling page: " INTPTR_FORMAT, p2i(os::get_polling_page())); st->cr(); } @@ -896,8 +826,7 @@ # undef END } -VMError* volatile VMError::first_error = NULL; -volatile jlong VMError::first_error_tid = -1; +volatile intptr_t VMError::first_error_tid = -1; // An error could happen before tty is initialized or after it has been // destroyed. Here we use a very simple unbuffered fdStream for printing. @@ -958,7 +887,59 @@ return fd; } -void VMError::report_and_die() { +int VMError::_id; +const char* VMError::_message; +char VMError::_detail_msg[1024]; +Thread* VMError::_thread; +address VMError::_pc; +void* VMError::_siginfo; +void* VMError::_context; +const char* VMError::_filename; +int VMError::_lineno; +size_t VMError::_size; + +void VMError::report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, + void* context, const char* detail_fmt, ...) +{ + va_list detail_args; + va_start(detail_args, detail_fmt); + report_and_die(sig, NULL, detail_fmt, detail_args, thread, pc, siginfo, context, NULL, 0, 0); + va_end(detail_args); +} + +void VMError::report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, void* context) +{ + report_and_die(thread, sig, pc, siginfo, context, "%s", ""); +} + +void VMError::report_and_die(const char* message, const char* detail_fmt, ...) +{ + va_list detail_args; + va_start(detail_args, detail_fmt); + report_and_die(INTERNAL_ERROR, message, detail_fmt, detail_args, NULL, NULL, NULL, NULL, NULL, 0, 0); + va_end(detail_args); +} + +void VMError::report_and_die(const char* message) +{ + report_and_die(message, "%s", ""); +} + +void VMError::report_and_die(Thread* thread, const char* filename, int lineno, const char* message, + const char* detail_fmt, va_list detail_args) +{ + report_and_die(INTERNAL_ERROR, message, detail_fmt, detail_args, thread, NULL, NULL, NULL, filename, lineno, 0); +} + +void VMError::report_and_die(Thread* thread, const char* filename, int lineno, size_t size, + VMErrorType vm_err_type, const char* detail_fmt, va_list detail_args) { + report_and_die(vm_err_type, NULL, detail_fmt, detail_args, thread, NULL, NULL, NULL, filename, lineno, size); +} + +void VMError::report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args, + Thread* thread, address pc, void* siginfo, void* context, const char* filename, + int lineno, size_t size) +{ // Don't allocate large buffer on stack static char buffer[O_BUFLEN]; @@ -974,12 +955,22 @@ if (SuppressFatalErrorMessage) { os::abort(CreateCoredumpOnCrash); } - jlong mytid = os::current_thread_id(); - if (first_error == NULL && - Atomic::cmpxchg_ptr(this, &first_error, NULL) == NULL) { + intptr_t mytid = os::current_thread_id(); + if (first_error_tid == -1 && + Atomic::cmpxchg_ptr(mytid, &first_error_tid, -1) == -1) { + + _id = id; + _message = message; + _thread = thread; + _pc = pc; + _siginfo = siginfo; + _context = context; + _filename = filename; + _lineno = lineno; + _size = size; + jio_vsnprintf(_detail_msg, sizeof(_detail_msg), detail_fmt, detail_args); // first time - first_error_tid = mytid; set_error_reported(); if (ShowMessageBoxOnError || PauseAtExit) { @@ -1007,7 +998,7 @@ if (first_error_tid != mytid) { char msgbuf[64]; jio_snprintf(msgbuf, sizeof(msgbuf), - "[thread " INT64_FORMAT " also had an error]", + "[thread " INTX_FORMAT " also had an error]", mytid); out.print_raw_cr(msgbuf); @@ -1022,8 +1013,7 @@ jio_snprintf(buffer, sizeof(buffer), "[error occurred during error reporting %s, id 0x%x]", - first_error ? first_error->_current_step_info : "", - _id); + _current_step_info, _id); if (log.is_open()) { log.cr(); log.print_raw_cr(buffer); @@ -1038,21 +1028,17 @@ // print to screen if (!out_done) { - first_error->_verbose = false; - staticBufferStream sbs(buffer, sizeof(buffer), &out); - first_error->report(&sbs); + report(&sbs, false); out_done = true; - first_error->_current_step = 0; // reset current_step - first_error->_current_step_info = ""; // reset current_step string + _current_step = 0; + _current_step_info = ""; } // print to error log file if (!log_done) { - first_error->_verbose = true; - // see if log file is already open if (!log.is_open()) { // open log file @@ -1072,12 +1058,12 @@ } staticBufferStream sbs(buffer, O_BUFLEN, &log); - first_error->report(&sbs); - first_error->_current_step = 0; // reset current_step - first_error->_current_step_info = ""; // reset current_step string + report(&sbs, true); + _current_step = 0; + _current_step_info = ""; // Run error reporting to determine whether or not to report the crash. - if (!transmit_report_done && should_report_bug(first_error->_id)) { + if (!transmit_report_done && should_report_bug(_id)) { transmit_report_done = true; const int fd2 = ::dup(log.fd()); FILE* const hs_err = ::fdopen(fd2, "r"); @@ -1149,7 +1135,7 @@ } } - static bool skip_bug_url = !should_report_bug(first_error->_id); + static bool skip_bug_url = !should_report_bug(_id); if (!skip_bug_url) { skip_bug_url = true; @@ -1162,7 +1148,7 @@ static bool skip_os_abort = false; if (!skip_os_abort) { skip_os_abort = true; - bool dump_core = should_report_bug(first_error->_id); + bool dump_core = should_report_bug(_id); os::abort(dump_core && CreateCoredumpOnCrash, _siginfo, _context); } @@ -1177,10 +1163,10 @@ */ class VM_ReportJavaOutOfMemory : public VM_Operation { private: - VMError *_err; + const char* _message; public: - VM_ReportJavaOutOfMemory(VMError *err) { _err = err; } - VMOp_Type type() const { return VMOp_ReportJavaOutOfMemory; } + VM_ReportJavaOutOfMemory(const char* message) { _message = message; } + VMOp_Type type() const { return VMOp_ReportJavaOutOfMemory; } void doit(); }; @@ -1189,7 +1175,7 @@ static char buffer[O_BUFLEN]; tty->print_cr("#"); - tty->print_cr("# java.lang.OutOfMemoryError: %s", _err->message()); + tty->print_cr("# java.lang.OutOfMemoryError: %s", _message); tty->print_cr("# -XX:OnOutOfMemoryError=\"%s\"", OnOutOfMemoryError); // make heap parsability @@ -1212,10 +1198,10 @@ } } -void VMError::report_java_out_of_memory() { +void VMError::report_java_out_of_memory(const char* message) { if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { MutexLocker ml(Heap_lock); - VM_ReportJavaOutOfMemory op(this); + VM_ReportJavaOutOfMemory op(message); VMThread::execute(&op); } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/src/share/vm/utilities/vmError.hpp --- a/hotspot/src/share/vm/utilities/vmError.hpp Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/src/share/vm/utilities/vmError.hpp Thu Oct 22 11:13:08 2015 -0700 @@ -30,39 +30,40 @@ class Decoder; class VM_ReportJavaOutOfMemory; -class VMError : public StackObj { +class VMError : public AllStatic { friend class VM_ReportJavaOutOfMemory; friend class Decoder; - int _id; // Solaris/Linux signals: 0 - SIGRTMAX - // Windows exceptions: 0xCxxxxxxx system errors - // 0x8xxxxxxx system warnings + static int _id; // Solaris/Linux signals: 0 - SIGRTMAX + // Windows exceptions: 0xCxxxxxxx system errors + // 0x8xxxxxxx system warnings - const char * _message; - const char * _detail_msg; + static const char* _message; + static char _detail_msg[1024]; - Thread * _thread; // NULL if it's native thread - + static Thread* _thread; // NULL if it's native thread // additional info for crashes - address _pc; // faulting PC - void * _siginfo; // ExceptionRecord on Windows, - // siginfo_t on Solaris/Linux - void * _context; // ContextRecord on Windows, - // ucontext_t on Solaris/Linux + static address _pc; // faulting PC + static void* _siginfo; // ExceptionRecord on Windows, + // siginfo_t on Solaris/Linux + static void* _context; // ContextRecord on Windows, + // ucontext_t on Solaris/Linux // additional info for VM internal errors - const char * _filename; - int _lineno; + static const char* _filename; + static int _lineno; + + // used by reporting about OOM + static size_t _size; // used by fatal error handler - int _current_step; - const char * _current_step_info; - int _verbose; - // First error, and its thread id. We must be able to handle native thread, + static int _current_step; + static const char* _current_step_info; + + // Thread id of the first error. We must be able to handle native thread, // so use thread id instead of Thread* to identify thread. - static VMError* volatile first_error; - static volatile jlong first_error_tid; + static volatile intptr_t first_error_tid; // Core dump status, false if we have been unable to write a core/minidump for some reason static bool coredump_status; @@ -72,18 +73,16 @@ // no core/minidump has been written to disk static char coredump_message[O_BUFLEN]; - // used by reporting about OOM - size_t _size; // set signal handlers on Solaris/Linux or the default exception filter // on Windows, to handle recursive crashes. - void reset_signal_handlers(); + static void reset_signal_handlers(); // handle -XX:+ShowMessageBoxOnError. buf is used to format the message string - void show_message_box(char* buf, int buflen); + static void show_message_box(char* buf, int buflen); // generate an error report - void report(outputStream* st); + static void report(outputStream* st, bool verbose); // generate a stack trace static void print_stack_trace(outputStream* st, JavaThread* jt, @@ -92,42 +91,44 @@ static const char* gc_mode(); static void print_oom_reasons(outputStream* st); - // accessor - const char* message() const { return _message; } - const char* detail_msg() const { return _detail_msg; } - bool should_report_bug(unsigned int id) { + static bool should_report_bug(unsigned int id) { return (id != OOM_MALLOC_ERROR) && (id != OOM_MMAP_ERROR); } + static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, + void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7); + static void report_and_die(const char* message, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(2, 3); + static fdStream out; static fdStream log; // error log used by VMError::report_and_die() public: - // Constructor for crashes - VMError(Thread* thread, unsigned int sig, address pc, void* siginfo, - void* context); - // Constructor for VM internal errors - VMError(Thread* thread, const char* filename, int lineno, - const char* message, const char * detail_msg); - - // Constructor for VM OOM errors - VMError(Thread* thread, const char* filename, int lineno, size_t size, - VMErrorType vm_err_type, const char* message); - // Constructor for non-fatal errors - VMError(const char* message); - // return a string to describe the error - char *error_string(char* buf, int buflen); + static char* error_string(char* buf, int buflen); // Record status of core/minidump static void record_coredump_status(const char* message, bool status); // main error reporting function - void report_and_die(); + static void report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args, + Thread* thread, address pc, void* siginfo, void* context, + const char* filename, int lineno, size_t size) ATTRIBUTE_PRINTF(3, 0); + + static void report_and_die(Thread* thread, unsigned int sig, address pc, + void* siginfo, void* context); + + static void report_and_die(Thread* thread,const char* filename, int lineno, const char* message, + const char* detail_fmt, va_list detail_args) ATTRIBUTE_PRINTF(5, 0); + + static void report_and_die(Thread* thread, const char* filename, int lineno, size_t size, + VMErrorType vm_err_type, const char* detail_fmt, + va_list detail_args) ATTRIBUTE_PRINTF(6, 0); + + static void report_and_die(const char* message); // reporting OutOfMemoryError - void report_java_out_of_memory(); + static void report_java_out_of_memory(const char* message); // returns original flags for signal, if it was resetted, or -1 if // signal was not changed by error reporter @@ -138,11 +139,9 @@ static address get_resetted_sighandler(int sig); // check to see if fatal error reporting is in progress - static bool fatal_error_in_progress() { return first_error != NULL; } + static bool fatal_error_in_progress() { return first_error_tid != -1; } - static jlong get_first_error_tid() { - return first_error_tid; - } + static intptr_t get_first_error_tid() { return first_error_tid; } }; #endif // SHARE_VM_UTILITIES_VMERROR_HPP diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/TEST.groups --- a/hotspot/test/TEST.groups Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/TEST.groups Thu Oct 22 11:13:08 2015 -0700 @@ -319,7 +319,7 @@ hotspot_runtime = \ runtime/ \ - -runtime/6888954/vmerrors.sh \ + -runtime/ErrorHandling/ErrorHandler.java \ -runtime/RedefineObject/TestRedefineObject.java \ -runtime/8003720/Test8003720.java \ -runtime/Metaspace/FragmentMetaspace.java \ @@ -327,6 +327,7 @@ -runtime/Thread/TestThreadDumpMonitorContention.java \ -runtime/SharedArchiveFile/SharedBaseAddress.java \ -runtime/memory/ReserveMemory.java \ + -runtime/memory/RunUnitTestsConcurrently.java \ -runtime/Unsafe/RangeCheck.java \ -runtime/SharedArchiveFile/CdsSameObjectAlignment.java \ -runtime/SharedArchiveFile/DefaultUseWithClient.java \ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/TestMoveStoresOutOfLoopsStoreNoCtrl.java --- a/hotspot/test/compiler/TestMoveStoresOutOfLoopsStoreNoCtrl.java Thu Oct 22 08:47:43 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 8134288 - * @summary Store nodes may not have a control if used to update profiling - * @run main/othervm -XX:-ProfileInterpreter -XX:-TieredCompilation -XX:-BackgroundCompilation TestMoveStoresOutOfLoopsStoreNoCtrl - * - */ - -public class TestMoveStoresOutOfLoopsStoreNoCtrl { - - static void test(boolean flag) { - for (int i = 0; i < 20000; i++) { - if (flag) { - int j = 0; - do { - j++; - } while(j < 10); - } - } - } - - static public void main(String[] args) { - test(false); - } - -} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/c2/5057225/Test5057225.java --- a/hotspot/test/compiler/c2/5057225/Test5057225.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/c2/5057225/Test5057225.java Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,11 @@ * @test * @bug 5057225 * @summary Remove useless I2L conversions - * + * @library /testlibrary * @run main/othervm -Xcomp -XX:CompileOnly=Test5057225.doload Test5057225 */ -import java.net.URLClassLoader; +import jdk.test.lib.Utils; public class Test5057225 { static byte[] ba = new byte[] { -1 }; @@ -89,8 +89,9 @@ static void loadAndRunClass(String classname) throws Exception { Class cl = Class.forName(classname); - URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent()); + ClassLoader apploader = cl.getClassLoader(); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass(classname); Runnable r = (Runnable) c.newInstance(); r.run(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/c2/5091921/Test7005594.sh --- a/hotspot/test/compiler/c2/5091921/Test7005594.sh Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/c2/5091921/Test7005594.sh Thu Oct 22 11:13:08 2015 -0700 @@ -78,7 +78,7 @@ ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7005594.java -${TESTJAVA}/bin/java ${TESTOPTS} -Xmx1600m -Xms1600m -XX:+IgnoreUnrecognizedVMOptions -XX:-ZapUnusedHeapArea -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 > test.out 2>&1 +${TESTJAVA}/bin/java ${TESTOPTS} -Xmx1600m -Xms1600m -XX:+IgnoreUnrecognizedVMOptions -XX:-ZapUnusedHeapArea -Xcomp -XX:CompileOnly=Test7005594.test -XX:CompileCommand=quiet Test7005594 > test.out 2>&1 result=$? diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/c2/6603011/Test.java --- a/hotspot/test/compiler/c2/6603011/Test.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/c2/6603011/Test.java Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 6603011 * @summary long/int division by constant - * + * @library /testlibrary * @run main/othervm -Xcomp -Xbatch -XX:-Inline Test */ @@ -36,7 +36,7 @@ // dividend and divisor combinations are tested // -import java.net.*; +import jdk.test.lib.Utils; class s { static int divi(int dividend, int divisor) { return dividend / divisor; } @@ -189,10 +189,10 @@ // This allows the JIT to see q.DIVISOR as a final constant, and change // any divisions or mod operations into multiplies. public static void test_divisor(int divisor, - URLClassLoader apploader) throws Exception { + ClassLoader apploader) throws Exception { System.setProperty("divisor", "" + divisor); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), - apploader.getParent()); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass("Test"); Runnable r = (Runnable)c.newInstance(); r.run(); @@ -200,7 +200,7 @@ public static void main(String[] args) throws Exception { Class cl = Class.forName("Test"); - URLClassLoader apploader = (URLClassLoader)cl.getClassLoader(); + ClassLoader apploader = cl.getClassLoader(); // Test every divisor between -100 and 100. diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/c2/6800154/Test6800154.java --- a/hotspot/test/compiler/c2/6800154/Test6800154.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/c2/6800154/Test6800154.java Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,11 @@ * @test * @bug 6800154 * @summary Add comments to long_by_long_mulhi() for better understandability - * + * @library /testlibrary * @run main/othervm -Xcomp -XX:CompileOnly=Test6800154.divcomp Test6800154 */ -import java.net.URLClassLoader; +import jdk.test.lib.Utils; public class Test6800154 implements Runnable { static final long[] DIVIDENDS = { @@ -78,12 +78,13 @@ public static void main(String[] args) throws Exception { Class cl = Class.forName("Test6800154"); - URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); + ClassLoader apploader = cl.getClassLoader(); // Iterate over all divisors. for (int i = 0; i < DIVISORS.length; i++) { System.setProperty("divisor", "" + DIVISORS[i]); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent()); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass("Test6800154"); Runnable r = (Runnable) c.newInstance(); r.run(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/c2/6805724/Test6805724.java --- a/hotspot/test/compiler/c2/6805724/Test6805724.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/c2/6805724/Test6805724.java Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * 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,12 +24,13 @@ /** * @test * @bug 6805724 - * @summary ModLNode::Ideal() generates functionally incorrect graph when divisor is any (2^k-1) constant. - * + * @summary ModLNode::Ideal() generates functionally incorrect graph + * when divisor is any (2^k-1) constant. + * @library /testlibrary * @run main/othervm -Xcomp -XX:CompileOnly=Test6805724.fcomp Test6805724 */ -import java.net.URLClassLoader; +import jdk.test.lib.Utils; public class Test6805724 implements Runnable { // Initialize DIVISOR so that it is final in this class. @@ -65,13 +66,14 @@ public static void main(String args[]) throws Exception { Class cl = Class.forName("Test6805724"); - URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); + ClassLoader apploader = cl.getClassLoader(); // Iterate over all 2^k-1 divisors. for (int k = 1; k < Long.SIZE; k++) { long divisor = (1L << k) - 1; System.setProperty("divisor", "" + divisor); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent()); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass("Test6805724"); Runnable r = (Runnable) c.newInstance(); r.run(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java --- a/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -21,6 +21,7 @@ * questions. */ +import compiler.testlibrary.CompilerUtils; import jdk.test.lib.Asserts; import jdk.test.lib.JDKToolFinder; import jdk.test.lib.OutputAnalyzer; @@ -47,7 +48,7 @@ * @test SegmentedCodeCacheDtraceTest * @bug 8015774 * @requires os.family=="solaris" - * @library /testlibrary /compiler/testlibrary /../../test/lib + * @library /testlibrary / /../../test/lib * @build SegmentedCodeCacheDtraceTestWorker * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/codegen/6823354/Test6823354.java --- a/hotspot/test/compiler/codegen/6823354/Test6823354.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/codegen/6823354/Test6823354.java Thu Oct 22 11:13:08 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,11 @@ * @test * @bug 6823354 * @summary These methods can be instrinsified by using bit scan, bit test, and population count instructions. - * + * @library /testlibrary * @run main/othervm -Xcomp -XX:CompileOnly=Test6823354.lzcomp,Test6823354.tzcomp,.dolzcomp,.dotzcomp Test6823354 */ -import java.net.URLClassLoader; +import jdk.test.lib.Utils; public class Test6823354 { // Arrays of corner case values. @@ -197,8 +197,9 @@ static void loadandrunclass(String classname) throws Exception { Class cl = Class.forName(classname); - URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); - ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent()); + ClassLoader apploader = cl.getClassLoader(); + ClassLoader loader + = Utils.getTestClassPathURLClassLoader(apploader.getParent()); Class c = loader.loadClass(classname); Runnable r = (Runnable) c.newInstance(); r.run(); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/matcher/MethodMatcherTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/matcher/MethodMatcherTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.compilercontrol.matcher; + +import jdk.test.lib.Pair; +import compiler.compilercontrol.share.method.MethodDescriptor; +import compiler.compilercontrol.share.method.MethodGenerator; +import pool.PoolHelper; +import sun.hotspot.WhiteBox; + +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/* + * @test + * @bug 8135068 + * @summary Tests CompilerCommand's method matcher + * @library /testlibrary /../../test/lib /compiler/whitebox ../share / + * @build MethodMatcherTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI compiler.compilercontrol.matcher.MethodMatcherTest + */ +public class MethodMatcherTest { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final PoolHelper POOL = new PoolHelper(); + private static final List>> METHODS = + POOL.getAllMethods(); + private static final int AMOUNT = Integer.parseInt(System + .getProperty("test.amount", "25")); + + public static void main(String[] args) { + MethodGenerator gen = new MethodGenerator(); + List>> testMethods = + POOL.getAllMethods(PoolHelper.METHOD_FILTER); + for (Pair> pair : testMethods) { + for (int i = 0; i < AMOUNT; i++) { + MethodDescriptor md = gen.generateRandomDescriptor(pair.first); + check(md); + } + } + } + + /** + * Check method matcher with given test case + * + * @param methodDescriptor method descriptor to check matcher's pattern + */ + private static void check(MethodDescriptor methodDescriptor) { + System.out.println("Test case: " + methodDescriptor.getString()); + System.out.println("Regex: " + methodDescriptor.getRegexp()); + Pattern pattern = Pattern.compile(methodDescriptor.getRegexp()); + boolean isValidDesc = methodDescriptor.isValid(); + List failList = new ArrayList<>(); + // walk through all methods in pool to check match with test pattern + for (Pair> pair : METHODS) { + MethodDescriptor m = MethodGenerator.commandDescriptor(pair.first); + Matcher matcher = pattern.matcher(m.getCanonicalString()); + // get expected result + MatcherResult expected; + if (isValidDesc) { + expected = matcher.matches() ? + MatcherResult.MATCH : MatcherResult.NO_MATCH; + } else { + expected = MatcherResult.PARSING_FAILURE; + } + // get MethodMatcher's result + MatcherResult matchResult = MatcherResult.fromCode(WB.matchesMethod( + pair.first, methodDescriptor.getString())); + // compare + if (matchResult != expected) { + System.out.printf("- Method: %s%n-- FAILED: result: %s, " + + "but expected: %s%n", m.getCanonicalString(), + matchResult, expected); + failList.add(m); + } + } + int size = failList.size(); + if (size != 0) { + System.err.println("FAILED test case: " + methodDescriptor + .getString()); + if (size == METHODS.size()) { + System.err.println("-- All methods failed to match"); + } else { + for (MethodDescriptor md : failList) { + System.err.println("-- FAILED match: " + md.getString()); + } + } + throw new AssertionError("FAIL: " + methodDescriptor.getString()); + } + System.out.println("--PASSED"); + } + + /** + * Represents MethodMatcher's matching result + */ + public enum MatcherResult { + PARSING_FAILURE(-1, "Parsing failed"), + NO_MATCH(0, "No match"), + MATCH(1, "Match"); + + public final int code; + private final String message; + + private MatcherResult(int code, String message) { + this.code = code; + this.message = message; + } + + public static MatcherResult fromCode(int code) { + switch (code) { + case -1: return PARSING_FAILURE; + case 0: return NO_MATCH; + case 1: return MATCH; + default: + throw new IllegalArgumentException("MATCHER FAILURE:" + + "Wrong code: " + code); + } + } + + @Override + public String toString() { + return message; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/method/ClassType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/method/ClassType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.compilercontrol.share.method; + +import java.lang.reflect.Executable; +import java.util.Arrays; +import java.util.stream.Collectors; + +/** + * Element represents class in method descriptor + * that consist from class package and class itself + */ +public class ClassType extends MethodElementType { + private final String[] packageDirs; + private final Class aClass; + private boolean setPackage; + + public ClassType(Executable method) { + // Use pack/subpack/Class::method separators style + super(MethodDescriptor.Separator.SLASH); + // Get package + aClass = method.getDeclaringClass(); + Package aPackage = method.getDeclaringClass().getPackage(); + if (aPackage != null) { + // split into directories + packageDirs = aPackage.getName().split("\\."); + } else { + packageDirs = null; + } + setPackage = true; + buildElement(setPackage); + } + + @Override + public boolean isValid() { + if (element.isEmpty()) { + return false; + } + boolean separatorMet = false; + char separatorChar = 0; + char[] charArray = element.toCharArray(); + for (int i = 0; i < charArray.length; i++) { + char ch = charArray[i]; + switch (ch) { + case '/': + case '.': + if (separatorMet) { + if (ch != separatorChar) { + // there are two different separators + return false; + } + } else { + separatorChar = ch; + separatorMet = true; + } + break; + case ':': + if (++i != charArray.length) { + if (charArray[i] == ':') { + // :: is invalid separator + separator = MethodDescriptor.Separator.DOUBLECOLON; + return false; + } + } + break; + // Invalid separators + case ',': + case ' ': + return false; + } + } + // set correct separator + switch (separatorChar) { + case '.': + separator = MethodDescriptor.Separator.DOT; + break; + case '/': + separator = MethodDescriptor.Separator.SLASH; + break; + default: + separator = MethodDescriptor.Separator.NONE; + break; + } + return super.isValid(); + } + + @Override + public void setSeparator(MethodDescriptor.Separator separator) { + this.separator = separator; + buildElement(setPackage); + } + + @Override + public void setPattern(MethodDescriptor.PatternType patternType) { + switch (patternType) { + case EXACT: + break; + case PREFIX: + // For prefix pattern use only class name without package + buildElement(false); + regexp = ".*" + regexp; + element = "*" + element; + break; + case ANY: + regexp = ".*"; + element = "*"; + break; + case SUFFIX: + regexp = regexp + ".*"; + element = element + "*"; + break; + case SUBSTRING: + setPattern(MethodDescriptor.PatternType.PREFIX); + setPattern(MethodDescriptor.PatternType.SUFFIX); + break; + default: + throw new IllegalArgumentException("ERROR: wrong pattern type " + + patternType); + } + } + + /** + * Builds element string and regexp. + * + * @param setPackage shows that element should have a package name + */ + private void buildElement(boolean setPackage) { + this.setPackage = setPackage; + StringBuilder elementBuilder = new StringBuilder(); + if (packageDirs != null && setPackage) { + elementBuilder.append(Arrays.stream(packageDirs) + .collect(Collectors.joining(separator.symbol))); + elementBuilder.append(separator.symbol); + } + String className = aClass.getSimpleName(); + if (setPackage) { + // Add outer classes if any + Class enclosingClass = aClass.getEnclosingClass(); + while (enclosingClass != null) { + className = enclosingClass.getSimpleName() + "$" + className; + enclosingClass = enclosingClass.getEnclosingClass(); + } + } + elementBuilder.append(className); + element = elementBuilder.toString(); + if (separator == MethodDescriptor.Separator.DOT) { + // Replace . with / to make regexp look like CommandSignature + regexp = element.replace(".", "/"); + } else { + regexp = element; + } + regexp = regexp.replace("$", "\\$"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/method/MethodDescriptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/method/MethodDescriptor.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.compilercontrol.share.method; + +import jdk.test.lib.Triple; + +import java.lang.reflect.Executable; +import java.util.function.Function; +import java.util.regex.Pattern; + +/** + * Method descriptor for Compiler Control commands. + * It represents method pattern used for matching in Compiler Control + * and CompileCommand option + */ +public class MethodDescriptor { + public final ClassType aClass; // Represents class and package + public final MethodType aMethod; // Represents method + public final SignatureType aSignature; // Represents signature + + /** + * Constructor + * + * @param method executable to build method descriptor from + */ + public MethodDescriptor(Executable method) { + aClass = new ClassType(method); + aMethod = new MethodType(method); + aSignature = new SignatureType(method); + } + + /** + * Sets signature separators for all elements + */ + public void setSeparators( + Triple separators) { + aClass.setSeparator(separators.getFirst()); + aMethod.setSeparator(separators.getSecond()); + aSignature.setSeparator(separators.getThird()); + } + + /** + * Sets custom strings for each element + */ + public void setStrings(Triple strings) { + aClass.setElement(strings.getFirst()); + aMethod.setElement(strings.getSecond()); + aSignature.setElement(strings.getThird()); + } + + /** + * Sets patterns for all elements + */ + public void setPatterns( + Triple patterns) { + aClass.setPattern(patterns.getFirst()); + aMethod.setPattern(patterns.getSecond()); + aSignature.setPattern(patterns.getThird()); + } + + /** + * Separates elements in the MethodDescriptor + */ + public static enum Separator { + SLASH("/"), + DOT("."), + COMMA(","), + DOUBLECOLON("::"), + SPACE(" "), + NONE(""); + + public final String symbol; + + Separator(String symbol) { + this.symbol = symbol; + } + + /** + * Validates method descriptor separators + * + * @param md method descriptor to validate + * @return true if descriptor's separators are valid + */ + public static boolean isValid(MethodDescriptor md) { + Separator cls = md.getClassSeparator(); + Separator method = md.getMethodSeparator(); + Separator sign = md.getSignatureSeparator(); + if (sign == SPACE || sign == NONE || sign == COMMA) { + // if it looks like java/lang/String.indexOf + if ((cls == SLASH || cls == NONE) + // allow space and comma instead of dot + && (method == DOT || method == SPACE + || method == COMMA)) { + return true; + } + // if it looks like java.lang.String::indexOf + if ((cls == DOT || cls == NONE) && method == DOUBLECOLON) { + return true; + } + } + return false; + } + } + + /** + * Type of the pattern + */ + public static enum PatternType { + PREFIX, + ANY, + SUFFIX, + SUBSTRING, + EXACT + } + + public Separator getClassSeparator() { + return aClass.getSeparator(); + } + + public Separator getMethodSeparator() { + return aMethod.getSeparator(); + } + + public Separator getSignatureSeparator() { + return aSignature.getSeparator(); + } + + /** + * Gets regular expression to match methods + * + * @return string representation of the regular expression + */ + public String getRegexp() { + // regexp should have a . as a method separator + // and / as a package/class separator + return aClass.getRegexp().replaceAll("\\.", "/") + .replaceAll("/\\*", ".*") + + Pattern.quote(Separator.DOT.symbol) + + aMethod.getRegexp() + aSignature.getRegexp(); + } + + /** + * Gets method descriptor string representation. + * This string is used as a pattern in CompilerControl and CompileCommand + */ + public String getString() { + return aClass.getElement() + getMethodSeparator().symbol + + aMethod.getElement() + getSignatureSeparator().symbol + + aSignature.getElement(); + } + + /** + * Convert method descriptor to be regexp-compatible + * + * @return string representation of the method signature + */ + public String getCanonicalString() { + return aClass.getElement().replaceAll("\\.", "/") + Separator.DOT.symbol + + aMethod.getElement() + aSignature.getElement(); + } + + /** + * Shows if this descriptor is a valid pattern for CompilerControl + * + * @return true, if descriptor is valid, false otherwise + */ + public boolean isValid() { + return aClass.isValid() && aMethod.isValid() && aSignature.isValid() + && Separator.isValid(this); + } + + /** + * Sets custom string from element mutate function + * to the appropriate element of method descriptor + */ + public void applyMutates(Triple, + Function, + Function> mutators) { + String elementString = aClass.getElement(); + aClass.setElement(mutators.getFirst().apply(elementString)); + elementString = aMethod.getElement(); + aMethod.setElement(mutators.getSecond().apply(elementString)); + elementString = aSignature.getElement(); + aSignature.setElement(mutators.getThird().apply(elementString)); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/method/MethodElementType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/method/MethodElementType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.compilercontrol.share.method; + +import java.util.regex.Pattern; + +/** + * Class represents an element of the MethodDescriptor + * used as pattern for CompilerCommand method strings + */ +public abstract class MethodElementType { + private static final char[] INVALID_CHARS = { ';', '[', '(', ')', ']', + '<', '>'}; + protected String element; + protected String regexp; + protected MethodDescriptor.Separator separator; + + /** + * Constructor + */ + protected MethodElementType(MethodDescriptor.Separator separator) { + this.separator = separator; + } + + /** + * Gets element's separator + * + * @return separator instance + */ + public MethodDescriptor.Separator getSeparator() { + return separator; + } + + /** + * Sets separator for this element + * + * @param separator separator type + */ + public void setSeparator(MethodDescriptor.Separator separator) { + this.separator = separator; + } + + /** + * Gets String representation of the element + * + * @return element string + */ + public String getElement() { + return element; + } + + /** + * Sets String representation of the element + * + * @param element custom string to be used as an element + */ + public void setElement(String element) { + this.element = element; + this.regexp = Pattern.quote(element); + } + + /** + * Shows that the element is valid according to CompilerControl and JVMS specs + * + * @return true, if the element is a valid string + */ + public boolean isValid() { + for (char ch : INVALID_CHARS) { + if (element.indexOf(ch) != -1) { + return false; + } + } + // Check for * usage + if (element.equals("**")) { + return false; + } + for (int i = 0; i < element.length(); i++) { + char c = element.charAt(i); + if (c == '*' && i > 0 && i < element.length() - 1) { + // Embedded * isn't allowed + return false; + } + } + return true; + } + + /** + * Creates pattern of a given type + * + * @param patternType type of the pattern + */ + public void setPattern(MethodDescriptor.PatternType patternType) { + switch (patternType) { + case EXACT: + break; + case PREFIX: + regexp = ".*" + regexp; + element = "*" + element; + break; + case ANY: + regexp = ".*"; + element = "*"; + break; + case SUFFIX: + regexp = regexp + ".*"; + element = element + "*"; + break; + case SUBSTRING: + setPattern(MethodDescriptor.PatternType.PREFIX); + setPattern(MethodDescriptor.PatternType.SUFFIX); + break; + default: + throw new IllegalArgumentException("ERROR: wrong pattern type" + + patternType); + } + } + + /** + * Gets regular expression of this element + * + * @return string representation of regexp + */ + public String getRegexp() { + return regexp; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/method/MethodGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/method/MethodGenerator.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.compilercontrol.share.method; + +import compiler.compilercontrol.share.method.MethodDescriptor.PatternType; +import compiler.compilercontrol.share.method.MethodDescriptor.Separator; +import jdk.test.lib.Pair; +import jdk.test.lib.Triple; +import jdk.test.lib.Utils; +import pool.PoolHelper; + +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Function; + +/** + * Generates combinations of method descriptors from the pool of methods + */ +public class MethodGenerator { + private static final List>> METHODS = + new PoolHelper().getAllMethods(PoolHelper.METHOD_FILTER); + // Different combinations of patterns + private static final List> PATTERNS_LIST; + // Different combinations of separators + private static final List> SEPARATORS_LIST; + // List of functions that modify elements + private static final List> ELEMENT_MUTATORS; + + static { + PATTERNS_LIST = + generate(EnumSet.allOf(PatternType.class), + EnumSet.allOf(PatternType.class), + EnumSet.of(PatternType.ANY, PatternType.EXACT)); + SEPARATORS_LIST = + generate(EnumSet.of(Separator.SLASH, Separator.DOT), + EnumSet.complementOf(EnumSet.of(Separator.NONE)), + EnumSet.of(Separator.COMMA, Separator.SPACE, + Separator.NONE)); + ELEMENT_MUTATORS = generateMutators(); + } + + // Test method + public static void main(String[] args) { + MethodGenerator methodGenerator = new MethodGenerator(); + List tests = methodGenerator.getTests(); + tests.forEach(System.out::println); + } + + /** + * Generates random method descriptor + * + * @param executable executable used to generate descriptor + * @return MethodDescriptor instance + */ + public MethodDescriptor generateRandomDescriptor(Executable executable) { + Combination patterns = + Utils.getRandomElement(PATTERNS_LIST); + Combination separators = + Utils.getRandomElement(SEPARATORS_LIST); + // Create simple mutators for signature generation + List> signMutators = new ArrayList<>(); + signMutators.add(input -> input); + signMutators.add(input -> ""); + Combination> mutators = new Combination<>( + Utils.getRandomElement(ELEMENT_MUTATORS), + Utils.getRandomElement(ELEMENT_MUTATORS), + // use only this type of mutators + Utils.getRandomElement(signMutators)); + return makeMethodDescriptor(executable, patterns, + separators, mutators); + } + + /** + * Compile command signature that looks like java/lang/String.indexOf + * http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html#BABDDFII + * + * @param executable executable used to generate descriptor + * @return MethodDescriptor instance + */ + public static MethodDescriptor commandDescriptor(Executable executable) { + MethodDescriptor md = new MethodDescriptor(executable); + md.aClass.setSeparator(Separator.SLASH); + md.aMethod.setSeparator(Separator.DOT); + md.aSignature.setSeparator(Separator.NONE); + return md; + } + + /** + * Compile command signature that looks like java.lang.String::indexOf + * + * @param executable executable used to generate descriptor + * @return MethodDescriptor instance + */ + public static MethodDescriptor logDescriptor(Executable executable) { + MethodDescriptor md = new MethodDescriptor(executable); + md.aClass.setSeparator(Separator.DOT); + md.aMethod.setSeparator(Separator.DOUBLECOLON); + md.aSignature.setSeparator(Separator.NONE); + return md; + } + + /** + * Generates a list of method patterns from the pool of methods + * + * @return a list of test cases + */ + public List getTests() { + List list = new ArrayList<>(); + METHODS.forEach(pair -> list.addAll(getTests(pair.first))); + return list; + } + + /** + * Generates all combinations of method descriptors for a given executable + * + * @param executable executable for which the different combination is built + * @return list of method descriptors + */ + public List getTests(Executable executable) { + List list = new ArrayList<>(); + for (Combination patterns : PATTERNS_LIST) { + for (Combination separators : SEPARATORS_LIST) { + for (Function classGen : ELEMENT_MUTATORS) { + for (Function methodGen : + ELEMENT_MUTATORS) { + for (Function signatureGen : + ELEMENT_MUTATORS) { + list.add(makeMethodDescriptor(executable, + patterns, separators, + new Combination<>(classGen, methodGen, + signatureGen))); + } + } + } + } + } + return list; + } + + /** + * Creates method descriptor from the given executable, + * patterns and separators for its elements + */ + private MethodDescriptor makeMethodDescriptor( + Executable executable, + Combination patterns, + Combination separators, + Combination> mutators) { + MethodDescriptor methodDescriptor = new MethodDescriptor(executable); + methodDescriptor.setSeparators(separators); + methodDescriptor.applyMutates(mutators); + methodDescriptor.setPatterns(patterns); + return methodDescriptor; + } + + /** + * Creates a list of functions that change given string + */ + private static List> generateMutators() { + List> elements = new ArrayList<>(); + // Use the input itself + elements.add(input -> input); + // Use half of the input string + elements.add(input -> input.substring(input.length() / 2)); + // Add nonexistent element + elements.add(input -> "nonexistent"); + // Use left and right angle brackets + elements.add(input -> "<" + input + ">"); + // Embed * inside + elements.add(input -> embed(input, "*")); + // ** as a whole element + elements.add(input -> "**"); + // Embed JLS-invalid letters + elements.add(input -> embed(input, "@%")); + elements.add(input -> embed(input, "]")); + // Use JLS-invalid letters + elements.add(input -> "-"); + elements.add(input -> "+"); + elements.add(input -> ")" + input); + elements.add(input -> "{" + input + "}"); + // Add valid Java identifier start char + elements.add(input -> "_" + input); + elements.add(input -> "$" + input); + elements.add(input -> "0" + input); + // Unicode characters + elements.add(input -> embed(input, "\u0001")); + elements.add(input -> embed(input, "\u007F")); + // Combining character + elements.add(input -> embed(input, "\u0300")); + elements.add(input -> embed(input, "\u0306")); + // Supplementary character + elements.add(input -> new String(Character.toChars(0x1F64C))); + return elements; + } + + /** + * Embeds one string inside another one + * + * @param target target source string + * @param element string to be embedded into target string + * @return result string + */ + private static String embed(String target, String element) { + int mid = target.length() / 2; + String begin = target.substring(0, mid); + String end = target.substring(mid); + return begin + element + end; + } + + /** + * Generates triples from the given enum sets + * for each of the method elements + * + * @param classSet set of allowed elements for class + * @param methodSet set of allowed elements for method + * @param signSet set of allowed elements for signature + * @param type of generated triples + * @return list of triples + */ + private static > List> generate( + EnumSet classSet, EnumSet methodSet, EnumSet signSet) { + List> list = new ArrayList<>(); + classSet.forEach(clsElement -> + methodSet.forEach(methodElement -> + signSet.forEach(signElement -> + list.add(new Combination<>(clsElement, methodElement, + signElement)) + ) + ) + ); + return list; + } + + private static class Combination extends Triple { + public Combination(T first, T second, T third) { + super(first, second, third); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/method/MethodType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/method/MethodType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.compilercontrol.share.method; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; + +/** + * Represents a method in CompileControl method signature + */ +public class MethodType extends MethodElementType { + private static final char[] INVALID_CHARS = { '.', '/' }; + + public MethodType(Executable method) { + // Use pack/subpack/Class::method separators style + super(MethodDescriptor.Separator.DOT); + if (method instanceof Constructor) { + element = ""; + } else { + element = method.getName(); + } + regexp = element; + } + + @Override + public boolean isValid() { + for (char ch : INVALID_CHARS) { + if (element.indexOf(ch) != -1) { + return false; + } + } + if (element.isEmpty()) { + // Shouldn't be empty + return false; + } + if (element.contains("<") || element.contains(">")) { + return element.matches("(\\*)?<(cl)?init>(\\*)?"); + } + return super.isValid(); + } + + @Override + public void setPattern(MethodDescriptor.PatternType patternType) { + switch (patternType) { + case EXACT: + break; + case PREFIX: + regexp = ".*" + regexp; + element = "*" + element; + break; + case ANY: + regexp = "[^(]*"; + element = "*"; + break; + case SUFFIX: + regexp = regexp + "[^(]*"; + element = element + "*"; + break; + case SUBSTRING: + setPattern(MethodDescriptor.PatternType.PREFIX); + setPattern(MethodDescriptor.PatternType.SUFFIX); + break; + default: + throw new IllegalArgumentException("ERROR: wrong pattern type " + + patternType); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/method/SignatureType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/method/SignatureType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.compilercontrol.share.method; + +import jdk.test.lib.Utils; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.Arrays; + +/** + * This class represents a signature of the method + */ +public class SignatureType extends MethodElementType { + public SignatureType(Executable method) { + super(MethodDescriptor.Separator.NONE); + // Get parameters + Class[] types = method.getParameterTypes(); + String[] parameterTypes = new String[types.length]; + for (int i = 0; i < types.length; i++) { + parameterTypes[i] = Utils.toJVMTypeSignature(types[i]); + } + // Get return value + String returnType; + if (method instanceof Method) { + returnType = Utils.toJVMTypeSignature(((Method) method) + .getReturnType()); + } else if (method instanceof Constructor) { + // Constructor returns void in VM + returnType = Utils.toJVMTypeSignature(void.class); + } else { + throw new Error(String.format("TESTBUG: wrong type of executable " + + "%s of class %s", method, method.getClass())); + } + // Create signature + setElement("(" + String.join("", parameterTypes)+ ")" + returnType); + regexp = element; + setPattern(MethodDescriptor.PatternType.EXACT); + separator = MethodDescriptor.Separator.NONE; + } + + @Override + public void setElement(String element) { + if (element.isEmpty()) { + setPattern(MethodDescriptor.PatternType.ANY); + } else { + super.setElement(element); + } + } + + @Override + public boolean isValid() { + if (element.isEmpty()) { + return true; + } + // Allowed primitive types + char[] baseTypes = {'B', 'C', 'D', 'F', 'I', 'J', 'S', 'Z'}; // sorted + // Parsing states + boolean isArray = false; + boolean isInsideSig = false; + boolean isClass = false; + + for (char ch : element.toCharArray()) { + if (ch == '(') { + if (isInsideSig) { + // Met another ( inside + return false; + } + isInsideSig = true; + } else if (ch == ')') { + if (!isInsideSig) { + // met another ) outside + return false; + } + isInsideSig = false; + } else if (ch == 'V') { + if (isInsideSig) { + // void type is allowed only as a return value + return false; + } + } else if (ch == 'L') { + // this is a beginning of class/interface + isClass = true; + // met actual type of array + isArray = false; + } else if (ch == '[') { + isArray = true; + } else if (isClass) { + if (!Character.isJavaIdentifierPart(ch)) { + if (ch == '/' || ch == '.') { + // separator met + } else if (ch == ';') { + // end of class/interface + isClass = false; + } else { + return false; + } + } + } else if (Arrays.binarySearch(baseTypes, ch) < 0) { + // if it doesn't belong to base types + return false; + } else { + // array of a base type + isArray = false; + } + } + return !(isArray || isInsideSig || isClass); + } + + @Override + public void setPattern(MethodDescriptor.PatternType patternType) { + switch (patternType) { + case PREFIX: + case SUFFIX: + case SUBSTRING: + // These patterns are not supported in Compiler Control + // Just use ANY pattern instead + case ANY: + regexp = "\\(.*\\).*"; + element = ""; + break; + case EXACT: + break; + default: + throw new IllegalArgumentException("ERROR: wrong pattern type " + + patternType); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/pool/MethodHolder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/pool/MethodHolder.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 pool; + +import jdk.test.lib.Pair; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * Represents a holder that contains test methods + */ +public abstract class MethodHolder { + /** + * Helper method to get executable for the specified method + * + * @param holder class that holds specified method + * @param name method name + * @param parameterTypes parameter types of the specified method + * @return {@link Method} instance + */ + public Method getMethod(MethodHolder holder, + String name, + Class... parameterTypes) { + try { + return holder.getClass().getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException e) { + throw new Error("TESTBUG: Can't get method " + name, e); + } + } + + /** + * Gets all test methods + * + * @return pairs of Executable and appropriate Callable + */ + public List>> getAllMethods() { + Class aClass = this.getClass(); + Object classInstance; + try { + classInstance = aClass.newInstance(); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG: unable to get new instance", e); + } + List>> pairs = new ArrayList<>(); + { + Method method = getMethod(this, "method", int.class, String[].class, + Integer.class, byte[].class, double[][].class); + Pair> pair = new Pair<>(method, + () -> { + // Make args + int a = 0; + String[] ss = {"a", "b", "c", "d"}; + Integer i = 1; + byte[] bb = {1, 2}; + double[][] dd = { + {1.618033, 3.141592}, + {2.718281, 0.007874} + }; + // Invoke method + method.invoke(classInstance, a, ss, i, bb, dd); + return true; + }); + pairs.add(pair); + } + { + Method method = getMethod(this, "method"); + Pair> pair = new Pair<>(method, + () -> { + method.invoke(classInstance); + return true; + }); + pairs.add(pair); + } + { + Method method = getMethod(this, "smethod"); + Pair> pair = new Pair<>(method, + () -> method.invoke(classInstance)); + pairs.add(pair); + } + { + Method method = getMethod(this, "smethod", int.class, int[].class); + Pair> pair = new Pair<>(method, + () -> { + int[] array = {1, 2, 3}; + return method.invoke(classInstance, 42, array); + }); + pairs.add(pair); + } + { + Method method = getMethod(this, "smethod", Integer.class); + Pair> pair = new Pair<>(method, + () -> method.invoke(classInstance, 100)); + pairs.add(pair); + } + return pairs; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/pool/PoolHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/pool/PoolHelper.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 pool; + +import jdk.test.lib.Pair; +import pool.MethodHolder; +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * This is a helper class that provides tests with methods + */ +public class PoolHelper extends MethodHolder { + private static final List>> METHODS; + + /** + * Filters only those methods who belong to Klass or its internal class + * Internal and named as "method" or is a constructor + */ + public static final Predicate METHOD_FILTER = executable -> { + String methodName = executable.getName(); + String className = executable.getDeclaringClass().getName(); + return className.matches(".*(Klass)(\\$Internal)?") && + (methodName.equals("method") || + methodName.equals(className)); // if method is + }; + + static { + METHODS = new ArrayList<>(); + List holders = new ArrayList<>(); + holders.add(new pool.sub.Klass()); + holders.add(new pool.sub.KlassDup()); + holders.add(new pool.subpack.Klass()); + holders.add(new pool.subpack.KlassDup()); + holders.add(new pool.sub.Klass.Internal()); + holders.add(new pool.subpack.KlassDup.Internal()); + for (MethodHolder holder : holders) { + METHODS.addAll(holder.getAllMethods()); + } + } + + /** + * Gets all methods from the pool using specified filter + * + * @param filter method filter + * @return pairs of Executable and appropriate Callable + */ + public List>> getAllMethods( + Predicate filter) { + return getAllMethods().stream() + .filter(pair -> filter.test(pair.first)) + .collect(Collectors.toList()); + } + + /** + * Gets all methods from the pool + * + * @return pairs of Executable and appropriate Callable + */ + @Override + public List>> getAllMethods() { + return METHODS; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/pool/sub/Klass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/pool/sub/Klass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 pool.sub; + +import jdk.test.lib.Pair; +import pool.MethodHolder; + +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * Simple class with methods to test signatures + */ +public class Klass extends MethodHolder { + public void method(int a, String[] ss, Integer i, byte[] bb, double[][] dd) { } + + public void method() { } + + public static String smethod() { + return "ABC"; + } + + public static String smethod(int iarg, int[] aarg) { + return "ABC"; + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } + + // Internal class and constructor + public static class Internal extends MethodHolder { + public Internal() { } + + public Double method(Float fl) { return Double.valueOf(fl); } + + public Double methodDup() { + return Math.exp(1.0); + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } + + @Override + public List>> getAllMethods() { + List>> pairs = new ArrayList<>(); + Pair> pair = new Pair<> + (getMethod(this, "method", Float.class), + () -> this.method(3.141592f)); + pairs.add(pair); + pair = new Pair<>(getMethod(this, "methodDup"), this::methodDup); + pairs.add(pair); + pair = new Pair<>(getMethod(this, "smethod", Integer.class), + () -> smethod(1024)); + pairs.add(pair); + try { + pair = new Pair<>(this.getClass().getConstructor(), + Internal::new); + pairs.add(pair); + } catch (NoSuchMethodException e) { + throw new Error("TESTBUG: unable to get constructor"); + } + return pairs; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/pool/sub/KlassDup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/pool/sub/KlassDup.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 pool.sub; + +import pool.MethodHolder; + +/** + * Simple class with methods to test signatures + * This class has Dup suffix in the name to test suffix patterns like Klass*. + * Such patterns should match both Klass and KlassDup + */ +public class KlassDup extends MethodHolder { + public void method(int a, String[] ss, Integer i, byte[] bb, double[][] dd) { } + + public void method() { } + + public static String smethod() { + return "ABC"; + } + + public static String smethod(int iarg, int[] aarg) { + return "ABC"; + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/pool/subpack/Klass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/pool/subpack/Klass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 pool.subpack; + +import pool.MethodHolder; + +/** + * Simple class with methods to test signatures + * This is a clone of the pool.sub.Klass, but without inner class + * This class has different package name to test prefix patterns like *Klass. + * *Klass patern should match both pool.sub.Klass and pool.subpack.Klass + */ +public class Klass extends MethodHolder { + public void method(int a, String[] ss, Integer i, byte[] bb, double[][] dd) { } + + public void method() { } + + public static String smethod() { + return "ABC"; + } + + public static String smethod(int iarg, int[] aarg) { + return "ABC"; + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/compilercontrol/share/pool/subpack/KlassDup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/compilercontrol/share/pool/subpack/KlassDup.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 pool.subpack; + +import jdk.test.lib.Pair; +import pool.MethodHolder; + +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +/** + * This is a clone of the pool.sub.Klass used to test pattern matching + * Full class name contains both suffix (Dup) and prefix (pool.subpack) + */ +public class KlassDup extends MethodHolder { + public void method(int a, String[] ss, Integer i, byte[] bb, double[][] dd) { } + + public void method() { } + + public static String smethod() { + return "ABC"; + } + + public static String smethod(int iarg, int[] aarg) { + return "ABC"; + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } + + // Internal class and constructor + public static class Internal extends MethodHolder { + public Internal() { } + + public Double method(Float fl) { return Double.valueOf(fl); } + + public Double methodDup() { + return Math.exp(1.0); + } + + public static Integer smethod(Integer arg) { + Integer var = 1024; + return arg + var; + } + + @Override + public List>> getAllMethods() { + List>> pairs = new ArrayList<>(); + Pair> pair = new Pair<> + (getMethod(this, "method", Float.class), + () -> this.method(3.141592f)); + pairs.add(pair); + pair = new Pair<>(getMethod(this, "methodDup"), this::methodDup); + pairs.add(pair); + pair = new Pair<>(getMethod(this, "smethod", Integer.class), + () -> smethod(1024)); + pairs.add(pair); + try { + pair = new Pair<>(this.getClass().getConstructor(), + Internal::new); + pairs.add(pair); + } catch (NoSuchMethodException e) { + throw new Error("TESTBUG: unable to get constructor"); + } + return pairs; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary / + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.positive=true + * -XX:+EnableJVMCI + * compiler.jvmci.JVM_GetJVMCIRuntimeTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.positive=false + * -XX:-EnableJVMCI + * compiler.jvmci.JVM_GetJVMCIRuntimeTest + + */ + +package compiler.jvmci; + +import jdk.vm.ci.runtime.JVMCI; +import jdk.test.lib.Asserts; + +import java.lang.reflect.Method; + +public class JVM_GetJVMCIRuntimeTest { + private static final boolean IS_POSITIVE = Boolean.getBoolean( + "compiler.jvmci.JVM_GetJVMCIRuntimeTest.positive"); + + private final Method initializeRuntime; + + public static void main(String[] args) { + new JVM_GetJVMCIRuntimeTest().runTest(); + } + + private void runTest() { + Object result; + try { + result = invoke(); + } catch (InternalError e) { + if (IS_POSITIVE) { + throw new AssertionError("unexpected exception", e); + } + return; + } + if (!IS_POSITIVE) { + throw new AssertionError("didn't get expected exception"); + } + Asserts.assertNotNull(result, + "initializeRuntime returned null"); + Asserts.assertEQ(result, invoke(), + "initializeRuntime returns different results"); + + } + private Object invoke() { + Object result; + try { + result = initializeRuntime.invoke(JVMCI.class); + } catch (ReflectiveOperationException e) { + throw new Error("can't invoke initializeRuntime", e); + } + return result; + } + + private JVM_GetJVMCIRuntimeTest() { + Method method; + try { + method = JVMCI.class.getDeclaredMethod("initializeRuntime"); + method.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new Error("can't find JVMCI::initializeRuntime", e); + } + initializeRuntime = method; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.SecurityRestrictionsTest + * NO_SEC_MAN + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.SecurityRestrictionsTest + * NO_PERM + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.SecurityRestrictionsTest + * ALL_PERM + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.SecurityRestrictionsTest + * NO_JVMCI_ACCESS_PERM + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * compiler.jvmci.SecurityRestrictionsTest + * NO_JVMCI + */ + +package compiler.jvmci; + +import jdk.vm.ci.hotspot.CompilerToVM; +import jdk.test.lib.Utils; +import java.lang.InternalError; +import java.security.AccessControlException; +import java.security.Permission; +import java.util.PropertyPermission; +import java.util.function.Consumer; + +public class SecurityRestrictionsTest { + + public static void main(String[] args) { + try { + // to init Utils before call SecurityManager + Class.forName(Utils.class.getName(), true, + Utils.class.getClassLoader()); + } catch (ClassNotFoundException e) { + throw new Error("[TEST BUG]: jdk.test.lib.Utils not found", e); + } + try { + TestCase mode = TestCase.valueOf(args[0]); + mode.run(); + } catch (IllegalArgumentException e) { + throw new Error("[TEST BUG]: Unknown mode " + args[0], e); + } + } + + private enum TestCase { + NO_SEC_MAN, + NO_JVMCI { + @Override + public Class getExpectedException() { + return InternalError.class; + } + }, + ALL_PERM { + @Override + public SecurityManager getSecurityManager() { + return new SecurityManager() { + @Override + public void checkPermission(Permission perm) { + } + }; + } + }, + NO_PERM { + @Override + public SecurityManager getSecurityManager() { + return new SecurityManager(); + } + + @Override + public Class getExpectedException() { + return AccessControlException.class; + } + }, + NO_JVMCI_ACCESS_PERM { + @Override + public SecurityManager getSecurityManager() { + return new SecurityManager() { + @Override + public void checkPermission(Permission perm) { + if (isJvmciPermission(perm)) { + super.checkPermission(perm); + } + } + + @Override + public void checkPropertyAccess(String key) { + if (key.startsWith(JVMCI_PROP_START)) { + super.checkPropertyAccess(key); + } + } + }; + } + + private boolean isJvmciPermission(Permission perm) { + String name = perm.getName(); + boolean isJvmciRuntime = perm instanceof RuntimePermission + && (JVMCI_SERVICES.equals(name) + || name.startsWith(JVMCI_RT_PERM_START)); + boolean isJvmciProperty = perm instanceof PropertyPermission + && name.startsWith(JVMCI_PROP_START); + return isJvmciRuntime || isJvmciProperty; + } + + @Override + public Class getExpectedException() { + return AccessControlException.class; + } + }; + + public void run() { + System.setSecurityManager(getSecurityManager()); + Consumer exceptionCheck = e -> { + if (e == null) { + if (getExpectedException() != null) { + String message = name() + ": Didn't get expected exception " + + getExpectedException(); + throw new AssertionError(message); + } + } else { + String message = name() + ": Got unexpected exception " + + e.getClass().getSimpleName(); + if (getExpectedException() == null){ + throw new AssertionError(message, e); + } + + Throwable t = e; + while (t.getCause() != null) { + t = t.getCause(); + } + if (!getExpectedException().isAssignableFrom(t.getClass())) { + message += " instead of " + getExpectedException() + .getSimpleName(); + throw new AssertionError(message, e); + } + } + }; + Utils.runAndCheckException(CompilerToVM::new, exceptionCheck); + } + + public SecurityManager getSecurityManager() { + return null; + } + + public Class getExpectedException() { + return null; + } + + private static final String JVMCI_RT_PERM_START + = "accessClassInPackage.jdk.vm.ci"; + private static final String JVMCI_SERVICES = "jvmciServices"; + private static final String JVMCI_PROP_START = "jvmci."; + + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/CTVMUtilities.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/CTVMUtilities.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common; + +import java.lang.reflect.Field; +import java.lang.reflect.Executable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; + +public class CTVMUtilities { + /* + * A method to return HotSpotResolvedJavaMethod object using class object + * and method as input + */ + public static HotSpotResolvedJavaMethodImpl getResolvedMethod(Class cls, + Executable method) { + if (!(method instanceof Method || method instanceof Constructor)) { + throw new Error("wrong executable type " + method.getClass()); + } + Field slotField; + int slot; + try { + slotField = method.getClass().getDeclaredField("slot"); + boolean old = slotField.isAccessible(); + slotField.setAccessible(true); + slot = slotField.getInt(method); + slotField.setAccessible(old); + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG: Can't get slot field", e); + } + return CompilerToVMHelper.getResolvedJavaMethodAtSlot(cls, slot); + } + + public static HotSpotResolvedJavaMethodImpl getResolvedMethod( + Executable method) { + return getResolvedMethod(method.getDeclaringClass(), method); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/CompilerToVMHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/CompilerToVMHelper.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.SpeculationLog; + +/* + * A simple "proxy" class to get test access to CompilerToVM package-private methods + */ +public class CompilerToVMHelper { + public static final CompilerToVM CTVM = new CompilerToVM(); + + public static byte[] getBytecode(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getBytecode(method); + } + + public static int getExceptionTableLength(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getExceptionTableLength(method); + } + + public static long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getExceptionTableStart(method); + } + + public static boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method) { + return CTVM.canInlineMethod(method); + } + + public static boolean shouldInlineMethod(HotSpotResolvedJavaMethodImpl method) { + return CTVM.shouldInlineMethod(method); + } + + public static HotSpotResolvedJavaMethodImpl findUniqueConcreteMethod( + HotSpotResolvedObjectTypeImpl actualHolderType, + HotSpotResolvedJavaMethodImpl method) { + return CTVM.findUniqueConcreteMethod(actualHolderType, method); + } + + public static HotSpotResolvedObjectTypeImpl getImplementor(HotSpotResolvedObjectTypeImpl type) { + return CTVM.getImplementor(type); + } + + public static boolean methodIsIgnoredBySecurityStackWalk(HotSpotResolvedJavaMethodImpl method) { + return CTVM.methodIsIgnoredBySecurityStackWalk(method); + } + + public static HotSpotResolvedObjectTypeImpl lookupType(String name, + Class accessingClass, boolean resolve) { + return CTVM.lookupType(name, accessingClass, resolve); + } + + public static Object resolveConstantInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.resolveConstantInPool(constantPool, cpi); + } + + public static Object resolvePossiblyCachedConstantInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.resolvePossiblyCachedConstantInPool(constantPool, cpi); + } + + public static int lookupNameAndTypeRefIndexInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupNameAndTypeRefIndexInPool(constantPool, cpi); + } + + public static String lookupNameInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupNameInPool(constantPool, cpi); + } + + public static String lookupSignatureInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupSignatureInPool(constantPool, cpi); + } + + public static int lookupKlassRefIndexInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupKlassRefIndexInPool(constantPool, cpi); + } + + public static Object lookupKlassInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupKlassInPool(constantPool, cpi); + } + + public static HotSpotResolvedJavaMethodImpl lookupMethodInPool( + HotSpotConstantPool constantPool, int cpi, byte opcode) { + return CTVM.lookupMethodInPool(constantPool, cpi, opcode); + } + + public static void resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, int cpi) { + CTVM.resolveInvokeDynamicInPool(constantPool, cpi); + } + + public static void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi) { + CTVM.resolveInvokeHandleInPool(constantPool, cpi); + } + + public static HotSpotResolvedObjectTypeImpl resolveTypeInPool( + HotSpotConstantPool constantPool, int cpi) throws LinkageError { + return CTVM.resolveTypeInPool(constantPool, cpi); + } + + public static HotSpotResolvedObjectTypeImpl resolveFieldInPool( + HotSpotConstantPool constantPool, int cpi, byte opcode, long[] info) { + return CTVM.resolveFieldInPool(constantPool, cpi, opcode, info); + } + + public static int constantPoolRemapInstructionOperandFromCache( + HotSpotConstantPool constantPool, int cpci) { + return CTVM.constantPoolRemapInstructionOperandFromCache(constantPool, cpci); + } + + public static Object lookupAppendixInPool(HotSpotConstantPool constantPool, int cpi) { + return CTVM.lookupAppendixInPool(constantPool, cpi); + } + + public static int installCode(TargetDescription target, + HotSpotCompiledCode compiledCode, InstalledCode code, SpeculationLog speculationLog) { + return CTVM.installCode(target, compiledCode, code, speculationLog); + } + + public static int getMetadata(TargetDescription target, + HotSpotCompiledCode compiledCode, HotSpotMetaData metaData) { + return CTVM.getMetadata(target, compiledCode, metaData); + } + + public static void notifyCompilationStatistics(int id, + HotSpotResolvedJavaMethodImpl method, boolean osr, + int processedBytecodes, long time, long timeUnitsPerSecond, + InstalledCode installedCode) { + CTVM.notifyCompilationStatistics(id, method, osr, processedBytecodes, + time, timeUnitsPerSecond, installedCode); + } + + public static void resetCompilationStatistics() { + CTVM.resetCompilationStatistics(); + } + + public static long initializeConfiguration() { + return CTVM.initializeConfiguration(); + } + + public static HotSpotResolvedJavaMethodImpl resolveMethod( + HotSpotResolvedObjectTypeImpl exactReceiver, + HotSpotResolvedJavaMethodImpl method, + HotSpotResolvedObjectTypeImpl caller) { + return CTVM.resolveMethod(exactReceiver, method, caller); + } + + public static HotSpotResolvedJavaMethodImpl getClassInitializer( + HotSpotResolvedObjectTypeImpl type) { + return CTVM.getClassInitializer(type); + } + + public static boolean hasFinalizableSubclass(HotSpotResolvedObjectTypeImpl type) { + return CTVM.hasFinalizableSubclass(type); + } + + public static HotSpotResolvedJavaMethodImpl getResolvedJavaMethodAtSlot(Class holder, + int slot) { + return CTVM.getResolvedJavaMethodAtSlot(holder, slot); + } + + public static long getMaxCallTargetOffset(long address) { + return CTVM.getMaxCallTargetOffset(address); + } + + public static String disassembleCodeBlob(long codeBlob) { + return CTVM.disassembleCodeBlob(codeBlob); + } + + public static StackTraceElement getStackTraceElement( + HotSpotResolvedJavaMethodImpl method, int bci) { + return CTVM.getStackTraceElement(method, bci); + } + + public static Object executeInstalledCode(Object[] args, + InstalledCode installedCode) throws InvalidInstalledCodeException { + return CTVM.executeInstalledCode(args, installedCode); + } + + public static long[] getLineNumberTable(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getLineNumberTable(method); + } + + public static int getLocalVariableTableLength(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getLocalVariableTableLength(method); + } + + public static long getLocalVariableTableStart(HotSpotResolvedJavaMethodImpl method) { + return CTVM.getLocalVariableTableStart(method); + } + + public static Object readUncompressedOop(long address) { + return CTVM.readUncompressedOop(address); + } + + public static void doNotInlineOrCompile(HotSpotResolvedJavaMethodImpl method) { + CTVM.doNotInlineOrCompile(method); + } + + public static void reprofile(HotSpotResolvedJavaMethodImpl method) { + CTVM.reprofile(method); + } + + public static void invalidateInstalledCode(InstalledCode installedCode) { + CTVM.invalidateInstalledCode(installedCode); + } + + public static long[] collectCounters() { + return CTVM.collectCounters(); + } + + public static boolean isMature(long metaspaceMethodData) { + return CTVM.isMature(metaspaceMethodData); + } + + public static int allocateCompileId(HotSpotResolvedJavaMethodImpl method, + int entryBCI) { + return CTVM.allocateCompileId(method, entryBCI); + } + + public static boolean hasCompiledCodeForOSR( + HotSpotResolvedJavaMethodImpl method, int entryBCI, int level) { + return CTVM.hasCompiledCodeForOSR(method, entryBCI, level); + } + + public static String getSymbol(long metaspaceSymbol) { + return CTVM.getSymbol(metaspaceSymbol); + } + + public static HotSpotStackFrameReference getNextStackFrame( + HotSpotStackFrameReference frame, + HotSpotResolvedJavaMethodImpl[] methods, int initialSkip) { + return CTVM.getNextStackFrame(frame, methods, initialSkip); + } + + public static void materializeVirtualObjects( + HotSpotStackFrameReference stackFrame, boolean invalidate) { + CTVM.materializeVirtualObjects(stackFrame, invalidate); + } + + public static int getVtableIndexForInterfaceMethod(HotSpotResolvedObjectTypeImpl type, + HotSpotResolvedJavaMethodImpl method) { + return CTVM.getVtableIndexForInterfaceMethod(type, method); + } + + public static boolean shouldDebugNonSafepoints() { + return CTVM.shouldDebugNonSafepoints(); + } + + public static void writeDebugOutput(byte[] bytes, int offset, int length) { + CTVM.writeDebugOutput(bytes, offset, length); + } + + public static void flushDebugOutput() { + CTVM.flushDebugOutput(); + } + + public static HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(Object base, + long displacement) { + return CTVM.getResolvedJavaMethod(base, displacement); + } + + public static HotSpotConstantPool getConstantPool(Object base, long displacement) { + return CTVM.getConstantPool(base, displacement); + } + + public static HotSpotResolvedObjectTypeImpl getResolvedJavaType(Object base, + long displacement, boolean compressed) { + return CTVM.getResolvedJavaType(base, displacement, compressed); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/JVMCIHelpers.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/JVMCIHelpers.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; +import jdk.vm.ci.compiler.Compiler; +import jdk.vm.ci.compiler.CompilerFactory; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCIRuntime; + +/* + * A stub classes to be able to use jvmci + */ +public class JVMCIHelpers { + + public static class EmptyVMEventListener implements HotSpotVMEventListener { + // just empty, using default interface methods + } + + public static class EmptyHotspotCompiler implements Compiler { + + @Override + public void compileMethod(ResolvedJavaMethod method, int entryBCI, + long jvmciEnv, int id) { + // do nothing + } + } + + public static class EmptyCompilerFactory implements CompilerFactory { + + @Override + public String getCompilerName() { + return "EmptyCompiler"; + } + + @Override + public Architecture initializeArchitecture(Architecture arch) { + return arch; + } + + @Override + public Compiler createCompiler(JVMCIRuntime runtime) { + return new EmptyHotspotCompiler(); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.Compiler --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.Compiler Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.CompilerFactory --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.compiler.CompilerFactory Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.hotspot.HotSpotVMEventListener --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/services/jdk.vm.ci.hotspot.HotSpotVMEventListener Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +compiler.jvmci.common.JVMCIHelpers$EmptyVMEventListener diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/AbstractClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/AbstractClass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public abstract class AbstractClass { + public static final long initTime = System.currentTimeMillis(); + public abstract void abstractMethod(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/AbstractClassExtender.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/AbstractClassExtender.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class AbstractClassExtender extends AbstractClass { + @Override + public void abstractMethod() { + // empty + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementer.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class AnotherSingleImplementer implements AnotherSingleImplementerInterface { + + @Override + public void interfaceMethod() { + // empty + } + + public void nonInterfaceMethod() { + // empty + } + + @Override + public void finalize() throws Throwable { + super.finalize(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementerInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/AnotherSingleImplementerInterface.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public interface AnotherSingleImplementerInterface { + public static final long initTime = System.currentTimeMillis(); + + default void defaultMethod() { + // empty + } + + void interfaceMethod(); + + void finalize() throws Throwable; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/DoNotExtendClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/DoNotExtendClass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class DoNotExtendClass { + // empty +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/DoNotImplementInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/DoNotImplementInterface.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public interface DoNotImplementInterface { + // empty +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class MultiSubclassedClass { + // empty +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass1.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class MultiSubclassedClassSubclass1 extends MultiSubclassedClass { + // empty +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/MultiSubclassedClassSubclass2.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class MultiSubclassedClassSubclass2 extends MultiSubclassedClass { + // empty +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public abstract class MultipleAbstractImplementer + implements MultipleImplementersInterface { + + public abstract void abstractMethod(); + + @Override + public void finalize() throws Throwable { + super.finalize(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer1.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer1.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class MultipleImplementer1 implements MultipleImplementersInterface { + + @Override + public void defaultMethod() { + // empty + } + + @Override + public void testMethod() { + // empty + } + @Override + public void finalize() throws Throwable { + super.finalize(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class MultipleImplementer2 implements MultipleImplementersInterface { + + private static int intStaticField = INT_CONSTANT; + static long longStaticField = LONG_CONSTANT; + static float floatStaticField = FLOAT_CONSTANT; + static double doubleStaticField = DOUBLE_CONSTANT; + public static String stringStaticField = STRING_CONSTANT; + protected static Object objectStaticField = OBJECT_CONSTANT; + + public int intField = INT_CONSTANT; + private long longField = LONG_CONSTANT; + protected float floatField = FLOAT_CONSTANT; + double doubleField = DOUBLE_CONSTANT; + String stringField = STRING_CONSTANT; + Object objectField = OBJECT_CONSTANT; + + public MultipleImplementer2() { + intField = Integer.MAX_VALUE; + longField = Long.MAX_VALUE; + floatField = Float.MAX_VALUE; + doubleField = Double.MAX_VALUE; + stringField = "Message"; + objectField = new Object(); + } + + @Override + public void testMethod() { + // empty + } + + @Override + public void finalize() throws Throwable { + super.finalize(); + } + + public void interfaceMethodReferral2(MultipleImplementersInterface obj) { + obj.interfaceMethodReferral(obj); + } + + public void lambdaUsingMethod2() { + Thread t = new Thread(this::testMethod); + t.start(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public interface MultipleImplementersInterface { + + int INT_CONSTANT = Integer.MAX_VALUE; + long LONG_CONSTANT = Long.MAX_VALUE; + float FLOAT_CONSTANT = Float.MAX_VALUE; + double DOUBLE_CONSTANT = Double.MAX_VALUE; + String STRING_CONSTANT = "Hello"; + Object OBJECT_CONSTANT = new Object(); + + default void defaultMethod() { + // empty + } + + void testMethod(); + + default void finalize() throws Throwable { + // empty + } + + default void interfaceMethodReferral(MultipleImplementersInterface obj) { + obj.defaultMethod(); + } + + default void lambdaUsingMethod() { + Thread t = new Thread(this::defaultMethod); + t.start(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterfaceExtender.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterfaceExtender.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public interface MultipleImplementersInterfaceExtender + extends MultipleImplementersInterface { + // provide default implementation for parent interface + @Override + default void testMethod() { + // empty + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/PackagePrivateClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/PackagePrivateClass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +class PackagePrivateClass { + // empty +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/SimpleClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/SimpleClass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +// just a most common simple class with method "testMethod" to use anywhere +public class SimpleClass { + + public void testMethod() { + // empty + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/SingleImplementer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/SingleImplementer.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class SingleImplementer implements SingleImplementerInterface { + public static final long initTime = System.currentTimeMillis(); + + @Override + public void interfaceMethod() { + // empty + } + + public void nonInterfaceMethod() { + // empty + } + + @Override + public void finalize() throws Throwable { + super.finalize(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/SingleImplementerInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/SingleImplementerInterface.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public interface SingleImplementerInterface { + public static final long initTime = System.currentTimeMillis(); + + default void defaultMethod() { + // empty + } + + void interfaceMethod(); + + void finalize() throws Throwable; +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/SingleSubclass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/SingleSubclass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class SingleSubclass extends SingleSubclassedClass { + public void usualMethod() { + // empty + } + + @Override + public void overridenMethod() { + // empty + } + + private void privateMethod() { + // empty + } + + public static void staticMethod() { + // empty + } + + protected void protectedMethod() { + // empty + } + + void defaultAccessMethod() { + // empty + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/SingleSubclassedClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/SingleSubclassedClass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +public class SingleSubclassedClass { + public void inheritedMethod() { + // empty + } + + public void overridenMethod() { + //empty + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/common/testcases/TestCase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/common/testcases/TestCase.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.common.testcases; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.ArrayList; +import java.util.Set; + +/** + * A test case for tests in compiler.jvmci.compilerToVM package. + */ +public class TestCase { + private static final Class[] CLASSES = { + AbstractClass.class, + AbstractClassExtender.class, + AnotherSingleImplementer.class, + AnotherSingleImplementerInterface.class, + DoNotExtendClass.class, + DoNotImplementInterface.class, + MultipleAbstractImplementer.class, + MultipleImplementer1.class, + MultipleImplementer2.class, + MultipleImplementersInterface.class, + MultipleImplementersInterfaceExtender.class, + MultiSubclassedClass.class, + MultiSubclassedClassSubclass1.class, + MultiSubclassedClassSubclass2.class, + PackagePrivateClass.class, + SimpleClass.class, + SingleImplementer.class, + SingleImplementerInterface.class, + SingleSubclass.class, + SingleSubclassedClass.class + }; + + public static Collection> getAllClasses() { + return Arrays.asList(CLASSES); + } + + public static Collection getAllExecutables() { + Set result = new HashSet<>(); + for (Class aClass : CLASSES) { + result.addAll(Arrays.asList(aClass.getMethods())); + result.addAll(Arrays.asList(aClass.getConstructors())); + } + return result; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:-BackgroundCompilation + * compiler.jvmci.compilerToVM.AllocateCompileIdTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.HashSet; + +import compiler.jvmci.common.testcases.TestCase; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Pair; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; + +public class AllocateCompileIdTest { + + private final HashSet ids = new HashSet<>(); + + public static void main(String[] args) { + AllocateCompileIdTest test = new AllocateCompileIdTest(); + createTestCasesCorrectBci().forEach(test::runSanityCorrectTest); + createTestCasesIncorrectBci().forEach(test::runSanityIncorrectTest); + } + + + private static List createTestCasesCorrectBci() { + List result = new ArrayList<>(); + try { + Class aClass = DummyClass.class; + Method method = aClass.getMethod("withLoop"); + result.add(new CompileCodeTestCase(method, 17)); + result.add(new CompileCodeTestCase(method, -1)); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG : " + e, e); + } + return result; + } + + + private static List>> + createTestCasesIncorrectBci() { + List>> result + = new ArrayList<>(); + + try { + Class aClass = DummyClass.class; + Method method = aClass.getMethod("dummyInstanceFunction"); + // greater than bytecode.length + int[] bcis = new int[] {30, 50, 200}; + for (int bci : bcis) { + result.add(new Pair<>(new CompileCodeTestCase(method, bci), + IllegalArgumentException.class)); + } + bcis = new int[] {-4, -50, -200}; + for (int bci : bcis) { + result.add(new Pair<>(new CompileCodeTestCase(method, bci), + IllegalArgumentException.class)); + } + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG : " + e.getMessage(), e); + } + return result; + } + + private void runSanityCorrectTest(CompileCodeTestCase testCase) { + System.out.println(testCase); + Executable aMethod = testCase.executable; + int bci = testCase.bci; + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + int wbCompileID = getWBCompileID(testCase); + int id = CompilerToVMHelper.allocateCompileId(method, bci); + Asserts.assertNE(id, 0, testCase + " : zero compile id"); + + if (wbCompileID > 0) { + Asserts.assertGT(id, wbCompileID, testCase + + " : allocated 'compile id' not greater than existed"); + if (!ids.add(wbCompileID)) { + throw new AssertionError(String.format( + "%s : vm compilation allocated existed id -- %d", + testCase, id)); + } + } + if (!ids.add(id)) { + throw new AssertionError(String.format( + "%s : allocateCompileId returned existed id %d", + testCase, id)); + } + } + + private void runSanityIncorrectTest( + Pair> testCase) { + System.out.println(testCase); + Class exception = testCase.second; + Executable aMethod = testCase.first.executable; + int bci = testCase.first.bci; + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + Utils.runAndCheckException( + () -> CompilerToVMHelper.allocateCompileId(method, bci), + exception); + } + + private int getWBCompileID(CompileCodeTestCase testCase) { + NMethod nm = testCase.deoptimizeAndCompile(); + if (nm == null) { + throw new Error("[TEST BUG] cannot compile method " + testCase); + } + return nm.compile_id; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.CanInlineMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +public class CanInlineMethodTest { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + List testCases = createTestCases(); + testCases.forEach(CanInlineMethodTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + boolean canInline = CompilerToVMHelper.canInlineMethod(method); + boolean expectedCanInline = !WB.testSetDontInlineMethod(aMethod, + true); + Asserts.assertEQ(canInline, expectedCanInline, "Unexpected initial " + + "value of property 'can inline'"); + + canInline = CompilerToVMHelper.canInlineMethod(method); + Asserts.assertFalse(canInline, aMethod + "Unexpected value of " + + "property 'can inline' after setting 'do not inline' to true"); + WB.testSetDontInlineMethod(aMethod, false); + canInline = CompilerToVMHelper.canInlineMethod(method); + Asserts.assertTrue(canInline, "Unexpected value of " + + "property 'can inline' after setting 'do not inline' to false"); + } + + private static List createTestCases() { + List testCases = new ArrayList<>(); + + Class aClass = DummyClass.class; + testCases.addAll(Arrays.asList(aClass.getDeclaredMethods())); + testCases.addAll(Arrays.asList(aClass.getDeclaredConstructors())); + return testCases; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.CollectCountersTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -Xbootclasspath/a:. + * -XX:JVMCICounterSize=0 + * -Dcompiler.jvmci.compilerToVM.CollectCountersTest.expected=0 + * compiler.jvmci.compilerToVM.CollectCountersTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -Xbootclasspath/a:. + * -XX:JVMCICounterSize=11 + * -Dcompiler.jvmci.compilerToVM.CollectCountersTest.expected=11 + * compiler.jvmci.compilerToVM.CollectCountersTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class CollectCountersTest { + private static final int EXPECTED = Integer.getInteger( + "compiler.jvmci.compilerToVM.CollectCountersTest.expected"); + public static void main(String args[]) { + new CollectCountersTest().runTest(); + } + + private void runTest() { + long[] counters = CompilerToVMHelper.collectCounters(); + Asserts.assertNotNull(counters, "Expected not-null counters array"); + int ctvmData = counters.length; + Asserts.assertEQ(EXPECTED, ctvmData, "Unexpected counters amount"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/CompileCodeTestCase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/CompileCodeTestCase.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.compilerToVM; + +import compiler.testlibrary.CompilerUtils; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; + +import java.lang.reflect.Executable; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A test case for tests which require compiled code. + */ +public final class CompileCodeTestCase { + public static final Map, Object> RECEIVERS; + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final int COMP_LEVEL; + static { + int[] levels = CompilerUtils.getAvailableCompilationLevels(); + if (levels.length == 0) { + throw new Error("TESTBUG: no compilers available"); + } + COMP_LEVEL = levels[levels.length - 1]; + } + private static final Class[] CLASSES = { + Interface.class, + Dummy.class, + DummyEx.class}; + + public final Executable executable; + public final int bci; + private final boolean isOsr; + + public CompileCodeTestCase(Executable executable, int bci) { + this.executable = executable; + this.bci = bci; + isOsr = bci >= 0; + } + + public NMethod compile() { + return compile(COMP_LEVEL); + } + + public NMethod compile(int level) { + boolean enqueued = WB.enqueueMethodForCompilation(executable, + level, bci); + if (!enqueued) { + throw new Error(String.format( + "%s can't be enqueued for %scompilation on level %d", + executable, bci >= 0 ? "osr-" : "", level)); + } + Utils.waitForCondition(() -> WB.isMethodCompiled(executable, isOsr)); + return NMethod.get(executable, isOsr); + } + + public static List generate(int bci) { + ArrayList result = new ArrayList<>(); + for (Class aClass : CLASSES) { + for (Executable m : aClass.getDeclaredConstructors()) { + result.add(new CompileCodeTestCase(m, bci)); + } + Arrays.stream(aClass.getDeclaredMethods()) + .filter(m -> !Modifier.isAbstract(m.getModifiers())) + .filter(m -> !Modifier.isNative(m.getModifiers())) + .map(m -> new CompileCodeTestCase(m, bci)) + .forEach(result::add); + } + return result; + } + + public NMethod toNMethod() { + return NMethod.get(executable, isOsr); + } + + @Override + public String toString() { + return "CompileCodeTestCase{" + + "executable=" + executable + + ", bci=" + bci + + '}'; + } + + public void deoptimize() { + WB.deoptimizeMethod(executable, isOsr); + } + + public NMethod deoptimizeAndCompile() { + deoptimize(); + return compile(); + } + + // classes which are used as "input" data in test cases + private static interface Interface { + Interface interfaceMethod(); + default Long defaultOverriddenMethod(Interface[] array) { + return array == null ? 0L : array.length; + } + default int defaultMethod(Object o) { + return o != null ? o.hashCode() : 0; + } + } + + private static abstract class Dummy implements Interface { + protected Dummy() { + } + + private static void staticMethod() { + } + + Dummy instanceMethod(int i) { + return null; + } + + abstract Object abstractMethod(double d); + + @Override + public Long defaultOverriddenMethod(Interface[] array) { + return 0L; + } + } + + public static class DummyEx extends Dummy { + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return 0; + } + + public DummyEx() { + } + + protected Dummy instanceMethod(int i) { + if (i == 0) { + return this; + } + return null; + } + + @Override + Object abstractMethod(double d) { + return this; + } + + @Override + public Interface interfaceMethod() { + return null; + } + } + + static { + Map, Object> map = new HashMap<>();; + map.put(CompileCodeTestCase.DummyEx.class, + new CompileCodeTestCase.DummyEx()); + map.put(CompileCodeTestCase.Dummy.class, + new CompileCodeTestCase.Dummy() { + @Override + public CompileCodeTestCase.Interface interfaceMethod() { + throw new AbstractMethodError(); + } + + @Override + Object abstractMethod(double d) { + throw new AbstractMethodError(); + } + }); + map.put(CompileCodeTestCase.Interface.class, + new CompileCodeTestCase.Interface() { + @Override + public CompileCodeTestCase.Interface interfaceMethod() { + throw new AbstractMethodError(); + } + }); + RECEIVERS = Collections.unmodifiableMap(map); + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.compilerToVM; + +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.internal.misc.SharedSecrets; +import sun.reflect.ConstantPool; + +/** + * Common class for jdk.vm.ci.hotspot.CompilerToVM constant pool tests + */ +public class ConstantPoolTestCase { + + private final Map typeTests; + + public static interface Validator { + void validate(HotSpotConstantPool constantPoolCTVM, ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int index); + } + + public ConstantPoolTestCase(Map typeTests) { + this.typeTests = new HashMap<>(); + this.typeTests.putAll(typeTests); + } + + private void messageOnFail(Throwable t, + ConstantPoolTestsHelper.ConstantTypes cpType, + ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). + getConstantPool(dummyClass.klass); + String msg = String.format("Test for %s constant pool entry of" + + " type %s", + dummyClass.klass, cpType.name()); + switch (cpType) { + case CONSTANT_CLASS: + case CONSTANT_STRING: + case CONSTANT_METHODTYPE: + String utf8 = constantPoolSS + .getUTF8At((int) dummyClass.cp.get(index).value); + msg = String.format("%s (%s) failed with %s", msg, utf8, t); + break; + case CONSTANT_INTEGER: + int intValue = constantPoolSS.getIntAt(index); + msg = String.format("%s (%d) failed with %s", msg, intValue, t); + break; + case CONSTANT_LONG: + long longValue = constantPoolSS.getLongAt(index); + msg = String.format("%s (%d) failed with %s", msg, longValue, t); + break; + case CONSTANT_FLOAT: + float floatValue = constantPoolSS.getFloatAt(index); + msg = String.format("%s (%E) failed with %s", msg, floatValue, t); + break; + case CONSTANT_DOUBLE: + double doubleValue = constantPoolSS.getDoubleAt(index); + msg = String.format("%s (%E) failed with %s", msg, doubleValue, t); + break; + case CONSTANT_UTF8: + String utf8Value = constantPoolSS.getUTF8At(index); + msg = String.format("%s (%s) failed with %s", msg, utf8Value, t); + break; + case CONSTANT_INVOKEDYNAMIC: + index = ((int[]) dummyClass.cp.get(index).value)[1]; + case CONSTANT_NAMEANDTYPE: + String name = constantPoolSS + .getUTF8At(((int[]) dummyClass.cp.get(index).value)[0]); + String type = constantPoolSS + .getUTF8At(((int[]) dummyClass.cp.get(index).value)[1]); + msg = String.format("%s (%s:%s) failed with %s", + msg, name, type, t); + break; + case CONSTANT_METHODHANDLE: + index = ((int[]) dummyClass.cp.get(index).value)[1]; + case CONSTANT_METHODREF: + case CONSTANT_INTERFACEMETHODREF: + case CONSTANT_FIELDREF: + int classIndex = ((int[]) dummyClass.cp.get(index).value)[0]; + int nameAndTypeIndex = ((int[]) dummyClass.cp.get(index).value)[1]; + String cName = constantPoolSS + .getUTF8At((int) dummyClass.cp.get(classIndex).value); + String mName = constantPoolSS + .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[0]); + String mType = constantPoolSS + .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[1]); + msg = String.format("%s (%s.%s:%s) failed with %s ", + msg, cName, mName, mType, t); + break; + default: + msg = String.format("Test bug: unknown constant type %s ", cpType); + } + throw new Error(msg + t.getMessage(), t); + } + + public void test() { + for (ConstantPoolTestsHelper.DummyClasses dummyClass + : ConstantPoolTestsHelper.DummyClasses.values()) { + System.out.printf("%nTesting dummy %s%n", dummyClass.klass); + HotSpotResolvedObjectTypeImpl holder = HotSpotResolvedObjectTypeImpl + .fromObjectClass(dummyClass.klass); + HotSpotConstantPool constantPoolCTVM = holder.getConstantPool(); + ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). + getConstantPool(dummyClass.klass); + for (Integer i : dummyClass.cp.keySet()) { + ConstantPoolTestsHelper.ConstantTypes cpType + = dummyClass.cp.get(i).type; + if (!typeTests.keySet().contains(cpType)) { + continue; + } + try { + typeTests.get(cpType).validate(constantPoolCTVM, + constantPoolSS, dummyClass, i); + } catch (Throwable t) { + messageOnFail(t, cpType, dummyClass, i); + } + } + } + } +} + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.MultipleImplementer2; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import java.util.HashMap; +import java.util.Map; + +/** + * Class contains hard-coded constant pool tables for dummy classes used for + * jdk.vm.ci.hotspot.CompilerToVM constant pool methods + */ +public class ConstantPoolTestsHelper { + + public enum ConstantTypes { + CONSTANT_CLASS, + CONSTANT_FIELDREF, + CONSTANT_METHODREF, + CONSTANT_INTERFACEMETHODREF, + CONSTANT_STRING, + CONSTANT_INTEGER, + CONSTANT_FLOAT, + CONSTANT_LONG, + CONSTANT_DOUBLE, + CONSTANT_NAMEANDTYPE, + CONSTANT_UTF8, + CONSTANT_METHODHANDLE, + CONSTANT_METHODTYPE, + CONSTANT_INVOKEDYNAMIC; + } + + public enum DummyClasses { + DUMMY_CLASS(MultipleImplementer2.class, CP_MAP_FOR_CLASS), + DUMMY_INTERFACE(MultipleImplementersInterface.class, CP_MAP_FOR_INTERFACE); + + public final Class klass; + public final Map cp; + + DummyClasses(Class klass, Map cp) { + this.klass = klass; + this.cp = cp; + } + } + + public static class ConstantPoolEntry { + + public final ConstantTypes type; + public final Object value; + + public ConstantPoolEntry(ConstantTypes type, Object value) { + this.type = type; + this.value = value; + } + } + + private static final Map CP_MAP_FOR_CLASS + = new HashMap<>(); + static { + CP_MAP_FOR_CLASS.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 68})); + CP_MAP_FOR_CLASS.put(2, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 69)); + CP_MAP_FOR_CLASS.put(3, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); + CP_MAP_FOR_CLASS.put(4, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 70})); + CP_MAP_FOR_CLASS.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807L)); + CP_MAP_FOR_CLASS.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38F)); + CP_MAP_FOR_CLASS.put(10, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308D)); + CP_MAP_FOR_CLASS.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 74)); + CP_MAP_FOR_CLASS.put(22, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 83)); + CP_MAP_FOR_CLASS.put(23, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 84})); + CP_MAP_FOR_CLASS.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{2, 85})); + CP_MAP_FOR_CLASS.put(26, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 91})); + CP_MAP_FOR_CLASS.put(29, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 94})); + CP_MAP_FOR_CLASS.put(35, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 100)); + CP_MAP_FOR_CLASS.put(68, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{54, 55})); + CP_MAP_FOR_CLASS.put(70, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{48, 37})); + CP_MAP_FOR_CLASS.put(84, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{59, 55})); + CP_MAP_FOR_CLASS.put(85, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{103, 63})); + CP_MAP_FOR_CLASS.put(91, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{106, 107})); + CP_MAP_FOR_CLASS.put(94, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{36, 37})); + CP_MAP_FOR_CLASS.put(104, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{110, 111})); + CP_MAP_FOR_CLASS.put(105, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{35, 112})); + CP_MAP_FOR_CLASS.put(110, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 113)); + CP_MAP_FOR_CLASS.put(111, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{114, 118})); + CP_MAP_FOR_CLASS.put(112, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{58, 55})); + } + + private static final Map CP_MAP_FOR_INTERFACE + = new HashMap<>(); + static { + CP_MAP_FOR_INTERFACE.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 48)); + CP_MAP_FOR_INTERFACE.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{13, 52})); + CP_MAP_FOR_INTERFACE.put(6, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 53)); + CP_MAP_FOR_INTERFACE.put(7, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 58})); + CP_MAP_FOR_INTERFACE.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 59})); + CP_MAP_FOR_INTERFACE.put(9, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 60})); + CP_MAP_FOR_INTERFACE.put(12, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{13, 63})); + CP_MAP_FOR_INTERFACE.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 64)); + CP_MAP_FOR_INTERFACE.put(17, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); + CP_MAP_FOR_INTERFACE.put(20, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807l)); + CP_MAP_FOR_INTERFACE.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38f)); + CP_MAP_FOR_INTERFACE.put(27, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308d)); + CP_MAP_FOR_INTERFACE.put(31, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 65)); + CP_MAP_FOR_INTERFACE.put(52, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{34, 35})); + CP_MAP_FOR_INTERFACE.put(55, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{6, 67})); + CP_MAP_FOR_INTERFACE.put(56, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODTYPE, 35)); + CP_MAP_FOR_INTERFACE.put(57, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{9, 5})); + CP_MAP_FOR_INTERFACE.put(58, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{68, 69})); + CP_MAP_FOR_INTERFACE.put(59, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{70, 71})); + CP_MAP_FOR_INTERFACE.put(60, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{72, 35})); + CP_MAP_FOR_INTERFACE.put(63, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{32, 33})); + CP_MAP_FOR_INTERFACE.put(67, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{73, 74})); + CP_MAP_FOR_INTERFACE.put(73, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 75)); + CP_MAP_FOR_INTERFACE.put(74, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{76, 80})); + CP_MAP_FOR_INTERFACE.put(77, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 82)); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run driver compiler.jvmci.compilerToVM.DebugOutputTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.ProcessTools; +import java.util.Arrays; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Utils; + +public class DebugOutputTest { + public static void main(String[] args) { + new DebugOutputTest().test(); + } + + private void test() { + for (TestCaseData testCase : TestCaseData.values()) { + System.out.println(testCase); + OutputAnalyzer oa; + try { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + /* use test options = */ true, + "-XX:+UnlockExperimentalVMOptions", + "-XX:+EnableJVMCI", + "-Xbootclasspath/a:.", + DebugOutputTest.Worker.class.getName(), + testCase.name()); + oa = ProcessTools.executeProcess(pb); + } catch (Exception e) { + e.printStackTrace(); + throw new Error("Problems running child process", e); + } + if (testCase.expectedException != null) { + oa.shouldHaveExitValue(1); + oa.shouldContain(testCase.expectedException.getName()); + } else { + oa.shouldHaveExitValue(0); + oa.shouldContain(new String(testCase.getExpected())); + } + } + } + + /** + * A list of test cases that are executed in forked VM + */ + private enum TestCaseData { + PART_ARRAY(100, 50), + FULL_ARRAY(0, 255), + EMPTY(0, 0), + NEGATIVE_LENGTH(0, Integer.MIN_VALUE, + ArrayIndexOutOfBoundsException.class), + NEGATIVE_OFFSET(-1, 255, + ArrayIndexOutOfBoundsException.class), + LEFT_BOUND(Integer.MIN_VALUE, 100, + ArrayIndexOutOfBoundsException.class), + RIGHT_BOUND(Integer.MAX_VALUE, 100, + ArrayIndexOutOfBoundsException.class), + BIG_LENGTH(0, Integer.MAX_VALUE, + ArrayIndexOutOfBoundsException.class), + NULL_POINTER(0, 0, + NullPointerException.class), + ; + + private static final int SIZE = 255; + private static final byte[] DATA = generate(); + public final int offset; + public final int length; + public final Class expectedException; + + private TestCaseData(int offset, int length, + Class expectedException) { + this.offset = offset; + this.length = length; + this.expectedException = expectedException; + } + + private TestCaseData(int offset, int length) { + this(offset, length, null); + } + + private static byte[] generate() { + byte[] byteArray = new byte[SIZE]; + for (int i = 0; i < SIZE; i++) { + byteArray[i] = (byte) (i + 1); + } + return byteArray; + } + + public byte[] getExpected() { + if (expectedException != null) { + return new byte[0]; + } + return Arrays.copyOfRange(TestCaseData.DATA, offset, + offset + length); + } + + @Override + public String toString() { + return "CASE: " + this.name(); + } + + public byte[] getData() { + if (equals(NULL_POINTER)) { + return null; + } else { + return DATA; + } + } + } + + public static class Worker { + public static void main(String[] args) { + for (String arg : args) { + TestCaseData tcase = TestCaseData.valueOf(arg); + CompilerToVMHelper.writeDebugOutput(tcase.getData(), + tcase.offset, tcase.length); + CompilerToVMHelper.flushDebugOutput(); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @ignore 8139700 + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.DisassembleCodeBlobTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.DisassembleCodeBlobTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.code.NMethod; + +import java.util.List; + +public class DisassembleCodeBlobTest { + + public static void main(String[] args) { + DisassembleCodeBlobTest test + = new DisassembleCodeBlobTest(); + List testCases + = CompileCodeTestCase.generate(/* bci = */ -1); + testCases.addAll(CompileCodeTestCase.generate(/* bci = */ 0)); + testCases.forEach(test::check); + test.checkNull(); + } + + private void checkNull() { + String str = CompilerToVMHelper.disassembleCodeBlob(0L); + Asserts.assertNull(str, "not null string returned for null pointer"); + } + + private void check(CompileCodeTestCase testCase) { + System.out.println(testCase); + // to have a clean state + NMethod nMethod = testCase.deoptimizeAndCompile(); + if (nMethod == null) { + throw new Error(testCase + " : method is not compiled"); + } + String str = CompilerToVMHelper.disassembleCodeBlob(nMethod.address); + if (str != null) { + Asserts.assertGT(str.length(), 0, + testCase + " : returned string has to be non-zero length"); + } + String str2 = CompilerToVMHelper.disassembleCodeBlob(nMethod.address); + Asserts.assertEQ(str, str2, + testCase + " : 2nd invocation returned different value"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.DoNotInlineOrCompileTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +public class DoNotInlineOrCompileTest { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + List testCases = createTestCases(); + testCases.forEach(DoNotInlineOrCompileTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + boolean canInline = CompilerToVMHelper.canInlineMethod(method); + Asserts.assertTrue(canInline, "Unexpected initial " + + "value of property 'can inline'"); + CompilerToVMHelper.doNotInlineOrCompile(method); + canInline = CompilerToVMHelper.canInlineMethod(method); + Asserts.assertFalse(canInline, aMethod + + " : can be inlined even after doNotInlineOrCompile'"); + } + + private static List createTestCases() { + List testCases = new ArrayList<>(); + + Class aClass = DummyClass.class; + testCases.addAll(Arrays.asList(aClass.getDeclaredMethods())); + testCases.addAll(Arrays.asList(aClass.getDeclaredConstructors())); + return testCases; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/DummyAbstractClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/DummyAbstractClass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.compilerToVM; + +abstract class DummyAbstractClass implements DummyInterface { + public abstract int dummyAbstractFunction(); +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/DummyClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/DummyClass.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.compilerToVM; + +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; + +import java.util.Random; + +class DummyClass extends DummyAbstractClass { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + int p1 = 5; + int p2 = 6; + + public int dummyInstanceFunction() { + String str1 = "123123123"; + double x = 3.14; + int y = Integer.parseInt(str1); + + return y / (int) x; + } + + public int dummyEmptyInstanceFunction() { + return 42; + } + + public static int dummyEmptyStaticFunction() { + return -42; + } + + @Override + public int dummyAbstractFunction() { + int z = p1 * p2; + return (int) (Math.cos(p2 - p1 + z) * 100); + } + + @Override + public void dummyFunction() { + dummyEmptyInstanceFunction(); + } + + public void withLoop() { + long tier4 = (Long) WB.getVMFlag("Tier4BackEdgeThreshold"); + for (long i = 0; i < tier4; ++i) { + randomProfile(); + } + } + + private double randomProfile() { + String str1 = "123123123"; + double x = 3.14; + int y = Integer.parseInt(str1); + + Random rnd = Utils.getRandomInstance(); + if (rnd.nextDouble() > 0.2) { + return y / (int) x; + } else { + return x / y; + } + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/DummyInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/DummyInterface.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.compilerToVM; + +interface DummyInterface { + void dummyFunction(); + + default int dummyDefaultFunction(int x, int y) { + int z = x * y; + return (int) (Math.cos(x - y + z) * 100); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,176 @@ +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.InvalidInstalledCodeException; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import jdk.test.lib.Pair; +import sun.hotspot.code.NMethod; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/* + * @test + * @bug 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest + */ + +public class ExecuteInstalledCodeTest { + + + public static void main(String[] args) { + ExecuteInstalledCodeTest test = new ExecuteInstalledCodeTest(); + List testCases = new ArrayList<>(); + testCases.addAll(CompileCodeTestCase.generate(/* bci = */ -1)); + testCases .stream() + // ignore of abstract class -- 8138793 + .filter(e -> !(e.executable instanceof Constructor + && Modifier.isAbstract( + e.executable.getDeclaringClass() + .getModifiers()))) + .forEach(test::checkSanity); + } + + private void checkSanity(CompileCodeTestCase testCase) { + System.out.println(testCase); + // to have a clean state + testCase.deoptimize(); + Pair reflectionResult; + Object[] args = getArguments(testCase.executable); + reflectionResult = invoke(testCase, args); + NMethod nMethod = testCase.compile(); + if (nMethod == null) { + throw new Error(testCase + " : nmethod is null"); + } + InstalledCode installedCode = new InstalledCode( + testCase.executable.getName()); + installedCode.setAddress(nMethod.address); + Object result = null; + Throwable expectedException = reflectionResult.second; + boolean gotException = true; + try { + args = addReceiver(testCase, args); + result = CompilerToVMHelper.executeInstalledCode( + args, installedCode); + if (testCase.executable instanceof Constructor) { + // doesn't have return value, it changes receiver + result = args[0]; + } + gotException = false; + } catch (InvalidInstalledCodeException e) { + throw new AssertionError( + testCase + " : unexpected InvalidInstalledCodeException", e); + } catch (Throwable t) { + if (expectedException == null) { + throw new AssertionError(testCase + + " : got unexpected execption : " + t.getMessage(), t); + } + + if (expectedException.getClass() != t.getClass()) { + System.err.println("exception from CompilerToVM:"); + t.printStackTrace(); + System.err.println("exception from reflection:"); + expectedException.printStackTrace(); + throw new AssertionError(String.format( + "%s : got unexpected different exceptions : %s != %s", + testCase, expectedException.getClass(), t.getClass())); + } + } + + Asserts.assertEQ(reflectionResult.first, result, testCase + + " : different return value"); + if (!gotException) { + Asserts.assertNull(expectedException, testCase + + " : expected exception hasn't been thrown"); + } + } + + private Object[] addReceiver(CompileCodeTestCase testCase, Object[] args) { + if (!Modifier.isStatic(testCase.executable.getModifiers())) { + // add instance as 0th arg + Object[] newArgs = new Object[args.length + 1]; + newArgs[0] = getReciever(testCase); + System.arraycopy(args, 0, newArgs, 1, args.length); + args = newArgs; + } + return args; + } + + private Object getReciever(CompileCodeTestCase testCase) { + return CompileCodeTestCase.RECEIVERS.get( + testCase.executable.getDeclaringClass()); + } + + public Pair invoke( + CompileCodeTestCase testCase, Object[] args) { + Executable executable = testCase.executable; + boolean old = executable.isAccessible(); + executable.setAccessible(true); + try { + try { + if (executable instanceof Method) { + Method m = (Method) executable; + return new Pair<>(m.invoke(getReciever(testCase), args), null); + } + + if (executable instanceof Constructor) { + Constructor c = (Constructor) executable; + return new Pair<>(c.newInstance(args), null); + } + } catch (InvocationTargetException e) { + return new Pair<>(null, e.getCause()); + } catch (Throwable e) { + return new Pair<>(null, e); + } + } finally { + executable.setAccessible(old); + } + throw new Error(executable + " has unsupported type " + + executable.getClass()); + } + + private Object[] getArguments(Executable method) { + Class[] params = method.getParameterTypes(); + Object[] result = new Object[params.length]; + int i = 0; + for (Class aClass : params) { + result[i++] = getArgument(aClass); + } + return result; + } + private static Map, Object> DEFAULT_VALUES = new HashMap<>(); + static { + DEFAULT_VALUES.put(boolean.class, false); + DEFAULT_VALUES.put(byte.class, (byte) 0); + DEFAULT_VALUES.put(short.class, (short) 0); + DEFAULT_VALUES.put(char.class, '\0'); + DEFAULT_VALUES.put(int.class, 0); + DEFAULT_VALUES.put(long.class, 0L); + DEFAULT_VALUES.put(float.class, 0.0f); + DEFAULT_VALUES.put(double.class, 0.0d); + } + private Object getArgument(Class aClass) { + if (aClass.isPrimitive()) { + return DEFAULT_VALUES.get(aClass); + } + return null; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.FindUniqueConcreteMethodTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.FindUniqueConcreteMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.MultipleImplementer1; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleSubclass; +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class FindUniqueConcreteMethodTest { + public static void main(String args[]) { + FindUniqueConcreteMethodTest test = new FindUniqueConcreteMethodTest(); + try { + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find method", e); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + // a public method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "usualMethod")); + // overriden method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "overridenMethod")); + // private method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "privateMethod")); + // protected method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "protectedMethod")); + // default(package-private) method + result.add(new TestCase(true, SingleSubclass.class, + SingleSubclass.class, "defaultAccessMethod")); + // default interface method redefined in implementer + result.add(new TestCase(true, MultipleImplementer1.class, + MultipleImplementer1.class, "defaultMethod")); + // interface method + result.add(new TestCase(true, MultipleImplementer1.class, + MultipleImplementer1.class, "testMethod")); + // default interface method not redefined in implementer + result.add(new TestCase(true, SingleImplementer.class, + SingleImplementerInterface.class, "defaultMethod")); + // static method + result.add(new TestCase(false, SingleSubclass.class, + SingleSubclass.class, "staticMethod")); + return result; + } + + private void runTest(TestCase tcase) throws NoSuchMethodException { + System.out.println(tcase); + Method method = tcase.holder.getDeclaredMethod(tcase.methodName); + HotSpotResolvedJavaMethodImpl testMethod = CTVMUtilities + .getResolvedMethod(tcase.reciever, method); + HotSpotResolvedObjectTypeImpl resolvedType = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.reciever), getClass(), + /* resolve = */ true); + HotSpotResolvedJavaMethodImpl concreteMethod = CompilerToVMHelper + .findUniqueConcreteMethod(resolvedType, testMethod); + Asserts.assertEQ(concreteMethod, tcase.isPositive ? testMethod : null, + "Unexpected concrete method for " + tcase.methodName); + } + + private static class TestCase { + public final Class reciever; + public final Class holder; + public final String methodName; + public final boolean isPositive; + + public TestCase(boolean isPositive, Class clazz, Class holder, + String methodName) { + this.reciever = clazz; + this.methodName = methodName; + this.isPositive = isPositive; + this.holder = holder; + } + + @Override + public String toString() { + return String.format("CASE: reciever=%s, holder=%s, method=%s," + + " isPositive=%s", reciever.getName(), + holder.getName(), methodName, isPositive); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetBytecodeTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.TestCase; +import java.lang.reflect.Executable; +import java.lang.reflect.Modifier; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.test.lib.Asserts; + +public class GetBytecodeTest { + + public static void main(String[] args) { + TestCase.getAllExecutables() + .forEach(GetBytecodeTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + byte[] bytecode = CompilerToVMHelper.getBytecode(method); + + int mods = aMethod.getModifiers(); + boolean shouldHasZeroLength = Modifier.isAbstract(mods) + || Modifier.isNative(mods); + boolean correctLength = (bytecode.length == 0 && shouldHasZeroLength) + || (bytecode.length > 0 && !shouldHasZeroLength); + + Asserts.assertTrue(correctLength, "Bytecode of '" + aMethod + "' has " + + bytecode.length + " length"); + + if (!shouldHasZeroLength) { + Asserts.assertTrue(containsReturn(bytecode), "Bytecode of '" + + aMethod + "' doesn't have any return statement"); + } + } + + private static boolean containsReturn(byte[] bytecode) { + for (byte b : bytecode) { + // cast unsigned byte to int + int value = (int) b & 0x000000FF; + switch (value) { + case Opcodes.RET: + case Opcodes.ARETURN: + case Opcodes.IRETURN: + case Opcodes.LRETURN: + case Opcodes.FRETURN: + case Opcodes.DRETURN: + case Opcodes.RETURN: + return true; + } + } + return false; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetClassInitializerTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetClassInitializerTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.AbstractClassExtender; +import compiler.jvmci.common.testcases.DoNotExtendClass; +import compiler.jvmci.common.testcases.MultipleImplementersInterfaceExtender; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import java.util.HashSet; +import java.util.Set; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class GetClassInitializerTest { + + public static void main(String args[]) { + GetClassInitializerTest test = new GetClassInitializerTest(); + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + // a simple class with initializer + result.add(new TestCase(SingleImplementer.class, true)); + // an interface with initializer + result.add(new TestCase(SingleImplementerInterface.class, true)); + // an abstract class with initializer + result.add(new TestCase(AbstractClass.class, true)); + // a class without initializer, extending class with initializer + result.add(new TestCase(AbstractClassExtender.class, false)); + // an interface without initializer + result.add(new TestCase(MultipleImplementersInterfaceExtender.class, false)); + // a class without initializer + result.add(new TestCase(DoNotExtendClass.class, false)); + return result; + } + + private void runTest(TestCase tcase) { + System.out.println(tcase); + String className = tcase.holder.getName(); + HotSpotResolvedObjectTypeImpl resolvedClazz = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.holder), + getClass(), /* resolve = */ true); + HotSpotResolvedJavaMethodImpl initializer = CompilerToVMHelper + .getClassInitializer(resolvedClazz); + if (tcase.isPositive) { + Asserts.assertNotNull(initializer, "Couldn't get initializer for " + + className); + Asserts.assertEQ(initializer.getName(), "", + "Unexpected initializer name for " + className); + } else { + Asserts.assertNull(initializer, "Unexpected: found initializer for " + + className); + } + } + + private static class TestCase { + public final Class holder; + public final boolean isPositive; + + public TestCase(Class clazz, boolean isPositive) { + this.holder = clazz; + this.isPositive = isPositive; + } + + @Override + public String toString() { + return "CASE: clazz=" + holder.getName() + + ", isPositive=" + isPositive; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.GetConstantPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetConstantPoolTest + */ +package compiler.jvmci.compilerToVM; + +import java.lang.reflect.Field; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.vm.ci.hotspot.MetaspaceWrapperObject; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +/** + * Tests for jdk.vm.ci.hotspot.CompilerToVM::getConstantPool method + */ +public class GetConstantPoolTest { + private static enum TestCase { + NULL_BASE { + @Override + HotSpotConstantPool getConstantPool() { + return CompilerToVMHelper.getConstantPool(null, + getPtrToCpAddress()); + } + }, + JAVA_METHOD_BASE { + @Override + HotSpotConstantPool getConstantPool() { + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, getPtrToCpAddress()); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + + return CompilerToVMHelper.getConstantPool(methodInstance, 0L); + } + }, + CONSTANT_POOL_BASE { + @Override + HotSpotConstantPool getConstantPool() { + HotSpotConstantPool cpInst; + try { + cpInst = CompilerToVMHelper.getConstantPool(null, + getPtrToCpAddress()); + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, getPtrToCpAddress()); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getConstantPool(cpInst, 0L); + } + }, + CONSTANT_POOL_BASE_IN_TWO { + @Override + HotSpotConstantPool getConstantPool() { + long ptr = getPtrToCpAddress(); + HotSpotConstantPool cpInst; + try { + cpInst = CompilerToVMHelper.getConstantPool(null, ptr); + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, ptr / 2L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getConstantPool(cpInst, + ptr - ptr / 2L); + } + }, + CONSTANT_POOL_BASE_ZERO { + @Override + HotSpotConstantPool getConstantPool() { + long ptr = getPtrToCpAddress(); + HotSpotConstantPool cpInst; + try { + cpInst = CompilerToVMHelper.getConstantPool(null, ptr); + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, 0L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getConstantPool(cpInst, ptr); + } + }, + OBJECT_TYPE_BASE { + @Override + HotSpotConstantPool getConstantPool() { + HotSpotResolvedObjectTypeImpl type + = HotSpotResolvedObjectTypeImpl.fromObjectClass( + OBJECT_TYPE_BASE.getClass()); + long ptrToClass = UNSAFE.getKlassPointer(OBJECT_TYPE_BASE); + return CompilerToVMHelper.getConstantPool(type, + getPtrToCpAddress() - ptrToClass); + } + }, + ; + abstract HotSpotConstantPool getConstantPool(); + } + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final Unsafe UNSAFE = Utils.getUnsafe(); + private static final Class TEST_CLASS = GetConstantPoolTest.class; + private static final long CP_ADDRESS + = WB.getConstantPool(GetConstantPoolTest.class); + + public void test(TestCase testCase) { + System.out.println(testCase.name()); + HotSpotConstantPool cp = testCase.getConstantPool(); + String cpStringRep = cp.toString(); + if (!cpStringRep.contains(HotSpotConstantPool.class.getSimpleName()) + || !cpStringRep.contains(TEST_CLASS.getName())) { + String msg = String.format("%s : " + + " Constant pool is not valid." + + " String representation should contain \"%s\" and \"%s\"", + testCase.name(), + HotSpotConstantPool.class.getSimpleName(), + TEST_CLASS.getName()); + throw new AssertionError(msg); + } + } + + public static void main(String[] args) { + GetConstantPoolTest test = new GetConstantPoolTest(); + for (TestCase testCase : TestCase.values()) { + test.test(testCase); + } + testObjectBase(); + testMetaspaceWrapperBase(); + } + + private static void testObjectBase() { + try { + HotSpotConstantPool cp + = CompilerToVMHelper.getConstantPool(new Object(), 0L); + throw new AssertionError("Test OBJECT_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } + private static void testMetaspaceWrapperBase() { + try { + HotSpotConstantPool cp = CompilerToVMHelper.getConstantPool( + new MetaspaceWrapperObject() { + @Override + public long getMetaspacePointer() { + return getPtrToCpAddress(); + } + }, 0L); + throw new AssertionError("Test METASPACE_WRAPPER_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } + + private static long getPtrToCpAddress() { + Field field; + try { + field = TEST_CLASS.getDeclaredField("CP_ADDRESS"); + } catch (NoSuchFieldException nsfe) { + throw new Error("TESTBUG : cannot find field \"CP_ADDRESS\" : " + + nsfe.getMessage(), nsfe); + } + Object base = UNSAFE.staticFieldBase(field); + return WB.getObjectAddress(base) + UNSAFE.staticFieldOffset(field); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetExceptionTableTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.io.IOException; +import java.lang.reflect.Executable; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class GetExceptionTableTest { + + public static final int TRY_CATCH_COUNT = 3; + public static final int TRY_CATCH_FINALLY_COUNT = 8; + public static final int TRY_WITH_RESOURCES_COUNT = 6; + public static final int EMPTY_COUNT = 0; + + public static void main(String[] args) { + Map testCases = createTestCases(); + testCases.forEach(GetExceptionTableTest::runSanityTest); + } + + private static Map createTestCases() { + HashMap methods = new HashMap<>(); + try { + Class aClass = GetExceptionTableTest.DummyClass.class; + methods.put(aClass.getMethod("tryCatchDummy"), TRY_CATCH_COUNT); + methods.put(aClass.getMethod("tryCatchFinallyDummy"), + TRY_CATCH_FINALLY_COUNT); + methods.put(aClass.getMethod("tryWithResourcesDummy"), + TRY_WITH_RESOURCES_COUNT); + methods.put(aClass.getMethod("emptyFunction"), EMPTY_COUNT); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG", e); + } + return methods; + } + + private static void runSanityTest(Executable aMethod, + Integer expectedTableLength) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + int tableLength = CompilerToVMHelper.getExceptionTableLength(method); + Asserts.assertEQ(tableLength, expectedTableLength, aMethod + + " incorrect exception table length."); + + long tableStart = CompilerToVMHelper.getExceptionTableStart(method); + if (tableLength > 0) { + Asserts.assertNE(tableStart, 0L, aMethod + " exception table starts " + + "at 0."); + } + } + + private static class DummyClass { + public static void emptyFunction() {} + public static void tryCatchDummy() throws Throwable { + try { + throw new Exception("Dummy exception"); + } catch (ArithmeticException ex) { + throw new IOException(ex.getMessage()); + } catch (IOException ex) { + throw new Exception(ex); + } catch (Exception ex) { + throw new Exception(ex); + } + } + + public int tryCatchFinallyDummy() { + // 4 times catch/finally = 8 catch-blocks and finally-blocks + try { + throw new Exception("Dummy exception"); + } catch (IndexOutOfBoundsException ex) { + return 1; + } catch (ArithmeticException ex) { + return 2; + } catch (IOException ex) { + return 3; + } catch (Exception ex) { + return 4; + } finally { + return 0; + } + } + + public static int tryWithResourcesDummy() throws Throwable { + try (Socket socket = new Socket()) { + throw new Exception("Dummy exception"); + } catch (ArithmeticException ex) { + return 1; + } catch (IOException ex) { + return 2; + } catch (Exception ex) { + return 3; + } + } + } +} + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetImplementorTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetImplementorTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.AbstractClassExtender; +import compiler.jvmci.common.testcases.DoNotImplementInterface; +import compiler.jvmci.common.testcases.DoNotExtendClass; +import compiler.jvmci.common.testcases.MultipleImplementer1; +import compiler.jvmci.common.testcases.MultipleImplementer2; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import compiler.jvmci.common.testcases.SingleSubclass; +import compiler.jvmci.common.testcases.SingleSubclassedClass; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class GetImplementorTest { + public static void main(String args[]) { + GetImplementorTest test = new GetImplementorTest(); + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + Stream.of( + SingleSubclass.class, + AbstractClassExtender.class, + MultipleImplementer2.class, + MultipleImplementer1.class, + MultipleImplementersInterface.class, + DoNotImplementInterface.class, + DoNotExtendClass.class, + AbstractClass.class, + SingleSubclassedClass.class) + .forEach(Utils::ensureClassIsLoaded); + // an interface with single class implementing it + result.add(new TestCase(SingleImplementerInterface.class, + SingleImplementer.class)); + /* an interface with multiple implementers. According to getImplementor + javadoc, an itself should be returned in case of more than one + implementor + */ + result.add(new TestCase(MultipleImplementersInterface.class, + MultipleImplementersInterface.class)); + // an interface with no implementors + result.add(new TestCase(DoNotImplementInterface.class, null)); + // an abstract class with extender class + result.add(new TestCase(AbstractClass.class, null)); + // a simple class, which is not extended + result.add(new TestCase(DoNotExtendClass.class, null)); + // a usual class, which is extended + result.add(new TestCase(SingleSubclassedClass.class, null)); + return result; + } + + private void runTest(TestCase tcase) { + System.out.println(tcase); + HotSpotResolvedObjectTypeImpl resolvedIface = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.anInterface), + getClass(), /* resolve = */ true); + HotSpotResolvedObjectTypeImpl resolvedImplementer = CompilerToVMHelper + .getImplementor(resolvedIface); + HotSpotResolvedObjectTypeImpl resolvedExpected = null; + if (tcase.expectedImplementer != null) { + resolvedExpected = CompilerToVMHelper.lookupType(Utils + .toJVMTypeSignature(tcase.expectedImplementer), + getClass(), /* resolve = */ true); + } + Asserts.assertEQ(resolvedImplementer, resolvedExpected, + "Unexpected implementer for " + tcase.anInterface.getName()); + } + + private static class TestCase { + public final Class anInterface; + public final Class expectedImplementer; + + public TestCase(Class iface, Class expectedImplementer) { + this.anInterface = iface; + this.expectedImplementer = expectedImplementer; + } + + @Override + public String toString() { + return String.format("CASE: interface=%s, expected=%s", + anInterface.getName(), + expectedImplementer == null + ? null + : expectedImplementer.getName()); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetLineNumberTableTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.TestCase; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.tree.ClassNode; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +public class GetLineNumberTableTest { + public static void main(String[] args) { + TestCase.getAllExecutables() + .forEach(GetLineNumberTableTest::runSanityTest); + } + + public static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + long[] lineNumbers = CompilerToVMHelper.getLineNumberTable(method); + long[] expectedLineNumbers = getExpectedLineNumbers(aMethod); + + Asserts.assertTrue(Arrays.equals(lineNumbers, expectedLineNumbers), + String.format("%s : unequal table values : %n%s%n%s%n", + aMethod, + Arrays.toString(lineNumbers), + Arrays.toString(expectedLineNumbers))); + } + + public static long[] getExpectedLineNumbers(Executable aMethod) { + try { + ClassReader cr = new ClassReader(aMethod.getDeclaringClass() + .getName()); + ClassNode cn = new ClassNode(); + cr.accept(cn, ClassReader.EXPAND_FRAMES); + + Map lineNumbers = new HashMap<>(); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + ClassVisitor cv = new ClassVisitorForLabels(cw, lineNumbers, + aMethod); + cr.accept(cv, ClassReader.EXPAND_FRAMES); + + long[] result = null; + if (!lineNumbers.isEmpty()) { + Map labels = new TreeMap<>(); + lineNumbers.forEach((k, v) -> labels.put(k.getOffset(), v)); + + result = new long[2 * labels.size()]; + int i = 0; + for (Integer key : labels.keySet()) { + result[i++] = key.longValue(); + result[i++] = labels.get(key).longValue(); + } + } + // compilerToVM::getLineNumberTable returns null in case empty table + return result; + } catch (IOException e) { + throw new Error("TEST BUG " + e, e); + } + } + + private static class ClassVisitorForLabels extends ClassVisitor { + private final Map lineNumbers; + private final String targetName; + private final String targetDesc; + + public ClassVisitorForLabels(ClassWriter cw, Map lines, + Executable target) { + super(Opcodes.ASM5, cw); + this.lineNumbers = lines; + + StringBuilder builder = new StringBuilder("("); + for (Parameter parameter : target.getParameters()) { + builder.append(Utils.toJVMTypeSignature(parameter.getType())); + } + builder.append(")"); + if (target instanceof Constructor) { + targetName = ""; + builder.append("V"); + } else { + targetName = target.getName(); + builder.append(Utils.toJVMTypeSignature( + ((Method) target).getReturnType())); + } + targetDesc = builder.toString(); + } + + @Override + public final MethodVisitor visitMethod(int access, String name, + String desc, String signature, + String[] exceptions) { + MethodVisitor mv = cv.visitMethod(access, name, desc, signature, + exceptions); + if (targetDesc.equals(desc) && targetName.equals(name)) { + return new MethodVisitor(Opcodes.ASM5, mv) { + @Override + public void visitLineNumber(int i, Label label) { + super.visitLineNumber(i, label); + lineNumbers.put(label, i); + } + }; + } + return mv; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @clean compiler.jvmci.compilerToVM.* + * @compile -g DummyInterface.java + * @compile -g DummyAbstractClass.java + * @compile -g DummyClass.java + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetLocalVariableTableTest + * @clean compiler.jvmci.compilerToVM.* + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +import java.lang.reflect.Executable; +import java.util.HashMap; +import java.util.Map; + +public class GetLocalVariableTableTest { + + public static final int MAIN_LOCALS_COUNT = 0; + public static final int INSTANCE_LOCALS_COUNT = 4; + public static final int EMPTY_INSTANCE_COUNT = 1; + public static final int EMPTY_STATIC_COUNT = 0; + public static final int ABSTRACT_INHERIT_LOCALS_COUNT = 2; + public static final int DEFAULTFUNC_LOCALS_COUNT = 4; + + public static void main(String[] args) { + Map testCases = createTestCases(); + testCases.forEach(GetLocalVariableTableTest::runSanityTest); + } + + private static Map createTestCases() { + HashMap methods = new HashMap<>(); + try { + Class aClass; + + aClass = GetLocalVariableTableTest.class; + methods.put(aClass.getDeclaredMethod("main", String[].class), + MAIN_LOCALS_COUNT); + + aClass = DummyClass.class; + methods.put(aClass.getMethod("dummyInstanceFunction"), + INSTANCE_LOCALS_COUNT); + methods.put(aClass.getMethod("dummyEmptyInstanceFunction"), + EMPTY_INSTANCE_COUNT); + methods.put(aClass.getMethod("dummyEmptyStaticFunction"), + EMPTY_STATIC_COUNT); + methods.put(aClass.getMethod("dummyFunction"), + EMPTY_INSTANCE_COUNT); + methods.put(aClass.getMethod("dummyAbstractFunction"), + ABSTRACT_INHERIT_LOCALS_COUNT); + + aClass = DummyInterface.class; + methods.put(aClass.getMethod("dummyFunction"), EMPTY_STATIC_COUNT); + methods.put(aClass.getMethod("dummyDefaultFunction", int.class, + int.class), DEFAULTFUNC_LOCALS_COUNT); + + aClass = DummyAbstractClass.class; + methods.put(aClass.getMethod("dummyAbstractFunction"), 0); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG", e); + } + return methods; + } + + private static void runSanityTest(Executable aMethod, + Integer expectedTableLength) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + + int tblLength = CompilerToVMHelper.getLocalVariableTableLength(method); + Asserts.assertEQ(tblLength, expectedTableLength, aMethod + " : incorrect " + + "local variable table length."); + + long tblStart = CompilerToVMHelper.getLocalVariableTableStart(method); + if (tblLength > 0) { + Asserts.assertNE(tblStart, 0L, aMethod + " : local variable table starts" + + " at 0 with length " + tblLength); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetMaxCallTargetOffsetTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetMaxCallTargetOffsetTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class GetMaxCallTargetOffsetTest { + public static void main(String args[]) { + new GetMaxCallTargetOffsetTest().runTest(); + } + + private void runTest() { + long offset1 = CompilerToVMHelper.getMaxCallTargetOffset(0L); + Asserts.assertNE(offset1, 0L, + "Unexpected maxCallTargetOffset for 0L"); + long offset2 = CompilerToVMHelper.getMaxCallTargetOffset(100L); + Asserts.assertNE(offset2, 0L, + "Unexpected maxCallTargetOffset for 100L"); + long offset3 = CompilerToVMHelper.getMaxCallTargetOffset(1000000L); + Asserts.assertNE(offset3, 0L, + "Unexpected maxCallTargetOffset for 1000000L"); + // there can be 2 same offsets, but not 3 + Asserts.assertFalse(offset1 == offset2 && offset2 == offset3, + "All 3 offsets are unexpectedly equal: " + offset1); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetNextStackFrameTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Method; +import jdk.vm.ci.hotspot.CompilerToVM; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotStackFrameReference; +import jdk.test.lib.Asserts; + +public class GetNextStackFrameTest { + private static final int RECURSION_AMOUNT = 3; + private static final HotSpotResolvedJavaMethodImpl REC_FRAME_METHOD; + private static final HotSpotResolvedJavaMethodImpl FRAME1_METHOD; + private static final HotSpotResolvedJavaMethodImpl FRAME2_METHOD; + private static final HotSpotResolvedJavaMethodImpl FRAME3_METHOD; + private static final HotSpotResolvedJavaMethodImpl FRAME4_METHOD; + private static final HotSpotResolvedJavaMethodImpl RUN_METHOD; + + static { + Method method; + try { + Class aClass = GetNextStackFrameTest.class; + method = aClass.getDeclaredMethod("recursiveFrame", int.class); + REC_FRAME_METHOD = CTVMUtilities.getResolvedMethod(method); + method = aClass.getDeclaredMethod("frame1"); + FRAME1_METHOD = CTVMUtilities.getResolvedMethod(method); + method = aClass.getDeclaredMethod("frame2"); + FRAME2_METHOD = CTVMUtilities.getResolvedMethod(method); + method = aClass.getDeclaredMethod("frame3"); + FRAME3_METHOD = CTVMUtilities.getResolvedMethod(method); + method = aClass.getDeclaredMethod("frame4"); + FRAME4_METHOD = CTVMUtilities.getResolvedMethod(method); + method = Thread.class.getDeclaredMethod("run"); + RUN_METHOD = CTVMUtilities.getResolvedMethod(Thread.class, method); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find a test method", e); + } + } + + public static void main(String[] args) { + new GetNextStackFrameTest().test(); + } + + private void test() { + // Create new thread to get new clean stack + Thread thread = new Thread(() -> recursiveFrame(RECURSION_AMOUNT)); + thread.start(); + try { + thread.join(); + } catch (InterruptedException e) { + throw new Error("Interrupted while waiting to join", e); + } + } + + // Helper methods for a longer stack + private void recursiveFrame(int recursionAmount) { + if (--recursionAmount != 0) { + recursiveFrame(recursionAmount); + } else { + frame1(); + } + } + + private void frame1() { + frame2(); + } + + private void frame2() { + frame3(); + } + + private void frame3() { + frame4(); + } + + private void frame4() { + check(); + } + + private void check() { + findFirst(); + walkThrough(); + skipAll(); + findNextSkipped(); + findYourself(); + } + + /** + * Finds the first topmost frame from the list of methods to search + */ + private void findFirst() { + checkNextFrameFor(null /* topmost frame */, + new HotSpotResolvedJavaMethodImpl[] + {FRAME2_METHOD, FRAME3_METHOD, FRAME4_METHOD}, + FRAME4_METHOD, 0); + } + + /** + * Walks through whole stack and checks that every frame could be found + * while going down the stack till the end + */ + private void walkThrough() { + // Check that we would get a frame 4 starting from the topmost frame + HotSpotStackFrameReference nextStackFrame = checkNextFrameFor( + null /* topmost frame */, + new HotSpotResolvedJavaMethodImpl[] {FRAME4_METHOD}, + FRAME4_METHOD, 0); + // Check that we would get a frame 3 starting from frame 4 when we try + // to search one of the next two frames + nextStackFrame = checkNextFrameFor(nextStackFrame, + new HotSpotResolvedJavaMethodImpl[] {FRAME3_METHOD, + FRAME2_METHOD}, + FRAME3_METHOD, 0); + // Check that we would get a frame 1 + nextStackFrame = checkNextFrameFor(nextStackFrame, + new HotSpotResolvedJavaMethodImpl[] {FRAME1_METHOD}, + FRAME1_METHOD, 0); + // Check that we would skip (RECURSION_AMOUNT - 1) methods and find a + // recursionFrame starting from frame 1 + nextStackFrame = checkNextFrameFor(nextStackFrame, + new HotSpotResolvedJavaMethodImpl[] {REC_FRAME_METHOD}, + REC_FRAME_METHOD, RECURSION_AMOUNT - 1); + // Check that we would get a Thread::run method frame; + nextStackFrame = checkNextFrameFor(nextStackFrame, + new HotSpotResolvedJavaMethodImpl[] {RUN_METHOD}, + RUN_METHOD, 0); + // Check that there are no more frames after thread's run method + nextStackFrame = CompilerToVMHelper.getNextStackFrame(nextStackFrame, + null /* any */, 0); + Asserts.assertNull(nextStackFrame, + "Found stack frame after Thread::run"); + } + + /** + * Skips all frames to get null at the end of the stack + */ + private void skipAll() { + // Skip all frames (stack size) + 2 (getNextStackFrame() itself + // and from CompilerToVMHelper) + int initialSkip = Thread.currentThread().getStackTrace().length + 2; + HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper + .getNextStackFrame(null /* topmost frame */, null /* any */, + initialSkip); + Asserts.assertNull(nextStackFrame, "Unexpected frame"); + } + + /** + * Search for any frame skipping one frame + */ + private void findNextSkipped() { + // Get frame 4 + HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper + .getNextStackFrame(null /* topmost frame */, + new HotSpotResolvedJavaMethodImpl[] {FRAME4_METHOD}, 0); + // Get frame 2 by skipping one method starting from frame 4 + checkNextFrameFor(nextStackFrame, null /* any */, + FRAME2_METHOD , 1 /* skip one */); + } + + /** + * Finds test method in the stack + */ + private void findYourself() { + Method method; + try { + method = CompilerToVM.class.getDeclaredMethod("getNextStackFrame", + HotSpotStackFrameReference.class, + HotSpotResolvedJavaMethodImpl[].class, int.class); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find getNextStackFrame method"); + } + HotSpotResolvedJavaMethodImpl self + = CTVMUtilities.getResolvedMethod(CompilerToVM.class, method); + checkNextFrameFor(null /* topmost frame */, null /* any */, self, 0); + } + + /** + * Searches next frame and checks that it equals to expected + * + * @param currentFrame start frame to search from + * @param searchMethods a list of methods to search + * @param expected expected frame + * @param skip amount of frames to be skipped + * @return frame reference + */ + private HotSpotStackFrameReference checkNextFrameFor( + HotSpotStackFrameReference currentFrame, + HotSpotResolvedJavaMethodImpl[] searchMethods, + HotSpotResolvedJavaMethodImpl expected, + int skip) { + HotSpotStackFrameReference nextStackFrame = CompilerToVMHelper + .getNextStackFrame(currentFrame, searchMethods, skip); + Asserts.assertNotNull(nextStackFrame); + Asserts.assertTrue(nextStackFrame.isMethod(expected), + "Unexpected next frame: " + nextStackFrame + + " from current frame: " + currentFrame); + return nextStackFrame; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.GetResolvedJavaMethodAtSlotTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import java.util.HashMap; +import java.util.Map; + +public class GetResolvedJavaMethodAtSlotTest { + + private static class A { + { + System.out.println("Dummy"); + } + public void f1() {} + public int f2() { return 0; } + public String f3() { return ""; } + } + + + private static class S { + static { + System.out.println("Dummy static"); + } + public S() {} + public void f1() {} + public int f2() { return 0; } + public String f3() { return ""; } + } + + private class B extends A { + public void f4() {} + } + + private interface I { + void f1(); + int f2(); + String f3(); + } + + public static void main(String[] args) { + Map, Integer> testCases = getTestCases(); + testCases.forEach(GetResolvedJavaMethodAtSlotTest::test); + } + + private static Map, Integer> getTestCases() { + Map, Integer> testCases = new HashMap<>(); + testCases.put(A.class, 5); // ctor, init, f1, f2, f3 + testCases.put(S.class, 5); // ctor, cinit, f1, f2, f3 + testCases.put(I.class, 3); // f1, f2, f3 + testCases.put(B.class, 2); // ctor, f4 + return testCases; + } + + private static void test(Class aClass, int methodNumber) { + testSlotBigger(aClass); + testCorrectMethods(aClass, methodNumber); + } + + private static void testSlotBigger(Class holder) { + HotSpotResolvedJavaMethodImpl method + = CompilerToVMHelper.getResolvedJavaMethodAtSlot(holder, 50); + Asserts.assertNull(method, "Got method for non existing slot 50 in " + + holder); + } + + private static void testCorrectMethods(Class holder, int methodsNumber) { + for (int i = 0; i < methodsNumber; i++) { + HotSpotResolvedJavaMethodImpl method = CompilerToVMHelper + .getResolvedJavaMethodAtSlot(holder, i); + Asserts.assertNotNull(method, "Did not got method for slot " + i + + " in class " + holder.getCanonicalName()); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetResolvedJavaMethodTest + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.jvmci.compilerToVM.GetResolvedJavaMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.MetaspaceWrapperObject; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +public class GetResolvedJavaMethodTest { + private static enum TestCase { + NULL_BASE { + @Override + HotSpotResolvedJavaMethodImpl getResolvedJavaMethod() { + return CompilerToVMHelper.getResolvedJavaMethod( + null, getPtrToMethod()); + } + }, + JAVA_METHOD_BASE { + @Override + HotSpotResolvedJavaMethodImpl getResolvedJavaMethod() { + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, getPtrToMethod()); + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG : " + e, e); + } + return CompilerToVMHelper.getResolvedJavaMethod( + methodInstance, 0L); + } + }, + JAVA_METHOD_BASE_IN_TWO { + @Override + HotSpotResolvedJavaMethodImpl getResolvedJavaMethod() { + long ptr = getPtrToMethod(); + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, ptr / 2L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaMethod(methodInstance, + ptr - ptr / 2L); + } + }, + JAVA_METHOD_BASE_ZERO { + @Override + HotSpotResolvedJavaMethodImpl getResolvedJavaMethod() { + long ptr = getPtrToMethod(); + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, 0L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaMethod(methodInstance, + ptr); + } + } + ; + abstract HotSpotResolvedJavaMethodImpl getResolvedJavaMethod(); + } + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final Class TEST_CLASS = GetResolvedJavaMethodTest.class; + private static final long PTR; + static { + HotSpotResolvedJavaMethodImpl method + = CompilerToVMHelper.getResolvedJavaMethodAtSlot(TEST_CLASS, 0); + PTR = method.getMetaspacePointer(); + } + + private static long getPtrToMethod() { + Field field; + try { + field = TEST_CLASS.getDeclaredField("PTR"); + } catch (NoSuchFieldException e) { + throw new Error("TEST BUG : " + e, e); + } + Object base = UNSAFE.staticFieldBase(field); + return WB.getObjectAddress(base) + UNSAFE.staticFieldOffset(field); + } + + public void test(TestCase testCase) { + System.out.println(testCase.name()); + HotSpotResolvedJavaMethodImpl result = testCase.getResolvedJavaMethod(); + Asserts.assertNotNull(result, testCase + " : got null"); + Asserts.assertEQ(result.getDeclaringClass().mirror(), TEST_CLASS, + testCase + " : returned method has unexpected declaring class"); + } + + public static void main(String[] args) { + GetResolvedJavaMethodTest test = new GetResolvedJavaMethodTest(); + for (TestCase testCase : TestCase.values()) { + test.test(testCase); + } + testObjectBase(); + testMetaspaceWrapperBase(); + } + + private static void testMetaspaceWrapperBase() { + try { + HotSpotResolvedJavaMethodImpl method + = CompilerToVMHelper.getResolvedJavaMethod( + new MetaspaceWrapperObject() { + @Override + public long getMetaspacePointer() { + return getPtrToMethod(); + } + }, 0L); + throw new AssertionError("Test METASPACE_WRAPPER_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } + + private static void testObjectBase() { + try { + HotSpotResolvedJavaMethodImpl method + = CompilerToVMHelper.getResolvedJavaMethod(new Object(), 0L); + throw new AssertionError("Test OBJECT_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UseCompressedOops + * compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:-UseCompressedOops + * compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest + */ + +package compiler.jvmci.compilerToVM; + +import java.lang.reflect.Field; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.vm.ci.hotspot.MetaspaceWrapperObject; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +public class GetResolvedJavaTypeTest { + private static enum TestCase { + NULL_BASE { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + return CompilerToVMHelper.getResolvedJavaType( + null, getPtrToKlass(), COMPRESSED); + } + }, + JAVA_METHOD_BASE { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + HotSpotResolvedJavaMethodImpl methodInstance + = CompilerToVMHelper.getResolvedJavaMethodAtSlot( + TEST_CLASS, 0); + Field field; + try { + field = HotSpotResolvedJavaMethodImpl + .class.getDeclaredField("metaspaceMethod"); + field.setAccessible(true); + field.set(methodInstance, getPtrToKlass()); + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG : " + e, e); + } + + return CompilerToVMHelper.getResolvedJavaType(methodInstance, + 0L, COMPRESSED); + } + }, + CONSTANT_POOL_BASE { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + HotSpotConstantPool cpInst; + try { + cpInst = CompilerToVMHelper.getConstantPool(null, + getPtrToKlass()); + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, getPtrToKlass()); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaType(cpInst, + 0L, COMPRESSED); + } + }, + CONSTANT_POOL_BASE_IN_TWO { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + long ptr = getPtrToKlass(); + HotSpotConstantPool cpInst = HotSpotResolvedObjectTypeImpl + .fromObjectClass(TEST_CLASS).getConstantPool(); + try { + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, ptr / 2L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaType(cpInst, + ptr - ptr / 2L, COMPRESSED); + } + }, + CONSTANT_POOL_BASE_ZERO { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + long ptr = getPtrToKlass(); + HotSpotConstantPool cpInst = HotSpotResolvedObjectTypeImpl + .fromObjectClass(TEST_CLASS).getConstantPool(); + try { + Field field = HotSpotConstantPool.class + .getDeclaredField("metaspaceConstantPool"); + field.setAccessible(true); + field.set(cpInst, 0L); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG : " + e.getMessage(), e); + } + return CompilerToVMHelper.getResolvedJavaType(cpInst, + ptr, COMPRESSED); + } + }, + OBJECT_TYPE_BASE { + @Override + HotSpotResolvedObjectTypeImpl getResolvedJavaType() { + HotSpotResolvedObjectTypeImpl type + = HotSpotResolvedObjectTypeImpl.fromObjectClass( + OBJECT_TYPE_BASE.getClass()); + long ptrToClass = UNSAFE.getKlassPointer(OBJECT_TYPE_BASE); + return CompilerToVMHelper.getResolvedJavaType(type, + getPtrToKlass() - ptrToClass, COMPRESSED); + } + }, + ; + abstract HotSpotResolvedObjectTypeImpl getResolvedJavaType(); + } + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final long PTR = UNSAFE.getKlassPointer( + new GetResolvedJavaTypeTest()); + private static final Class TEST_CLASS = GetResolvedJavaTypeTest.class; + /* a compressed parameter for tested method is set to false because + unsafe.getKlassPointer always returns uncompressed pointer */ + private static final boolean COMPRESSED = false; + // = WB.getBooleanVMFlag("UseCompressedClassPointers"); + + private static long getPtrToKlass() { + Field field; + try { + field = TEST_CLASS.getDeclaredField("PTR"); + } catch (NoSuchFieldException e) { + throw new Error("TEST BUG : " + e, e); + } + Object base = UNSAFE.staticFieldBase(field); + return WB.getObjectAddress(base) + UNSAFE.staticFieldOffset(field); + } + + public void test(TestCase testCase) { + System.out.println(testCase.name()); + HotSpotResolvedObjectTypeImpl type = testCase.getResolvedJavaType(); + Asserts.assertEQ(type.mirror(), TEST_CLASS, testCase + + " Unexpected Class returned by getResolvedJavaType"); + } + + public static void main(String[] args) { + GetResolvedJavaTypeTest test = new GetResolvedJavaTypeTest(); + for (TestCase testCase : TestCase.values()) { + test.test(testCase); + } + testObjectBase(); + testMetaspaceWrapperBase(); + } + + private static void testMetaspaceWrapperBase() { + try { + HotSpotResolvedObjectTypeImpl type + = CompilerToVMHelper.getResolvedJavaType( + new MetaspaceWrapperObject() { + @Override + public long getMetaspacePointer() { + return getPtrToKlass(); + } + }, 0L, COMPRESSED); + throw new AssertionError("Test METASPACE_WRAPPER_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } + + private static void testObjectBase() { + try { + HotSpotResolvedObjectTypeImpl type + = CompilerToVMHelper.getResolvedJavaType(new Object(), 0L, + COMPRESSED); + throw new AssertionError("Test OBJECT_BASE." + + " Expected IllegalArgumentException has not been caught"); + } catch (IllegalArgumentException iae) { + // expected + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. compiler.jvmci.compilerToVM.GetStackTraceElementTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class GetStackTraceElementTest { + + public static void main(String[] args) { + Map testCases = createTestCases(); + testCases.forEach(GetStackTraceElementTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod, int[] bcis) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + String className = aMethod.getDeclaringClass().getName(); + int lastDot = className.lastIndexOf('.'); + int firstDol = className.contains("$") + ? className.indexOf('$') + : className.length(); + String fileName = className.substring(lastDot + 1, firstDol) + ".java"; + for (int bci : bcis) { + StackTraceElement ste = CompilerToVMHelper + .getStackTraceElement(method, bci); + Asserts.assertNotNull(ste); + Asserts.assertEQ(ste.getClassName(), className); + Asserts.assertEQ(ste.getFileName(), fileName); + Asserts.assertEQ(ste.getMethodName(), aMethod.getName()); + Asserts.assertEQ(ste.isNativeMethod(), Modifier + .isNative(aMethod.getModifiers())); + } + + } + + private static Map createTestCases() { + Map testCases = new HashMap<>(); + + try { + Class aClass = DummyClass.class; + Method aMethod = aClass.getDeclaredMethod("dummyInstanceFunction"); + int[] bci = new int[] {0, 2, 3, 6, 7, 8, 11, 13, 15, 16, 17, 18}; + testCases.put(aMethod, bci); + + aMethod = aClass.getDeclaredMethod("dummyEmptyFunction"); + bci = new int[] {0}; + testCases.put(aMethod, bci); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG : test method not found", e); + } + return testCases; + } + + private class DummyClass { + public int dummyInstanceFunction() { + String str1 = "123123123"; + double x = 3.14; + int y = Integer.parseInt(str1); + + return y / (int)x; + } + + public void dummyEmptyFunction() {} + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetSymbolTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * compiler.jvmci.common.testcases.SingleImplementer + * compiler.jvmci.common.testcases.SingleImplementerInterface + * compiler.jvmci.compilerToVM.GetSymbolTest + * compiler.jvmci.common.CTVMUtilities + * jdk.test.lib.Utils + * jdk.test.lib.Asserts + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. compiler.jvmci.compilerToVM.GetSymbolTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.SingleImplementer; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.meta.ConstantPool; +import jdk.test.lib.Utils; + +public class GetSymbolTest { + private static final int CONSTANT_POOL_UTF8_TAG = 1; // see jvms, section 4.4 + + private static final Function> NAMES = members -> + Stream.of(members) + .map(Member::getName) + .collect(Collectors.toList()); + + public static void main(String[] args) { + new GetSymbolTest().test(SingleImplementer.class); + } + + private void test(Class aClass) { + Utils.ensureClassIsLoaded(aClass); + Method method; + try { + method = aClass.getDeclaredMethod("nonInterfaceMethod"); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find test method", e); + } + HotSpotResolvedJavaMethodImpl resolvedMethod + = CTVMUtilities.getResolvedMethod(aClass, method); + List symbols; + try { + symbols = getSymbols(resolvedMethod); + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG: can't access private members", e); + } + List classSymbols = new ArrayList<>(); + classSymbols.addAll(NAMES.apply(aClass.getDeclaredFields())); + classSymbols.addAll(NAMES.apply(aClass.getDeclaredMethods())); + // Check that all members of test class have symbols from constant pool + for (String s : classSymbols) { + if (!symbols.contains(s)) { + // failed. print all symbols found by getSymbol + System.out.println("getSymbol data:"); + for (String ctvmValue : symbols) { + System.out.println(ctvmValue); + } + throw new AssertionError("Unable to find symbol " + s + + " using CompilerToVM.getSymbol"); + } + } + } + + private List getSymbols(HotSpotResolvedJavaMethodImpl + metaspaceMethod) throws ReflectiveOperationException { + List symbols = new ArrayList<>(); + ConstantPool pool = metaspaceMethod.getConstantPool(); + long length = pool.length(); + // jvms-4.1: The constant_pool table is indexed from 1 ... + for (int i = 1; i < length; i++) { + if (getTag(pool, i) == CONSTANT_POOL_UTF8_TAG) { + long entryPointer; + Method getEntryAt = pool.getClass() + .getDeclaredMethod("getEntryAt", int.class); + getEntryAt.setAccessible(true); + entryPointer = (Long) getEntryAt.invoke(pool, i); + String symbol = CompilerToVMHelper.getSymbol(entryPointer); + symbols.add(symbol); + } + } + return symbols; + } + + private int getTag(ConstantPool pool, int index) + throws ReflectiveOperationException { + Object jvmConstant; + Method getTag = pool.getClass().getDeclaredMethod("getTagAt", + int.class); + getTag.setAccessible(true); + jvmConstant = getTag.invoke(pool, index); + Field tagCode = jvmConstant.getClass().getDeclaredField("tag"); + tagCode.setAccessible(true); + return tagCode.getInt(jvmConstant); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.DoNotExtendClass; +import compiler.jvmci.common.testcases.MultipleAbstractImplementer; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.common.testcases.MultipleImplementersInterfaceExtender; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import compiler.jvmci.common.testcases.SingleSubclass; +import compiler.jvmci.common.testcases.SingleSubclassedClass; +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.AnotherSingleImplementer; +import compiler.jvmci.common.testcases.AnotherSingleImplementerInterface; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class GetVtableIndexForInterfaceTest { + private static final int INVALID_VTABLE_INDEX = -4; // see method.hpp: VtableIndexFlag + + public static void main(String args[]) { + GetVtableIndexForInterfaceTest test + = new GetVtableIndexForInterfaceTest(); + try { + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find requested method", e); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + Stream.of( + AbstractClass.class, + SingleImplementer.class, + SingleImplementerInterface.class, + MultipleImplementersInterface.class, + MultipleImplementersInterfaceExtender.class, + SingleSubclass.class, + SingleSubclassedClass.class, + DoNotExtendClass.class, + MultipleAbstractImplementer.class + ) + .forEach(Utils::ensureClassIsLoaded); + // non iface method + result.add(new TestCase(SingleImplementer.class, + SingleImplementer.class, "nonInterfaceMethod", + false, InternalError.class)); + // iface method w/o default implementation + result.add(new TestCase(SingleImplementer.class, + SingleImplementerInterface.class, "interfaceMethod", false)); + /* another iface which provides default implementation for the + original iface*/ + result.add(new TestCase(MultipleImplementersInterfaceExtender.class, + MultipleImplementersInterface.class, "testMethod", false, + InternalError.class)); + // iface method w/ default implementation + result.add(new TestCase(SingleImplementer.class, + SingleImplementerInterface.class, "defaultMethod", true)); + // non iface class + result.add(new TestCase(SingleSubclass.class, + SingleSubclassedClass.class, "inheritedMethod", false, + InternalError.class)); + // class not implementing iface + result.add(new TestCase(DoNotExtendClass.class, + SingleImplementerInterface.class, "defaultMethod", false)); + // abstract class which doesn't implement iface + result.add(new TestCase(AbstractClass.class, + SingleImplementerInterface.class, "defaultMethod", false)); + // abstract class which implements iface + result.add(new TestCase(MultipleAbstractImplementer.class, + MultipleImplementersInterface.class, "defaultMethod", true)); + // class not initialized + result.add(new TestCase(AnotherSingleImplementer.class, + AnotherSingleImplementerInterface.class, "defaultMethod", + false, InternalError.class)); + return result; + } + + private void runTest(TestCase tcase) throws NoSuchMethodException { + System.out.println(tcase); + Method method = tcase.holder.getDeclaredMethod(tcase.methodName); + HotSpotResolvedObjectTypeImpl metaspaceKlass = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.receiver), + getClass(), /* resolve = */ true); + HotSpotResolvedJavaMethodImpl metaspaceMethod = CTVMUtilities + .getResolvedMethod(tcase.holder, method); + int index = 0; + try { + index = CompilerToVMHelper + .getVtableIndexForInterfaceMethod(metaspaceKlass, + metaspaceMethod); + } catch (Throwable t) { + if (tcase.isPositive || tcase.expectedException == null) { + throw new Error("Caught unexpected exception " + t); + } + if (!tcase.expectedException.equals(t.getClass())) { + throw new Error(String.format("Caught %s while expected %s", + t.getClass().getName(), + tcase.expectedException.getName())); + } + return; + } + if (tcase.expectedException != null) { + throw new AssertionError("Expected exception wasn't caught: " + + tcase.expectedException.getName()); + } + if (tcase.isPositive) { + Asserts.assertNE(index, INVALID_VTABLE_INDEX, + "Unexpected: got invalid index"); + } else { + Asserts.assertEQ(index, INVALID_VTABLE_INDEX, + "Unexpected: got valid index "); + } + } + + private static class TestCase { + public final Class receiver; + public final Class holder; + public final String methodName; + public final boolean isPositive; + public final Class expectedException; + + public TestCase(Class receiver, Class holder, String methodName, + boolean isPositive, + Class expectedException) { + this.receiver = receiver; + this.holder = holder; + this.methodName = methodName; + this.isPositive = isPositive; + this.expectedException = expectedException; + } + + public TestCase(Class receiver, Class holder, String methodName, + boolean isPositive) { + this(receiver, holder, methodName, isPositive, null); + } + + @Override + public String toString() { + return String.format("CASE: receiver=%s, holder=%s, method=%s," + + " isPositive=%s%n", receiver.getName(), holder.getName(), + methodName, isPositive); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:-BackgroundCompilation + * compiler.jvmci.compilerToVM.HasCompiledCodeForOSRTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import compiler.testlibrary.CompilerUtils; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; +import sun.hotspot.code.NMethod; + +public class HasCompiledCodeForOSRTest { + public static void main(String[] args) { + ListtestCases = createTestCases(); + testCases.forEach(HasCompiledCodeForOSRTest::runSanityTest); + } + + public static List createTestCases() { + List testCases = new ArrayList<>(); + + try { + Class aClass = DummyClass.class; + testCases.add(new CompileCodeTestCase( + aClass.getMethod("withLoop"), 17)); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG : " + e.getMessage(), e); + } + return testCases; + } + + private static void runSanityTest(CompileCodeTestCase testCase) { + System.out.println(testCase); + Executable aMethod = testCase.executable; + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + testCase.deoptimize(); + int[] levels = CompilerUtils.getAvailableCompilationLevels(); + // not compiled + for (int level : levels) { + boolean isCompiled = CompilerToVMHelper.hasCompiledCodeForOSR( + method, testCase.bci, level); + Asserts.assertFalse(isCompiled, String.format( + "%s : unexpected return value for non-compiled method at " + + "level %d", testCase, level)); + } + NMethod nm = testCase.compile(); + if (nm == null) { + throw new Error(String.format( + "TEST BUG : %s : cannot compile method", testCase)); + } + + boolean isCompiled; + int level = nm.comp_level; + for (int i : levels) { + isCompiled = CompilerToVMHelper.hasCompiledCodeForOSR( + method, testCase.bci, i); + Asserts.assertEQ(isCompiled, level == i, String.format( + "%s : unexpected return value for compiled method at " + + "level %d", testCase, i)); + } + + for (int i : new int[] {-1, +1}) { + int bci = testCase.bci + i; + isCompiled = CompilerToVMHelper.hasCompiledCodeForOSR( + method, bci, level); + Asserts.assertFalse(isCompiled, String.format( + "%s : unexpected return value for compiled method at " + + "level %d with bci = %d ", + testCase, level, bci)); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.HasFinalizableSubclassTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.HasFinalizableSubclassTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.AbstractClassExtender; +import compiler.jvmci.common.testcases.DoNotImplementInterface; +import compiler.jvmci.common.testcases.MultipleImplementer1; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Stream; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class HasFinalizableSubclassTest { + public static void main(String args[]) { + HasFinalizableSubclassTest test = new HasFinalizableSubclassTest(); + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } + + private static Set createTestCases() { + Stream.of( + AbstractClassExtender.class, + SingleImplementerInterface.class, + MultipleImplementersInterface.class, + MultipleImplementer1.class, + DoNotImplementInterface.class) + .forEach(Utils::ensureClassIsLoaded); + Set result = new HashSet<>(); + // iface with finalize method + result.add(new TestCase(SingleImplementerInterface.class, false)); + // iface with default finalize method + result.add(new TestCase(MultipleImplementersInterface.class, false)); + // class which implements iface w/ default finalize method + result.add(new TestCase(MultipleImplementer1.class, true)); + // abstract class with finalizeable subclass + result.add(new TestCase(AbstractClass.class, true)); + // non-implemented iface + result.add(new TestCase(DoNotImplementInterface.class, false)); + return result; + } + + private void runTest(TestCase tcase) { + System.out.println(tcase); + HotSpotResolvedObjectTypeImpl metaspaceKlass = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.aClass), + getClass(), /* resolve = */ true); + Asserts.assertEQ(tcase.expected, + CompilerToVMHelper.hasFinalizableSubclass(metaspaceKlass), + "Unexpected finalizableSubclass state for " + + tcase.aClass.getName()); + } + + private static class TestCase { + public final Class aClass; + public final boolean expected; + + public TestCase(Class clazz, boolean expected) { + this.aClass = clazz; + this.expected = expected; + } + @Override + public String toString() { + return "CASE: class= " + aClass.getName() + ", expected=" + expected; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.InitializeConfigurationTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.InitializeConfigurationTest + */ + +package compiler.jvmci.compilerToVM; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Consumer; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.misc.Unsafe; + +public class InitializeConfigurationTest { + private static final Unsafe UNSAFE = Utils.getUnsafe(); + + public static void main(String args[]) { + new InitializeConfigurationTest().runTest(generateTestCases()); + } + + private static List generateTestCases() { + List result = new ArrayList<>(); + result.add(new TestCase("CodeCache", "_high_bound", "address", + InitializeConfigurationTest::verifyLongIsNotZero)); + result.add(new TestCase("StubRoutines", "_jint_arraycopy", "address", + InitializeConfigurationTest::verifyLongIsNotZero)); + return result; + } + + private static void verifyLongIsNotZero(Object o) { + Asserts.assertNotNull(o, "Got null value"); + Asserts.assertEQ(o.getClass(), Long.class, "Unexpected value type"); + Asserts.assertNE(o, 0L, "Got null address"); + } + + private void runTest(List tcases) { + VMStructDataReader reader = new VMStructDataReader( + CompilerToVMHelper.initializeConfiguration()); + while (reader.hasNext()) { + VMFieldData data = reader.next(); + for (TestCase tcase : tcases) { + tcase.check(data); + } + } + // now check if all passed + for (TestCase tcase: tcases) { + Asserts.assertTrue(tcase.isFound(), "Case failed: " + tcase); + } + } + + private static class VMStructDataReader implements Iterator { + // see jvmciCompilerToVM:105 static uintptr_t ciHotSpotVMData[28]; + private static final int HOTSPOT_VM_DATA_INDEX_COUNT = 28; + private final long addresses[]; + private final long vmStructsBase; + private final long entityNameFieldOffset; + private final long nameFieldOffset; + private final long typeStringFieldOffset; + private final long addressOffset; + private final long entrySize; + private long nextElementAddress; + private VMFieldData nextElement; + + public VMStructDataReader(long gHotSpotVMData) { + Asserts.assertNE(gHotSpotVMData, 0L, "Got null base address"); + addresses = new long[HOTSPOT_VM_DATA_INDEX_COUNT]; + for (int i = 0; i < HOTSPOT_VM_DATA_INDEX_COUNT; i++) { + addresses[i] = UNSAFE.getAddress( + gHotSpotVMData + Unsafe.ADDRESS_SIZE * i); + } + vmStructsBase = addresses[0]; + entityNameFieldOffset = addresses[1]; + nameFieldOffset = addresses[2]; + typeStringFieldOffset = addresses[3]; + addressOffset = addresses[6]; + entrySize = addresses[7]; + nextElementAddress = vmStructsBase; + nextElement = read(); + } + + @Override + public boolean hasNext() { + return nextElement != null; + } + + @Override + public VMFieldData next() { + if (nextElement == null) { + throw new NoSuchElementException("Next element is null"); + } + VMFieldData toReturn = nextElement; + nextElementAddress += entrySize; + nextElement = read(); + return toReturn; + } + + private VMFieldData read() { + String entityFieldName = readCString( + UNSAFE.getAddress(nextElementAddress + nameFieldOffset)); + if (entityFieldName == null) { + return null; + } + String fieldType = readCString(UNSAFE.getAddress( + nextElementAddress + typeStringFieldOffset)); + String entityName = readCString(UNSAFE.getAddress( + nextElementAddress + entityNameFieldOffset)); + Object value; + if ("address".equals(fieldType)) { + long address = UNSAFE.getAddress( + nextElementAddress + addressOffset); + value = address; + } else { + // non-address cases are not supported + value = null; + } + return new VMFieldData(entityName, entityFieldName, fieldType, + value); + } + + private static String readCString(long address) { + if (address == 0) { + return null; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0;; i++) { + char c = (char) UNSAFE.getByte(address + i); + if (c == 0) { + break; + } + sb.append(c); + } + return sb.toString(); + } + } + + private static class VMFieldData { + public final String entityFieldName; + public final String entityName; + public final String fieldType; + public final Object value; + + private VMFieldData(String entityName, String entityFieldName, + String fieldType, Object value) { + this.entityName = entityName; + this.entityFieldName = entityFieldName; + this.fieldType = fieldType; + this.value = value; + } + } + + private static class TestCase { + public final String entityName; + public final String fieldType; + public final String entityFieldName; + public final Consumer consumer; + private boolean found; + + public TestCase(String entityName, String entityFieldName, + String fieldType, Consumer predicate) { + Objects.requireNonNull(entityName, "Got null entityName"); + Objects.requireNonNull(entityFieldName, "Got null entityFieldName"); + Objects.requireNonNull(fieldType, "Got null type"); + if (!"address".equals(fieldType)) { + throw new Error("TESTBUG: unsupported testcase with fieldType=" + + fieldType); + } + this.entityName = entityName; + this.fieldType = fieldType; + this.entityFieldName = entityFieldName; + this.consumer = predicate; + this.found = false; + } + + public void check(VMFieldData data) { + if (entityFieldName.equals(data.entityFieldName) + && entityName.equals(data.entityName) + && fieldType.equals(data.fieldType)) { + Asserts.assertFalse(found, "Found 2 entries of " + this); + found = true; + consumer.accept(data.value); + } + } + + @Override + public String toString() { + return "CASE: entityName=" + entityName + " entityFieldName=" + + entityFieldName + " fieldType=" + fieldType; + } + + public boolean isFound() { + return found; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @ignore 8139700 + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.code.NMethod; + +import java.util.List; + +public class InvalidateInstalledCodeTest { + public static void main(String[] args) { + InvalidateInstalledCodeTest test + = new InvalidateInstalledCodeTest(); + List testCases + = CompileCodeTestCase.generate(/* bci = */ 0); + testCases.addAll(CompileCodeTestCase.generate(/* bci = */ -1)); + testCases.forEach(test::check); + test.checkNull(); + } + + private void checkNull() { + InstalledCode installedCode = new InstalledCode(""); + installedCode.setAddress(0); + CompilerToVMHelper.invalidateInstalledCode(installedCode); + } + + private void check(CompileCodeTestCase testCase) { + System.out.println(testCase); + // to have a clean state + NMethod beforeInvalidation = testCase.deoptimizeAndCompile(); + if (beforeInvalidation == null) { + throw new Error("method is not compiled, testCase " + testCase); + } + + // run twice to verify how it works if method is already invalidated + for (int i = 0; i < 2; ++i) { + InstalledCode installedCode = new InstalledCode( + testCase.executable.getName()); + installedCode.setAddress(beforeInvalidation.address); + + CompilerToVMHelper.invalidateInstalledCode(installedCode); + NMethod afterInvalidation = testCase.toNMethod(); + if (afterInvalidation != null) { + System.err.println("before: " + beforeInvalidation); + System.err.println("after: " + afterInvalidation); + throw new AssertionError(testCase + + " : method hasn't been invalidated, i = " + i); + } + Asserts.assertFalse(installedCode.isValid(), testCase + + " : code is valid after invalidation, i = " + i); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox IsMatureTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.IsMatureTest + */ +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.SimpleClass; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +import java.lang.reflect.Executable; + +public class IsMatureTest { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) throws Exception { + new IsMatureTest().test(); + } + + public void test() throws Exception { + SimpleClass sclass = new SimpleClass(); + Executable method = SimpleClass.class.getDeclaredMethod("testMethod"); + long metaspaceMethodData = WB.getMethodData(method); + Asserts.assertEQ(metaspaceMethodData, 0L, "MDO should be null for " + + "never invoked method"); + boolean isMature = CompilerToVMHelper.isMature(metaspaceMethodData); + Asserts.assertFalse(isMature, "null MDO can't be mature"); + for (int i = 0; i < 1000; i++) { + sclass.testMethod(); + } + // warmed up, mdo should be ready for now + metaspaceMethodData = WB.getMethodData(method); + Asserts.assertNE(metaspaceMethodData, 0L, + "MDO should be available after 1000 calls"); + for (int i = 0; i < 100_000; i++) { + sclass.testMethod(); + } + isMature = CompilerToVMHelper.isMature(metaspaceMethodData); + Asserts.assertTrue(isMature, + "a 100_000 times invoked method should be mature"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/JVM_RegisterJVMCINatives.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary / + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Dcompiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives.positive=true + * -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Dcompiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives.positive=false + * -XX:-EnableJVMCI + * compiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives + + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVM; +import jdk.vm.ci.runtime.JVMCI; +import jdk.test.lib.Asserts; + +import java.lang.reflect.Method; + +public class JVM_RegisterJVMCINatives { + private static final boolean IS_POSITIVE = Boolean.getBoolean( + "compiler.jvmci.compilerToVM.JVM_RegisterJVMCINatives.positive"); + + private final Method registerNatives; + + public static void main(String[] args) { + new JVM_RegisterJVMCINatives().runTest(); + } + + private void runTest() { + Object result; + try { + result = invoke(); + } catch (InternalError e) { + if (IS_POSITIVE) { + throw new AssertionError("unexpected exception", e); + } + return; + } + if (!IS_POSITIVE) { + throw new AssertionError("didn't get expected exception"); + } + Asserts.assertNull(result, + "registerNatives()V returned non-null"); + Asserts.assertEQ(result, invoke(), + "registerNatives returns different results"); + + } + private Object invoke() { + Object result; + try { + result = registerNatives.invoke(JVMCI.class); + } catch (ReflectiveOperationException e) { + throw new Error("can't invoke registerNatives", e); + } + return result; + } + + private JVM_RegisterJVMCINatives() { + Method method; + try { + method = CompilerToVM.class.getDeclaredMethod("registerNatives"); + method.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new Error("can't find CompilerToVM::registerNatives", e); + } + registerNatives = method; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @summary Testing compiler.jvmci.CompilerToVM.lookupKlassInPool method + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.common.testcases.MultipleImplementersInterface + * compiler.jvmci.common.testcases.MultipleImplementer2 + * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper + * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * compiler.jvmci.compilerToVM.LookupKlassInPoolTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.LookupKlassInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import sun.reflect.ConstantPool; + +/** + * Test for {@code compiler.jvmci.CompilerToVM.lookupKlassInPool} method + */ +public class LookupKlassInPoolTest { + + public static void main(String[] args) { + Map typeTests = new HashMap<>(1); + typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, + LookupKlassInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + } + + public static void validate(HotSpotConstantPool constantPoolCTVM, + ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { + Object classToVerify = CompilerToVMHelper + .lookupKlassInPool(constantPoolCTVM, i); + if (!(classToVerify instanceof HotSpotResolvedObjectTypeImpl) + && !(classToVerify instanceof String)) { + String msg = String.format("Output of method" + + " CTVM.lookupKlassInPool is neither" + + " a HotSpotResolvedObjectTypeImpl, nor a String"); + throw new AssertionError(msg); + } + int classNameIndex = (int) dummyClass.cp.get(i).value; + String classNameToRefer + = constantPoolSS.getUTF8At(classNameIndex); + String outputToVerify = classToVerify.toString(); + if (!outputToVerify.contains(classNameToRefer)) { + String msg = String.format("Wrong class accessed by constant" + + " pool index %d: %s, but should be %s", + i, outputToVerify, classNameToRefer); + throw new AssertionError(msg); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.LookupTypeTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.LookupTypeTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.DoNotExtendClass; +import compiler.jvmci.common.testcases.MultiSubclassedClass; +import compiler.jvmci.common.testcases.SingleSubclass; +import java.util.HashSet; +import java.util.Set; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +public class LookupTypeTest { + public static void main(String args[]) { + LookupTypeTest test = new LookupTypeTest(); + for (TestCase tcase : createTestCases()) { + test.runTest(tcase); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + // a primitive class + result.add(new TestCase(Utils.toJVMTypeSignature(int.class), + LookupTypeTest.class, true, false, InternalError.class)); + // lookup not existing class + result.add(new TestCase("Lsome_not_existing;", LookupTypeTest.class, + true, false, ClassNotFoundException.class)); + // lookup invalid classname + result.add(new TestCase("L!@#$%^&**()[]{}?;", LookupTypeTest.class, + true, false, ClassNotFoundException.class)); + // lookup package private class + result.add(new TestCase( + "Lcompiler/jvmci/compilerToVM/testcases/PackagePrivateClass;", + LookupTypeTest.class, true, false, + ClassNotFoundException.class)); + // lookup usual class with resolve=true + result.add(new TestCase(Utils.toJVMTypeSignature(SingleSubclass.class), + LookupTypeTest.class, true, true)); + // lookup usual class with resolve=false + result.add(new TestCase( + Utils.toJVMTypeSignature(DoNotExtendClass.class), + LookupTypeTest.class, false, true)); + // lookup usual class with null accessor + result.add(new TestCase( + Utils.toJVMTypeSignature(MultiSubclassedClass.class), null, + false, false, NullPointerException.class)); + return result; + } + + private void runTest(TestCase tcase) { + System.out.println(tcase); + HotSpotResolvedObjectTypeImpl metaspaceKlass; + try { + metaspaceKlass = CompilerToVMHelper.lookupType(tcase.className, + tcase.accessing, tcase.resolve); + } catch (Throwable t) { + Asserts.assertNotNull(tcase.expectedException, + "Assumed no exception, but got " + t); + Asserts.assertFalse(tcase.isPositive, + "Got unexpected exception " + t); + Asserts.assertEQ(t.getClass(), tcase.expectedException, + "Unexpected exception"); + // passed + return; + } + if (tcase.expectedException != null) { + throw new AssertionError("Expected exception was not thrown: " + + tcase.expectedException.getName()); + } + if (tcase.isPositive) { + Asserts.assertNotNull(metaspaceKlass, + "Unexpected null metaspace klass"); + Asserts.assertEQ(metaspaceKlass.getName(), tcase.className, + "Got unexpected resolved class name"); + } else { + Asserts.assertNull(metaspaceKlass, "Unexpected metaspace klass"); + } + } + + private static class TestCase { + public final String className; + public final Class accessing; + public final boolean resolve; + public final boolean isPositive; + public final Class expectedException; + + public TestCase(String className, Class accessing, boolean resolve, + boolean isPositive, + Class expectedException) { + this.className = className; + this.accessing = accessing; + this.resolve = resolve; + this.isPositive = isPositive; + this.expectedException = expectedException; + } + + public TestCase(String className, Class accessing, boolean resolve, + boolean isPositive) { + this.className = className; + this.accessing = accessing; + this.resolve = resolve; + this.isPositive = isPositive; + this.expectedException = null; + } + + @Override + public String toString() { + return String.format("CASE: class=%s, accessing=%s," + + " resolve=%s, positive=%s, expectedException=%s", className, + accessing, resolve, isPositive, expectedException); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @ignore 8139703 + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox MaterializeVirtualObjectTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:CompileCommand=exclude,*::check -XX:+DoEscapeAnalysis -Xbatch + * -Dcompiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate=false + * compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:CompileCommand=exclude,*::check -XX:+DoEscapeAnalysis -Xbatch + * -Dcompiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate=true + * compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import compiler.testlibrary.CompilerUtils; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; +import java.lang.reflect.Method; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotStackFrameReference; + +public class MaterializeVirtualObjectTest { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final Method METHOD; + private static final HotSpotResolvedJavaMethodImpl RESOLVED_METHOD; + private static final boolean INVALIDATE = Boolean.getBoolean( + "compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate"); + + static { + try { + METHOD = MaterializeVirtualObjectTest.class.getDeclaredMethod( + "testFrame", String.class, boolean.class); + } catch (NoSuchMethodException e) { + throw new Error("Can't get executable for test method", e); + } + RESOLVED_METHOD = CTVMUtilities.getResolvedMethod(METHOD); + } + + public static void main(String[] args) { + int levels[] = CompilerUtils.getAvailableCompilationLevels(); + // we need compilation level 4 to use EscapeAnalysis + if (levels.length < 1 || levels[levels.length - 1] != 4) { + System.out.println("INFO: Test needs compilation level 4 to" + + " be available. Skipping."); + } else { + new MaterializeVirtualObjectTest().test(); + } + } + + private static String getName() { + return "CASE: invalidate=" + INVALIDATE; + } + + private void test() { + System.out.println(getName()); + Asserts.assertFalse(WB.isMethodCompiled(METHOD), getName() + + " : method unexpectedly compiled"); + /* need to call testFrame at least once to be able to compile it, so + calling with materialize=false, because testFrame is not compiled */ + testFrame("someString", /* materialize= */ false); + WB.enqueueMethodForCompilation(METHOD, 4); + Asserts.assertTrue(WB.isMethodCompiled(METHOD), getName() + + "Method unexpectedly not compiled"); + // calling with materialize=true to materialize compiled testFrame + testFrame("someString", /* materialize= */ true); + } + + private void testFrame(String str, boolean materialize) { + Helper helper = new Helper(str); + check(materialize); + Asserts.assertTrue((helper.string != null) && (this != null) + && (helper != null), getName() + " : some locals are null"); + } + + private void check(boolean materialize) { + // Materialize virtual objects on last invocation + if (materialize) { + HotSpotStackFrameReference hsFrame = CompilerToVMHelper + .getNextStackFrame(/* topmost frame */ null, + new HotSpotResolvedJavaMethodImpl[]{ + RESOLVED_METHOD}, /* don't skip any */ 0); + Asserts.assertNotNull(hsFrame, getName() + " : got null frame"); + Asserts.assertTrue(WB.isMethodCompiled(METHOD), getName() + + "Test method should be compiled"); + Asserts.assertTrue(hsFrame.hasVirtualObjects(), getName() + + ": has no virtual object before materialization"); + CompilerToVMHelper.materializeVirtualObjects(hsFrame, INVALIDATE); + Asserts.assertFalse(hsFrame.hasVirtualObjects(), getName() + + " : has virtual object after materialization"); + Asserts.assertEQ(WB.isMethodCompiled(METHOD), !INVALIDATE, getName() + + " : unexpected compiled status"); + } + } + + private class Helper { + public String string; + + public Helper(String s) { + this.string = s; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.MethodIsIgnoredBySecurityStackWalkTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Method; +import java.lang.reflect.Executable; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class MethodIsIgnoredBySecurityStackWalkTest { + + public static void main(String[] args) { + Map testCases = createTestCases(); + testCases.forEach( + MethodIsIgnoredBySecurityStackWalkTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod, Boolean expected) { + HotSpotResolvedJavaMethodImpl method + = CTVMUtilities.getResolvedMethod(aMethod); + boolean isIgnored = CompilerToVMHelper + .methodIsIgnoredBySecurityStackWalk(method); + String msg = String.format("%s is%s ignored but must%s", aMethod, + isIgnored ? "" : " not", + expected ? "" : " not"); + Asserts.assertEQ(isIgnored, expected, msg); + } + + private static Map createTestCases() { + Map testCases = new HashMap<>(); + + try { + Class aClass = Method.class; + testCases.put(aClass.getMethod("invoke", Object.class, + Object[].class), true); + + aClass = Class.forName("sun.reflect.NativeMethodAccessorImpl"); + testCases.put(aClass.getMethod("invoke", Object.class, + Object[].class), true); + testCases.put(aClass.getDeclaredMethod("invoke0", Method.class, + Object.class, Object[].class), true); + + aClass = MethodIsIgnoredBySecurityStackWalkTest.class; + for (Executable method : aClass.getMethods()) { + testCases.put(method, false); + } + for (Executable method : aClass.getDeclaredMethods()) { + testCases.put(method, false); + } + for (Executable method : aClass.getConstructors()) { + testCases.put(method, false); + } + } catch (NoSuchMethodException | ClassNotFoundException e) { + throw new Error("TEST BUG " + e.getMessage(), e); + } + return testCases; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.ReadUncompressedOopTest + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:-UseCompressedOops + * compiler.jvmci.compilerToVM.ReadUncompressedOopTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UseCompressedOops + * compiler.jvmci.compilerToVM.ReadUncompressedOopTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +public class ReadUncompressedOopTest { + + public static void main(String args[]) { + new ReadUncompressedOopTest().runTest(); + } + + private void runTest() { + long ptr = getPtr(); + System.out.printf("calling readUncompressedOop(0x%x)%n", ptr); + Asserts.assertEQ(getClass(), + CompilerToVMHelper.readUncompressedOop(ptr), + String.format("unexpected class returned for 0x%x", ptr)); + } + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final Class CLASS = ReadUncompressedOopTest.class; + private static final long PTR = WB.getObjectAddress(CLASS); + + private static long getPtr() { + Field field; + try { + field = CLASS.getDeclaredField("PTR"); + } catch (NoSuchFieldException nsfe) { + throw new Error("TESTBUG : " + nsfe, nsfe); + } + Object base = UNSAFE.staticFieldBase(field); + return WB.getObjectAddress(base) + UNSAFE.staticFieldOffset(field); + } +} + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xmixed + * compiler.jvmci.compilerToVM.ReprofileTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ProfilingInfo; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.hotspot.WhiteBox; + +public class ReprofileTest { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + List testCases = createTestCases(); + testCases.forEach(ReprofileTest::runSanityTest); + } + + private static List createTestCases() { + List testCases = new ArrayList<>(); + try { + + Class aClass = DummyClass.class; + testCases.add(aClass.getMethod("withLoop")); + + aClass = DummyClass.class; + testCases.add(aClass.getDeclaredMethod("dummyFunction")); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG " + e.getMessage(), e); + } + return testCases; + } + + private static void runSanityTest(Method aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + ProfilingInfo startProfile = method.getProfilingInfo(); + Asserts.assertFalse(startProfile.isMature(), aMethod + + " : profiling info is mature in the begging"); + + long compileThreshold = (Long) WB.getVMFlag("CompileThreshold"); + // make interpreter to profile this method + try { + Object obj = aMethod.getDeclaringClass().newInstance(); + for (long i = 0; i < compileThreshold; i++) { + aMethod.invoke(obj); + } + } catch (ReflectiveOperationException e) { + throw new Error("TEST BUG : " + e.getMessage(), e); + } + ProfilingInfo compProfile = method.getProfilingInfo(); + + Asserts.assertNE(startProfile.toString(), compProfile.toString(), + String.format("%s : profiling info wasn't changed after " + + "%d invocations", + aMethod, compileThreshold)); + Asserts.assertTrue(compProfile.isMature(), + String.format("%s is not mature after %d invocations", + aMethod, compileThreshold)); + + CompilerToVMHelper.reprofile(method); + ProfilingInfo reprofiledProfile = method.getProfilingInfo(); + + Asserts.assertNE(startProfile.toString(), reprofiledProfile.toString(), + aMethod + " : profiling info wasn't changed after reprofiling"); + Asserts.assertNE(compProfile.toString(), reprofiledProfile.toString(), + aMethod + " : profiling info didn't change after reprofile"); + Asserts.assertFalse(reprofiledProfile.isMature(), aMethod + + " : profiling info is mature after reprofiling"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.ResolveConstantInPoolTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ResolveConstantInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.test.lib.Asserts; +import sun.reflect.ConstantPool; + +/** + * Test for {@code compiler.jvmci.CompilerToVM.resolveConstantInPool} method + */ +public class ResolveConstantInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(2); + typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODHANDLE, + ResolveConstantInPoolTest::validateMethodHandle); + typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODTYPE, + ResolveConstantInPoolTest::validateMethodType); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + } + + private static void validateMethodHandle(HotSpotConstantPool constantPoolCTVM, + ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { + Object constantInPool = CompilerToVMHelper + .resolveConstantInPool(constantPoolCTVM, index); + if (!(constantInPool instanceof MethodHandle)) { + String msg = String.format( + "Wrong constant pool entry accessed by index" + + " %d: %s, but should be subclass of %s", + index + 1, constantInPool.getClass(), + MethodHandle.class.getName()); + throw new AssertionError(msg); + } + } + + private static void validateMethodType(HotSpotConstantPool constantPoolCTVM, + ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { + Object constantInPool = CompilerToVMHelper + .resolveConstantInPool(constantPoolCTVM, index); + Class mtToVerify = constantInPool.getClass(); + Class mtToRefer = MethodType.class; + String msg = String.format("Wrong %s accessed by constant pool index" + + " %d: %s, but should be %s", "method type class", + index, mtToVerify, mtToRefer); + Asserts.assertEQ(mtToRefer, mtToVerify, msg); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.ResolveMethodTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.ResolveMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.testcases.AbstractClass; +import compiler.jvmci.common.testcases.AbstractClassExtender; +import compiler.jvmci.common.testcases.MultipleImplementer1; +import compiler.jvmci.common.testcases.MultipleImplementer2; +import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.common.testcases.SingleImplementer; +import compiler.jvmci.common.testcases.SingleImplementerInterface; +import compiler.jvmci.common.testcases.SingleSubclass; +import compiler.jvmci.common.testcases.SingleSubclassedClass; +import compiler.jvmci.common.CTVMUtilities; +import java.util.HashSet; +import java.util.Set; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.misc.Unsafe; + +public class ResolveMethodTest { + private static final Unsafe UNSAFE = Utils.getUnsafe(); + + public static void main(String args[]) { + ResolveMethodTest test = new ResolveMethodTest(); + // positive cases + try { + for (TestCase tcase: createTestCases()) { + test.runTest(tcase); + } + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find requested method", e); + } + } + + private static Set createTestCases() { + Set result = new HashSet<>(); + // a usual class public method + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "usualMethod", ResolveMethodTest.class, true)); + // an array method + result.add(new TestCase(int[].class, Object.class, "toString", + ResolveMethodTest.class, true)); + // a method from base class, which was overriden in tested one + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "overridenMethod", ResolveMethodTest.class, true)); + // a method from base class, which was not overriden in tested one + result.add(new TestCase(SingleSubclass.class, + SingleSubclassedClass.class, "inheritedMethod", + ResolveMethodTest.class, true)); + /* a method from base class, which was overriden in tested one with + base class as holder */ + result.add(new TestCase(SingleSubclass.class, + SingleSubclassedClass.class, "overridenMethod", + ResolveMethodTest.class, true)); + // an interface method + result.add(new TestCase(SingleImplementer.class, + SingleImplementerInterface.class, "interfaceMethod", + ResolveMethodTest.class, true)); + // an interface default method overriden in implementer + result.add(new TestCase(MultipleImplementer1.class, + MultipleImplementersInterface.class, "defaultMethod", + ResolveMethodTest.class, true)); + // an interface default method not overriden in implementer + result.add(new TestCase(MultipleImplementer2.class, + MultipleImplementersInterface.class, "defaultMethod", + ResolveMethodTest.class, true)); + // an abstract method + result.add(new TestCase(AbstractClassExtender.class, AbstractClass.class, + "abstractMethod", ResolveMethodTest.class, true)); + // private method with right accessor + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "privateMethod", SingleSubclass.class, true)); + // package-private method with right accessor + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "defaultAccessMethod", SingleSubclass.class, true)); + + // negative cases + + // private method of another class + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "privateMethod", ResolveMethodTest.class, false)); + // package-private method from another package + result.add(new TestCase(SingleSubclass.class, SingleSubclass.class, + "defaultAccessMethod", ResolveMethodTest.class, false)); + return result; + } + + private void runTest(TestCase tcase) throws NoSuchMethodException { + System.out.println(tcase); + HotSpotResolvedJavaMethodImpl metaspaceMethod = CTVMUtilities + .getResolvedMethod(tcase.holder, + tcase.holder.getDeclaredMethod(tcase.methodName)); + HotSpotResolvedObjectTypeImpl holderMetaspace = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.holder), + getClass(), /* resolve = */ true); + HotSpotResolvedObjectTypeImpl callerMetaspace = CompilerToVMHelper + .lookupType(Utils.toJVMTypeSignature(tcase.caller), + getClass(), /* resolve = */ true); + HotSpotResolvedJavaMethodImpl resolvedMetaspaceMethod + = CompilerToVMHelper.resolveMethod(holderMetaspace, + metaspaceMethod, callerMetaspace); + if (tcase.isPositive) { + Asserts.assertNotNull(resolvedMetaspaceMethod, + "Unexpected null resolved method value for " + + tcase.methodName); + Asserts.assertEQ(metaspaceMethod.getName(), tcase.methodName, + "Reflection and c2vm method names doesn't match"); + } else { + Asserts.assertNull(resolvedMetaspaceMethod, + "Method unexpectedly resolved"); + } + } + + private static class TestCase { + public final Class receiver; + public final Class holder; + public final Class caller; + public final String methodName; + public final boolean isPositive; + + public TestCase(Class recv, Class holder, String methodName, + Class caller, boolean isPositive) { + this.receiver = recv; + this.holder = holder; + this.caller = caller; + this.methodName = methodName; + this.isPositive = isPositive; + } + + @Override + public String toString() { + return String.format("CASE: receiver=%s, holder=%s, method=%s," + + "caller=%s, isPositive=%s%n", receiver.getName(), + holder.getName(), methodName, caller.getName(), isPositive); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @summary Testing compiler.jvmci.CompilerToVM.resolveTypeInPool method + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.common.testcases.MultipleImplementersInterface + * compiler.jvmci.common.testcases.MultipleImplementer2 + * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper + * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * compiler.jvmci.compilerToVM.ResolveTypeInPoolTest + * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.ResolveTypeInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotConstantPool; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl; +import sun.reflect.ConstantPool; + +/** + * Test for {@code compiler.jvmci.CompilerToVM.resolveTypeInPool} method + */ +public class ResolveTypeInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(1); + typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, + ResolveTypeInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + } + + public static void validate(HotSpotConstantPool constantPoolCTVM, + ConstantPool constantPoolSS, + ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { + HotSpotResolvedObjectTypeImpl typeToVerify = CompilerToVMHelper + .resolveTypeInPool(constantPoolCTVM, i); + int classNameIndex = (int) dummyClass.cp.get(i).value; + String classNameToRefer = constantPoolSS.getUTF8At(classNameIndex); + String outputToVerify = typeToVerify.toString(); + if (!outputToVerify.contains(classNameToRefer)) { + String msg = String.format("Wrong class accessed by constant" + + " pool index %d: %s, but should be %s", + i, outputToVerify, classNameToRefer); + throw new AssertionError(msg); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary /../../test/lib/ + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest + * @run main ClassFileInstaller + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+DebugNonSafepoints + * -Dcompiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected=true + * compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest + * @run main/othervm + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:-DebugNonSafepoints + * -Dcompiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected=false + * compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest + */ + +package compiler.jvmci.compilerToVM; + +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.test.lib.Asserts; + +public class ShouldDebugNonSafepointsTest { + private static final boolean EXPECTED = Boolean.getBoolean("compiler" + + ".jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected"); + + public static void main(String args[]) { + new ShouldDebugNonSafepointsTest().runTest(); + } + + private void runTest() { + Asserts.assertEQ(CompilerToVMHelper.shouldDebugNonSafepoints(), + EXPECTED, "Unexpected shouldDebugnonSafepoints value"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary /../../test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.jvmci.compilerToVM.ShouldInlineMethodTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.common.CTVMUtilities; +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +public class ShouldInlineMethodTest { + + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + List testCases = createTestCases(); + testCases.forEach(ShouldInlineMethodTest::runSanityTest); + } + + private static void runSanityTest(Executable aMethod) { + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(aMethod); + boolean shouldInline = CompilerToVMHelper.shouldInlineMethod(method); + boolean expectedShouldInline = WB.testSetForceInlineMethod(aMethod, + true); + Asserts.assertEQ(shouldInline, expectedShouldInline, + "Unexpected value of property 'should inline'"); + + shouldInline = CompilerToVMHelper.shouldInlineMethod(method); + Asserts.assertTrue(shouldInline, "Unexpected value of property " + + "'should inline' after setting 'force inline' to true"); + WB.testSetForceInlineMethod(aMethod, false); + shouldInline = CompilerToVMHelper.shouldInlineMethod(method); + Asserts.assertFalse(shouldInline, "Unexpected value of property " + + "'should inline' after setting 'force inline' to false"); + } + + private static List createTestCases() { + List testCases = new ArrayList<>(); + + Class aClass = DummyClass.class; + testCases.addAll(Arrays.asList(aClass.getDeclaredMethods())); + testCases.addAll(Arrays.asList(aClass.getDeclaredConstructors())); + return testCases; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.config Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +compiler.jvmci.events.JvmciCompleteInitializationTest diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/JvmciCompleteInitializationTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @build compiler.jvmci.common.JVMCIHelpers + * compiler.jvmci.events.JvmciCompleteInitializationTest + * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ + * @run main jdk.test.lib.FileInstaller ./JvmciCompleteInitializationTest.config + * ./META-INF/services/jdk.vm.ci.hotspot.HotSpotVMEventListener + * @run main ClassFileInstaller + * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler + * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory + * compiler.jvmci.events.JvmciCompleteInitializationTest + * jdk.test.lib.Asserts + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Xbootclasspath/a:. + * -XX:+EnableJVMCI + * -Dcompiler.jvmci.events.JvmciCompleteInitializationTest.positive=true + * compiler.jvmci.events.JvmciCompleteInitializationTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Xbootclasspath/a:. + * -XX:-EnableJVMCI + * -Dcompiler.jvmci.events.JvmciCompleteInitializationTest.positive=false + * compiler.jvmci.events.JvmciCompleteInitializationTest + */ + +package compiler.jvmci.events; + +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; + +public class JvmciCompleteInitializationTest implements HotSpotVMEventListener { + private static final boolean IS_POSITIVE = Boolean.getBoolean( + "compiler.jvmci.events.JvmciCompleteInitializationTest.positive"); + private static volatile int completeInitializationCount = 0; + private static volatile String errorMessage = ""; + + public static void main(String args[]) { + if (completeInitializationCount != 0) { + throw new Error("Unexpected completeInitialization events" + + " count at start"); + } + initializeRuntime(); + int expectedEventCount = IS_POSITIVE ? 1 : 0; + Asserts.assertEQ(completeInitializationCount, expectedEventCount, + "Unexpected completeInitialization events count" + + " after JVMCI init"); + initializeRuntime(); + Asserts.assertEQ(completeInitializationCount, expectedEventCount, + "Unexpected completeInitialization events count" + + " after 2nd JVMCI init"); + Asserts.assertTrue(errorMessage.isEmpty(), errorMessage); + } + + private static void initializeRuntime() { + Error t = null; + try { + /* in case JVMCI disabled, an InternalError on initialization + and NoClassDefFound on 2nd try */ + HotSpotJVMCIRuntime.runtime(); + } catch (Error e) { + t = e; + } + if (IS_POSITIVE) { + Asserts.assertNull(t, "Caught unexpected exception"); + } else { + Asserts.assertNotNull(t, "Got no expected error"); + } + } + + @Override + public void completeInitialization(HotSpotJVMCIRuntime + hotSpotJVMCIRuntime) { + completeInitializationCount++; + if (hotSpotJVMCIRuntime == null) { + errorMessage += " HotSpotJVMCIRuntime is null."; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.config Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +compiler.jvmci.events.JvmciCreateMetaAccessContextTest diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @compile ./MetaAccessWrapper.java + * @build compiler.jvmci.common.JVMCIHelpers + * compiler.jvmci.events.JvmciCreateMetaAccessContextTest + * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ + * @run main jdk.test.lib.FileInstaller + * ./JvmciCreateMetaAccessContextTest.config + * ./META-INF/services/jdk.vm.ci.hotspot.HotSpotVMEventListener + * @run main ClassFileInstaller + * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler + * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory + * compiler.jvmci.events.JvmciCreateMetaAccessContextTest + * jdk.vm.ci.hotspot.MetaAccessWrapper + * jdk.test.lib.Asserts + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * -Dcompiler.jvmci.events.JvmciCreateMetaAccessContextTest.providenull=true + * compiler.jvmci.events.JvmciCreateMetaAccessContextTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xbootclasspath/a:. + * -Dcompiler.jvmci.events.JvmciCreateMetaAccessContextTest.providenull=false + * compiler.jvmci.events.JvmciCreateMetaAccessContextTest + */ + +package compiler.jvmci.events; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; +import jdk.vm.ci.hotspot.MetaAccessWrapper; +import jdk.vm.ci.meta.JVMCIMetaAccessContext; +import jdk.test.lib.Asserts; + +public class JvmciCreateMetaAccessContextTest + implements HotSpotVMEventListener { + private static final boolean PROVIDE_NULL_CONTEXT = Boolean.getBoolean( + "compiler.jvmci.events.JvmciCreateMetaAccessContextTest" + + ".providenull"); + private static volatile int createMetaAccessContextCount = 0; + private static volatile String errorMessage = ""; + + public static void main(String args[]) { + if (createMetaAccessContextCount != 0) { + throw new Error("Unexpected createMetaAccessContextevents count" + + " at test start"); + } + JVMCIMetaAccessContext context; + context = HotSpotJVMCIRuntime.runtime().getMetaAccessContext(); + Asserts.assertNotNull(context, + "JVMCIMetaAccessContext is null after 1st request"); + Asserts.assertEQ(createMetaAccessContextCount, 1, + "Unexpected createMetaAccessContext events count after 1st" + + " JVMCI runtime request"); + context = HotSpotJVMCIRuntime.runtime().getMetaAccessContext(); + Asserts.assertNotNull(context, + "JVMCIMetaAccessContext is null after 2nd request"); + Asserts.assertEQ(createMetaAccessContextCount, 1, + "Unexpected createMetaAccessContext events count after 2nd" + + " JVMCI runtime request"); + Asserts.assertTrue(errorMessage.isEmpty(), errorMessage); + if (PROVIDE_NULL_CONTEXT) { + Asserts.assertFalse(context instanceof MetaAccessWrapper, + "Got unexpected context: " + context.getClass()); + } else { + Asserts.assertTrue(context instanceof MetaAccessWrapper, + "Got unexpected context: " + context.getClass()); + } + } + + @Override + public JVMCIMetaAccessContext createMetaAccessContext(HotSpotJVMCIRuntime + hotSpotJVMCIRuntime) { + createMetaAccessContextCount++; + if (hotSpotJVMCIRuntime == null) { + errorMessage += " HotSpotJVMCIRuntime is null."; + } + if (PROVIDE_NULL_CONTEXT) { + return null; + } + return new MetaAccessWrapper(); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.config Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +compiler.jvmci.events.JvmciNotifyInstallEventTest diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library / /testlibrary + * @compile ../common/CompilerToVMHelper.java + * @build compiler.jvmci.common.JVMCIHelpers + * compiler.jvmci.events.JvmciNotifyInstallEventTest + * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ + * @run main jdk.test.lib.FileInstaller ./JvmciNotifyInstallEventTest.config + * ./META-INF/services/jdk.vm.ci.hotspot.HotSpotVMEventListener + * @run main ClassFileInstaller + * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler + * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory + * compiler.jvmci.events.JvmciNotifyInstallEventTest + * compiler.jvmci.common.CTVMUtilities + * compiler.jvmci.common.testcases.SimpleClass + * jdk.vm.ci.hotspot.CompilerToVMHelper + * jdk.test.lib.Asserts + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Djvmci.compiler=EmptyCompiler -Xbootclasspath/a:. -Xmixed + * -XX:+UseJVMCICompiler -XX:-BootstrapJVMCI + * -Dcompiler.jvmci.events.JvmciNotifyInstallEventTest.noevent=false + * compiler.jvmci.events.JvmciNotifyInstallEventTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-EnableJVMCI + * -Djvmci.compiler=EmptyCompiler -Xbootclasspath/a:. -Xmixed + * -Dcompiler.jvmci.events.JvmciNotifyInstallEventTest.noevent=true + * compiler.jvmci.events.JvmciNotifyInstallEventTest + */ + +package compiler.jvmci.events; + +import compiler.jvmci.common.CTVMUtilities; +import compiler.jvmci.common.testcases.SimpleClass; +import jdk.test.lib.Asserts; +import java.lang.reflect.Method; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; +import jdk.vm.ci.code.CompilationResult; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl; + +public class JvmciNotifyInstallEventTest implements HotSpotVMEventListener { + private static final String METHOD_NAME = "testMethod"; + private static final boolean IS_POSITIVE = !Boolean.getBoolean( + "compiler.jvmci.events.JvmciNotifyInstallEventTest.noevent"); + private static volatile int gotInstallNotification = 0; + + public static void main(String args[]) { + new JvmciNotifyInstallEventTest().runTest(); + } + + private void runTest() { + if (gotInstallNotification != 0) { + throw new Error("Got install notification before test actions"); + } + HotSpotCodeCacheProvider codeCache = null; + try { + codeCache = (HotSpotCodeCacheProvider) HotSpotJVMCIRuntime.runtime() + .getHostJVMCIBackend().getCodeCache(); + } catch (InternalError ie) { + if (IS_POSITIVE) { + throw new AssertionError( + "Got unexpected InternalError trying to get code cache", + ie); + } + // passed + return; + } + Asserts.assertTrue(IS_POSITIVE, + "Haven't caught InternalError in negative case"); + Method testMethod; + try { + testMethod = SimpleClass.class.getDeclaredMethod(METHOD_NAME); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: Can't find " + METHOD_NAME, e); + } + HotSpotResolvedJavaMethodImpl method = CTVMUtilities + .getResolvedMethod(SimpleClass.class, testMethod); + CompilationResult compResult = new CompilationResult(METHOD_NAME); + // to pass sanity check of default -1 + compResult.setTotalFrameSize(0); + codeCache.installMethod(method, compResult, /* jvmciEnv = */ 0L, + /* isDefault = */ false); + Asserts.assertEQ(gotInstallNotification, 1, + "Got unexpected event count after 1st install attempt"); + // since "empty" compilation result is ok, a second attempt should be ok + codeCache.installMethod(method, compResult, /* jvmciEnv = */ 0L, + /* isDefault = */ false); + Asserts.assertEQ(gotInstallNotification, 2, + "Got unexpected event count after 2nd install attempt"); + } + + @Override + public void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, + InstalledCode installedCode, CompilationResult compResult) { + gotInstallNotification++; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/JvmciShutdownEventListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventListener.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 compiler.jvmci.events; + +import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotVMEventListener; + +public class JvmciShutdownEventListener implements HotSpotVMEventListener { + public static final String MESSAGE = "Shutdown notified"; + public static final String GOT_INTERNAL_ERROR = "Got internal error"; + + public static void main(String args[]) { + try { + HotSpotJVMCIRuntime.runtime(); // let's trigger that lazy jvmci init + } catch (InternalError e) { + System.out.println(GOT_INTERNAL_ERROR); + } + } + + @Override + public void notifyShutdown() { + System.out.println(MESSAGE); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.config --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.config Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +compiler.jvmci.events.JvmciShutdownEventListener diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/JvmciShutdownEventTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8136421 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @library /testlibrary / + * @build compiler.jvmci.common.JVMCIHelpers + * compiler.jvmci.events.JvmciShutdownEventListener + * compiler.jvmci.events.JvmciShutdownEventTest + * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ + * @run main jdk.test.lib.FileInstaller ./JvmciShutdownEventTest.config + * ./META-INF/services/jdk.vm.ci.hotspot.HotSpotVMEventListener + * @run main ClassFileInstaller + * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler + * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory + * compiler.jvmci.events.JvmciShutdownEventListener + * @run driver + * compiler.jvmci.events.JvmciShutdownEventTest + */ + +package compiler.jvmci.events; + +import jdk.test.lib.ExitCode; +import jdk.test.lib.cli.CommandLineOptionTest; + +public class JvmciShutdownEventTest { + private final static String[] MESSAGE = new String[]{ + JvmciShutdownEventListener.MESSAGE + }; + + private final static String[] ERROR_MESSAGE = new String[]{ + JvmciShutdownEventListener.GOT_INTERNAL_ERROR + }; + + public static void main(String args[]) throws Throwable { + boolean addTestVMOptions = true; + CommandLineOptionTest.verifyJVMStartup(MESSAGE, ERROR_MESSAGE, + "Unexpected exit code with +EnableJVMCI", + "Unexpected output with +EnableJVMCI", ExitCode.OK, + addTestVMOptions, "-XX:+UnlockExperimentalVMOptions", + "-XX:+EnableJVMCI", "-Xbootclasspath/a:.", + JvmciShutdownEventListener.class.getName() + ); + + CommandLineOptionTest.verifyJVMStartup(ERROR_MESSAGE, MESSAGE, + "Unexpected exit code with -EnableJVMCI", + "Unexpected output with -EnableJVMCI", ExitCode.OK, + addTestVMOptions, "-XX:+UnlockExperimentalVMOptions", + "-XX:-EnableJVMCI", "-Xbootclasspath/a:.", + JvmciShutdownEventListener.class.getName() + ); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/events/MetaAccessWrapper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/events/MetaAccessWrapper.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.hotspot; + +import jdk.vm.ci.meta.JVMCIMetaAccessContext; +import jdk.vm.ci.meta.ResolvedJavaType; + +/* + * A JVMCIMetaAccessContext wrapper class to mark context + * being provided/returned + */ +public class MetaAccessWrapper implements JVMCIMetaAccessContext { + private static final HotSpotJVMCIMetaAccessContext CONTEXT + = new HotSpotJVMCIMetaAccessContext(); + @Override + public ResolvedJavaType fromClass(Class clazz) { + return CONTEXT.fromClass(clazz); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/NestedBooleanOptionValueTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/NestedBooleanOptionValueTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @run junit jdk.vm.ci.options.test.NestedBooleanOptionValueTest + */ + +package jdk.vm.ci.options.test; + +import static jdk.vm.ci.options.test.NestedBooleanOptionValueTest.Options.*; +import static org.junit.Assert.*; +import jdk.vm.ci.options.*; +import jdk.vm.ci.options.OptionValue.*; + +import org.junit.*; + +public class NestedBooleanOptionValueTest { + + public static class Options { + public static final OptionValue Master0 = new OptionValue<>(true); + public static final OptionValue NestedOption0 = new NestedBooleanOptionValue(Master0, true); + public static final OptionValue Master1 = new OptionValue<>(true); + public static final OptionValue NestedOption1 = new NestedBooleanOptionValue(Master1, true); + public static final OptionValue Master2 = new OptionValue<>(true); + public static final OptionValue NestedOption2 = new NestedBooleanOptionValue(Master2, false); + } + + static final OptionDescriptor master0 = OptionDescriptor.create("Master0", Boolean.class, "", Options.class, "Master0", Master0); + static final OptionDescriptor nestedOption0 = OptionDescriptor.create("NestedOption0", Boolean.class, "", Options.class, "NestedOption0", NestedOption0); + static final OptionDescriptor master1 = OptionDescriptor.create("Master1", Boolean.class, "", Options.class, "Master1", Master1); + static final OptionDescriptor nestedOption1 = OptionDescriptor.create("NestedOption1", Boolean.class, "", Options.class, "NestedOption1", NestedOption1); + static final OptionDescriptor master2 = OptionDescriptor.create("Master2", Boolean.class, "", Options.class, "Master2", Master2); + static final OptionDescriptor nestedOption2 = OptionDescriptor.create("NestedOption2", Boolean.class, "", Options.class, "NestedOption2", NestedOption2); + + @SuppressWarnings("try") + @Test + public void runOverrides() { + assertTrue(Master0.getValue()); + assertTrue(NestedOption0.getValue()); + try (OverrideScope s1 = OptionValue.override(Master0, false)) { + assertFalse(Master0.getValue()); + assertFalse(NestedOption0.getValue()); + try (OverrideScope s2 = OptionValue.override(NestedOption0, false)) { + assertFalse(NestedOption0.getValue()); + } + try (OverrideScope s2 = OptionValue.override(NestedOption0, true)) { + assertTrue(NestedOption0.getValue()); + } + } + assertTrue(Master0.getValue()); + try (OverrideScope s1 = OptionValue.override(NestedOption0, false)) { + assertFalse(NestedOption0.getValue()); + } + try (OverrideScope s1 = OptionValue.override(NestedOption0, true)) { + assertTrue(NestedOption0.getValue()); + } + } + + @Test + public void runDefaultTrue() { + Master1.setValue(true); + assertTrue(Master1.getValue()); + assertTrue(NestedOption1.getValue()); + // nested value unset + Master1.setValue(false); + assertFalse(Master1.getValue()); + assertFalse(NestedOption1.getValue()); + // set false + Master1.setValue(false); + NestedOption1.setValue(false); + assertFalse(Master1.getValue()); + assertFalse(NestedOption1.getValue()); + Master1.setValue(true); + assertTrue(Master1.getValue()); + assertFalse(NestedOption1.getValue()); + // set true + Master1.setValue(false); + NestedOption1.setValue(true); + assertFalse(Master1.getValue()); + assertTrue(NestedOption1.getValue()); + Master1.setValue(true); + assertTrue(Master1.getValue()); + assertTrue(NestedOption1.getValue()); + } + + @Test + public void runDefaultFalse() { + Master2.setValue(true); + assertTrue(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + // nested value unset + Master2.setValue(false); + assertFalse(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + // set false + Master2.setValue(false); + NestedOption2.setValue(false); + assertFalse(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + Master2.setValue(true); + assertTrue(Master2.getValue()); + assertFalse(NestedOption2.getValue()); + // set true + Master2.setValue(false); + NestedOption2.setValue(true); + assertFalse(Master2.getValue()); + assertTrue(NestedOption2.getValue()); + Master2.setValue(true); + assertTrue(Master2.getValue()); + assertTrue(NestedOption2.getValue()); + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/TestOptionValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.options.test/src/jdk/vm/ci/options/test/TestOptionValue.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @run junit jdk.vm.ci.options.test.TestOptionValue + */ + +package jdk.vm.ci.options.test; + +import static jdk.vm.ci.options.test.TestOptionValue.Options.*; +import static org.junit.Assert.*; + +import java.util.*; + +import jdk.vm.ci.options.*; +import jdk.vm.ci.options.OptionValue.*; + +import org.junit.*; + +@SuppressWarnings("try") +public class TestOptionValue { + + public static class Options { + public static final OptionValue Stable = new StableOptionValue<>(true); + public static final OptionValue Mutable = new OptionValue<>("original"); + public static final OptionValue SecondMutable = new OptionValue<>("second"); + } + + static final OptionDescriptor stable = OptionDescriptor.create("Stable", Boolean.class, "", Options.class, "Stable", Stable); + static final OptionDescriptor mutable = OptionDescriptor.create("Mutable", String.class, "", Options.class, "Mutable", Mutable); + static final OptionDescriptor secondMutable = OptionDescriptor.create("SecondMutable", String.class, "", Options.class, "SecondMutable", SecondMutable); + + @Test + public void testMutable() { + assertEquals("original", Mutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals("override1", Mutable.getValue()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals("override2", Mutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + try (OverrideScope s3 = OptionValue.override(Mutable, "override3")) { + assertEquals("override3", Mutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + } + assertEquals("original", Mutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "original")) { + assertEquals("original", Mutable.getValue()); + } + } + + @Test + public void testMultiple() { + assertEquals("original", Mutable.getValue()); + assertEquals("second", SecondMutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1", SecondMutable, "secondOverride1")) { + assertEquals("override1", Mutable.getValue()); + assertEquals("secondOverride1", SecondMutable.getValue()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2", SecondMutable, "secondOverride2")) { + assertEquals("override2", Mutable.getValue()); + assertEquals("secondOverride2", SecondMutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + assertEquals("secondOverride1", SecondMutable.getValue()); + try (OverrideScope s3 = OptionValue.override(Mutable, "override3", SecondMutable, "secondOverride3")) { + assertEquals("override3", Mutable.getValue()); + assertEquals("secondOverride3", SecondMutable.getValue()); + } + assertEquals("override1", Mutable.getValue()); + assertEquals("secondOverride1", SecondMutable.getValue()); + } + assertEquals("original", Mutable.getValue()); + assertEquals("second", SecondMutable.getValue()); + try (OverrideScope s1 = OptionValue.override(Mutable, "original", SecondMutable, "second")) { + assertEquals("original", Mutable.getValue()); + assertEquals("second", SecondMutable.getValue()); + } + } + + @Test + public void testStable() { + assertTrue(Stable.getValue()); + try (OverrideScope s = OptionValue.override(Stable, false)) { + fail("cannot override stable option"); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void toStringTest() { + assertEquals("jdk.vm.ci.options.test.TestOptionValue$Options.Mutable=original", Mutable.toString()); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals("jdk.vm.ci.options.test.TestOptionValue$Options.Mutable=override1", Mutable.toString()); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals("jdk.vm.ci.options.test.TestOptionValue$Options.Mutable=override2", Mutable.toString()); + } + } + } + + @Test + public void getValuesTest() { + assertEquals(Arrays.asList("original"), Mutable.getValues(null)); + assertEquals(Arrays.asList(true), Stable.getValues(null)); + try (OverrideScope s1 = OptionValue.override(Mutable, "override1")) { + assertEquals(Arrays.asList("override1", "original"), Mutable.getValues(null)); + try (OverrideScope s2 = OptionValue.override(Mutable, "override2")) { + assertEquals(Arrays.asList("override2", "override1", "original"), Mutable.getValues(null)); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile ConstantTest.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ConstantTest + */ + +package jdk.vm.ci.runtime.test; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +public class ConstantTest extends FieldUniverse { + + @Test + public void testNegativeZero() { + Assert.assertTrue("Constant for 0.0f must be different from -0.0f", JavaConstant.FLOAT_0 != JavaConstant.forFloat(-0.0F)); + Assert.assertTrue("Constant for 0.0d must be different from -0.0d", JavaConstant.DOUBLE_0 != JavaConstant.forDouble(-0.0d)); + } + + @Test + public void testNullIsNull() { + Assert.assertTrue(JavaConstant.NULL_POINTER.isNull()); + } + + @Test + public void testOne() { + for (JavaKind kind : JavaKind.values()) { + if (kind.isNumericInteger() || kind.isNumericFloat()) { + Assert.assertTrue(JavaConstant.one(kind).getJavaKind() == kind); + } + } + Assert.assertEquals(1, JavaConstant.one(JavaKind.Int).asInt()); + Assert.assertEquals(1L, JavaConstant.one(JavaKind.Long).asLong()); + Assert.assertEquals(1, JavaConstant.one(JavaKind.Byte).asInt()); + Assert.assertEquals(1, JavaConstant.one(JavaKind.Short).asInt()); + Assert.assertEquals(1, JavaConstant.one(JavaKind.Char).asInt()); + Assert.assertTrue(1F == JavaConstant.one(JavaKind.Float).asFloat()); + Assert.assertTrue(1D == JavaConstant.one(JavaKind.Double).asDouble()); + } + + @Test(expected = IllegalArgumentException.class) + public void testIllegalOne() { + JavaConstant.one(JavaKind.Illegal); + } + + @Test(expected = IllegalArgumentException.class) + public void testVoidOne() { + JavaConstant.one(JavaKind.Void); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/FieldUniverse.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime.test; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Context for field related tests. + */ +public class FieldUniverse extends TypeUniverse { + + public static final Map fields = new HashMap<>(); + + { + for (Class c : classes) { + for (Field f : c.getDeclaredFields()) { + ResolvedJavaField field = metaAccess.lookupJavaField(f); + fields.put(f, field); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/MethodUniverse.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime.test; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +/** + * Context for method related tests. + */ +public class MethodUniverse extends TypeUniverse { + + public static final Map methods = new HashMap<>(); + public static final Map, ResolvedJavaMethod> constructors = new HashMap<>(); + + { + for (Class c : classes) { + for (Method m : c.getDeclaredMethods()) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m); + methods.put(m, method); + } + for (Constructor m : c.getDeclaredConstructors()) { + constructors.put(m, metaAccess.lookupJavaMethod(m)); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/NameAndSignature.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/NameAndSignature.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.vm.ci.runtime.test; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; + +class NameAndSignature { + + public static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + + final String name; + final Class returnType; + final Class[] parameterTypes; + + public NameAndSignature(Method m) { + this.name = m.getName(); + this.returnType = m.getReturnType(); + this.parameterTypes = m.getParameterTypes(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NameAndSignature) { + NameAndSignature s = (NameAndSignature) obj; + return s.returnType == returnType && name.equals(s.name) && Arrays.equals(s.parameterTypes, parameterTypes); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(name + "("); + String sep = ""; + for (Class p : parameterTypes) { + sb.append(sep); + sep = ", "; + sb.append(p.getName()); + } + return sb.append(')').append(returnType.getName()).toString(); + } + + public boolean signatureEquals(ResolvedJavaMethod m) { + Signature s = m.getSignature(); + ResolvedJavaType declaringClass = m.getDeclaringClass(); + if (!s.getReturnType(declaringClass).resolve(declaringClass).equals(metaAccess.lookupJavaType(returnType))) { + return false; + } + if (s.getParameterCount(false) != parameterTypes.length) { + return false; + } + for (int i = 0; i < parameterTypes.length; i++) { + if (!s.getParameterType(i, declaringClass).resolve(declaringClass).equals(metaAccess.lookupJavaType(parameterTypes[i]))) { + return false; + } + } + return true; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile RedefineClassTest.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.RedefineClassTest + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assume.*; + +import java.io.*; +import java.lang.instrument.*; +import java.lang.management.*; +import java.lang.reflect.*; +import java.nio.file.*; +import java.security.*; +import java.util.*; +import java.util.jar.*; + +import javax.tools.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests that {@link ResolvedJavaMethod}s are safe in the context of class redefinition being used + * to redefine the method to which they refer. + */ +public class RedefineClassTest extends TypeUniverse { + + static class Foo { + public static Object getName() { + return "foo"; + } + } + + @Test + public void test() throws Throwable { + + Method fooMethod = Foo.class.getDeclaredMethod("getName"); + + ResolvedJavaMethod foo1 = metaAccess.lookupJavaMethod(fooMethod); + ResolvedJavaMethod foo2 = metaAccess.lookupJavaMethod(fooMethod); + + String foo1Code = Arrays.toString(foo1.getCode()); + String foo2Code = Arrays.toString(foo2.getCode()); + + Assert.assertEquals("foo", Foo.getName()); + + redefineFoo(); + System.gc(); + + // Make sure the transformation happened + Assert.assertEquals("bar", Foo.getName()); + + Assert.assertEquals(foo1Code, Arrays.toString(foo1.getCode())); + Assert.assertEquals(foo2Code, Arrays.toString(foo1.getCode())); + } + + /** + * Adds the class file bytes for a given class to a JAR stream. + */ + static void add(JarOutputStream jar, Class c) throws IOException { + String name = c.getName(); + String classAsPath = name.replace('.', '/') + ".class"; + jar.putNextEntry(new JarEntry(classAsPath)); + + InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath); + + int nRead; + byte[] buf = new byte[1024]; + while ((nRead = stream.read(buf, 0, buf.length)) != -1) { + jar.write(buf, 0, nRead); + } + + jar.closeEntry(); + } + + protected void redefineFoo() throws Exception { + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + Attributes mainAttrs = manifest.getMainAttributes(); + mainAttrs.putValue("Agent-Class", FooAgent.class.getName()); + mainAttrs.putValue("Can-Redefine-Classes", "true"); + mainAttrs.putValue("Can-Retransform-Classes", "true"); + + Path jar = Files.createTempFile("myagent", ".jar"); + try { + JarOutputStream jarStream = new JarOutputStream(new FileOutputStream(jar.toFile()), manifest); + add(jarStream, FooAgent.class); + add(jarStream, FooTransformer.class); + jarStream.close(); + + loadAgent(jar); + } finally { + Files.deleteIfExists(jar); + } + } + + public static void loadAgent(Path agent) throws Exception { + String vmName = ManagementFactory.getRuntimeMXBean().getName(); + int p = vmName.indexOf('@'); + assumeTrue(p != -1); + String pid = vmName.substring(0, p); + ClassLoader cl = ToolProvider.getSystemToolClassLoader(); + Class c = Class.forName("com.sun.tools.attach.VirtualMachine", true, cl); + Method attach = c.getDeclaredMethod("attach", String.class); + Method loadAgent = c.getDeclaredMethod("loadAgent", String.class, String.class); + Method detach = c.getDeclaredMethod("detach"); + Object vm = attach.invoke(null, pid); + loadAgent.invoke(vm, agent.toString(), ""); + detach.invoke(vm); + } + + public static class FooAgent { + + public static void agentmain(@SuppressWarnings("unused") String args, Instrumentation inst) throws Exception { + if (inst.isRedefineClassesSupported() && inst.isRetransformClassesSupported()) { + inst.addTransformer(new FooTransformer(), true); + Class[] allClasses = inst.getAllLoadedClasses(); + for (int i = 0; i < allClasses.length; i++) { + Class c = allClasses[i]; + if (c == Foo.class) { + inst.retransformClasses(new Class[]{c}); + } + } + } + } + } + + /** + * This transformer replaces the first instance of the constant "foo" in the class file for + * {@link Foo} with "bar". + */ + static class FooTransformer implements ClassFileTransformer { + + @Override + public byte[] transform(ClassLoader cl, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + if (Foo.class.equals(classBeingRedefined)) { + String cf = new String(classfileBuffer); + int i = cf.indexOf("foo"); + Assert.assertTrue("cannot find \"foo\" constant in " + Foo.class.getSimpleName() + "'s class file", i > 0); + classfileBuffer[i] = 'b'; + classfileBuffer[i + 1] = 'a'; + classfileBuffer[i + 2] = 'r'; + } + return classfileBuffer; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveConcreteMethodTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ResolvedJavaTypeResolveConcreteMethodTest + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; + +import org.junit.*; + +public class ResolvedJavaTypeResolveConcreteMethodTest { + public final MetaAccessProvider metaAccess; + + public ResolvedJavaTypeResolveConcreteMethodTest() { + metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + } + + protected abstract static class A { + @SuppressWarnings("unused") + private void priv() { + } + + public void v1() { + } + + public void v2() { + } + + public abstract void abs(); + } + + protected static class B extends A implements I { + public void i() { + } + + @Override + public void v2() { + } + + @Override + public void abs() { + + } + } + + protected static class C extends B { + public void d() { + } + } + + protected abstract static class D extends A { + + } + + protected static class E extends D { + @Override + public void abs() { + } + } + + protected interface I { + void i(); + + default void d() { + } + } + + @Test + public void testDefaultMethod() { + ResolvedJavaType i = getType(I.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod di = getMethod(i, "d"); + ResolvedJavaMethod dc = getMethod(c, "d"); + + assertEquals(di, i.resolveConcreteMethod(di, c)); + assertEquals(di, b.resolveConcreteMethod(di, c)); + assertEquals(dc, c.resolveConcreteMethod(di, c)); + } + + @Test + public void testPrivateMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod priv = getMethod(a, "priv"); + + assertNull(a.resolveConcreteMethod(priv, c)); + assertNull(b.resolveConcreteMethod(priv, c)); + } + + @Test + public void testAbstractMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaType d = getType(D.class); + ResolvedJavaType e = getType(E.class); + ResolvedJavaMethod absa = getMethod(a, "abs"); + ResolvedJavaMethod absb = getMethod(b, "abs"); + ResolvedJavaMethod abse = getMethod(e, "abs"); + + assertNull(a.resolveConcreteMethod(absa, c)); + assertNull(d.resolveConcreteMethod(absa, c)); + + assertEquals(absb, b.resolveConcreteMethod(absa, c)); + assertEquals(absb, b.resolveConcreteMethod(absb, c)); + assertEquals(absb, c.resolveConcreteMethod(absa, c)); + assertEquals(absb, c.resolveConcreteMethod(absb, c)); + assertEquals(abse, e.resolveConcreteMethod(absa, c)); + assertNull(e.resolveConcreteMethod(absb, c)); + assertEquals(abse, e.resolveConcreteMethod(abse, c)); + } + + @Test + public void testVirtualMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod v1a = getMethod(a, "v1"); + ResolvedJavaMethod v2a = getMethod(a, "v2"); + ResolvedJavaMethod v2b = getMethod(b, "v2"); + + assertEquals(v1a, a.resolveConcreteMethod(v1a, c)); + assertEquals(v1a, b.resolveConcreteMethod(v1a, c)); + assertEquals(v1a, c.resolveConcreteMethod(v1a, c)); + assertEquals(v2a, a.resolveConcreteMethod(v2a, c)); + assertEquals(v2b, b.resolveConcreteMethod(v2a, c)); + assertEquals(v2b, b.resolveConcreteMethod(v2b, c)); + assertEquals(v2b, c.resolveConcreteMethod(v2a, c)); + assertEquals(v2b, c.resolveConcreteMethod(v2b, c)); + + } + + static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) { + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + return method; + } + } + throw new IllegalArgumentException(); + } + + protected ResolvedJavaType getType(Class clazz) { + ResolvedJavaType type = metaAccess.lookupJavaType(clazz); + type.initialize(); + return type; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ResolvedJavaTypeResolveMethodTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ResolvedJavaTypeResolveMethodTest + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; + +import org.junit.*; + +public class ResolvedJavaTypeResolveMethodTest { + public final MetaAccessProvider metaAccess; + + public ResolvedJavaTypeResolveMethodTest() { + metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + } + + protected abstract static class A { + @SuppressWarnings("unused") + private void priv() { + } + + public void v1() { + } + + public void v2() { + } + + public abstract void abs(); + } + + protected static class B extends A implements I { + public void i() { + } + + @Override + public void v2() { + } + + @Override + public void abs() { + + } + } + + protected static class C extends B { + public void d() { + } + } + + protected abstract static class D extends A { + + } + + protected static class E extends D { + @Override + public void abs() { + } + } + + protected interface I { + void i(); + + default void d() { + } + } + + @Test + public void testDefaultMethod() { + ResolvedJavaType i = getType(I.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod di = getMethod(i, "d"); + ResolvedJavaMethod dc = getMethod(c, "d"); + + assertEquals(di, i.resolveMethod(di, c)); + assertEquals(di, b.resolveMethod(di, c)); + assertEquals(dc, c.resolveMethod(di, c)); + } + + @Test + public void testPrivateMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod priv = getMethod(a, "priv"); + + assertNull(a.resolveMethod(priv, c)); + assertNull(b.resolveMethod(priv, c)); + } + + @Test + public void testAbstractMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaType d = getType(D.class); + ResolvedJavaType e = getType(E.class); + ResolvedJavaMethod absa = getMethod(a, "abs"); + ResolvedJavaMethod absb = getMethod(b, "abs"); + ResolvedJavaMethod abse = getMethod(e, "abs"); + + assertEquals(absa, a.resolveMethod(absa, c)); + assertEquals(absa, d.resolveMethod(absa, c)); + + assertEquals(absb, b.resolveMethod(absa, c)); + assertEquals(absb, b.resolveMethod(absb, c)); + assertEquals(absb, c.resolveMethod(absa, c)); + assertEquals(absb, c.resolveMethod(absb, c)); + assertEquals(abse, e.resolveMethod(absa, c)); + assertNull(e.resolveMethod(absb, c)); + assertEquals(abse, e.resolveMethod(abse, c)); + } + + @Test + public void testVirtualMethod() { + ResolvedJavaType a = getType(A.class); + ResolvedJavaType b = getType(B.class); + ResolvedJavaType c = getType(C.class); + ResolvedJavaMethod v1a = getMethod(a, "v1"); + ResolvedJavaMethod v2a = getMethod(a, "v2"); + ResolvedJavaMethod v2b = getMethod(b, "v2"); + + assertEquals(v1a, a.resolveMethod(v1a, c)); + assertEquals(v1a, b.resolveMethod(v1a, c)); + assertEquals(v1a, c.resolveMethod(v1a, c)); + assertEquals(v2a, a.resolveMethod(v2a, c)); + assertEquals(v2b, b.resolveMethod(v2a, c)); + assertEquals(v2b, b.resolveMethod(v2b, c)); + assertEquals(v2b, c.resolveMethod(v2a, c)); + assertEquals(v2b, c.resolveMethod(v2b, c)); + + } + + static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) { + for (ResolvedJavaMethod method : type.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + return method; + } + } + throw new IllegalArgumentException(); + } + + protected ResolvedJavaType getType(Class clazz) { + ResolvedJavaType type = metaAccess.lookupJavaType(clazz); + type.initialize(); + return type; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestConstantReflectionProvider.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestConstantReflectionProvider + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link ConstantReflectionProvider}. It assumes an implementation of the interface that + * actually returns non-null results for access operations that are possible, i.e., the tests will + * fail for an implementation that spuriously returns null (which is allowed by the specification). + */ +public class TestConstantReflectionProvider extends TypeUniverse { + + @Test + public void constantEqualsTest() { + for (ConstantValue c1 : constants()) { + for (ConstantValue c2 : constants()) { + // test symmetry + assertEquals(constantReflection.constantEquals(c1.value, c2.value), constantReflection.constantEquals(c2.value, c1.value)); + if (c1.value.getJavaKind() != JavaKind.Object && c2.value.getJavaKind() != JavaKind.Object) { + assertEquals(c1.value.equals(c2.value), constantReflection.constantEquals(c2.value, c1.value)); + } + } + } + } + + @Test + public void readArrayLengthTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + Integer actual = constantReflection.readArrayLength(c); + if (c.getJavaKind() != JavaKind.Object || c.isNull() || !cv.boxed.getClass().isArray()) { + assertNull(actual); + } else { + assertNotNull(actual); + int actualInt = actual; + assertEquals(Array.getLength(cv.boxed), actualInt); + } + } + } + + static class PrimitiveConstants { + static final long LONG_CONST = 42; + static final int INT_CONST = 66; + static final byte BYTE_CONST = 123; + static final boolean BOOL_CONST = true; + } + + static class BoxedConstants { + static final Long LONG_CONST = 42L; + static final Integer INT_CONST = 66; + static final Byte BYTE_CONST = 123; + static final Boolean BOOL_CONST = true; + } + + @Test + public void boxTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + JavaConstant boxed = constantReflection.boxPrimitive(c); + if (boxed != null && c.getJavaKind().isPrimitive()) { + assertTrue(boxed.getJavaKind().isObject()); + assertFalse(boxed.isNull()); + } + } + + List primitiveConstants = readConstants(PrimitiveConstants.class); + List boxedConstants = readConstants(BoxedConstants.class); + for (int i = 0; i < primitiveConstants.size(); i++) { + ConstantValue prim = primitiveConstants.get(i); + ConstantValue box = boxedConstants.get(i); + assertEquals(box.value, constantReflection.boxPrimitive(prim.value)); + } + + assertNull(constantReflection.boxPrimitive(JavaConstant.NULL_POINTER)); + } + + @Test + public void unboxTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + JavaConstant unboxed = c.isNull() ? null : constantReflection.unboxPrimitive(c); + if (unboxed != null) { + assertFalse(unboxed.getJavaKind().isObject()); + } + } + List primitiveConstants = readConstants(PrimitiveConstants.class); + List boxedConstants = readConstants(BoxedConstants.class); + for (int i = 0; i < primitiveConstants.size(); i++) { + ConstantValue prim = primitiveConstants.get(i); + ConstantValue box = boxedConstants.get(i); + assert prim.getSimpleName().equals(box.getSimpleName()); + assertEquals(prim.value, constantReflection.unboxPrimitive(box.value)); + } + + assertNull(constantReflection.unboxPrimitive(JavaConstant.NULL_POINTER)); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestJavaField.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaField + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link JavaField}. + */ +public class TestJavaField extends FieldUniverse { + + @Test + public void getNameTest() { + for (Map.Entry e : fields.entrySet()) { + String expected = e.getKey().getName(); + String actual = e.getValue().getName(); + assertEquals(expected, actual); + } + } + + @Test + public void getTypeTest() { + for (Map.Entry e : fields.entrySet()) { + // Must resolve types first as a resolved types != unresolved types + ResolvedJavaField rf = e.getValue(); + JavaType expected = metaAccess.lookupJavaType(e.getKey().getType()).resolve(rf.getDeclaringClass()); + JavaType actual = rf.getType().resolve(rf.getDeclaringClass()); + assertEquals(expected, actual); + } + } + + @Test + public void getJavaKindTest() { + for (Map.Entry e : fields.entrySet()) { + JavaKind expected = metaAccess.lookupJavaType(e.getKey().getType()).getJavaKind(); + JavaKind actual = e.getValue().getJavaKind(); + assertEquals(expected, actual); + } + } + + @Test + public void getDeclaringClassTest() { + for (Map.Entry e : fields.entrySet()) { + Class expected = e.getKey().getDeclaringClass(); + ResolvedJavaType actual = e.getValue().getDeclaringClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java NameAndSignature.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaMethod + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link JavaMethod}. + */ +public class TestJavaMethod extends MethodUniverse { + + @Test + public void getNameTest() { + for (Map.Entry e : methods.entrySet()) { + String expected = e.getKey().getName(); + String actual = e.getValue().getName(); + assertEquals(expected, actual); + } + } + + @Test + public void getDeclaringClassTest() { + for (Map.Entry e : methods.entrySet()) { + Class expected = e.getKey().getDeclaringClass(); + ResolvedJavaType actual = e.getValue().getDeclaringClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + + @Test + public void getSignatureTest() { + for (Map.Entry e : methods.entrySet()) { + assertTrue(new NameAndSignature(e.getKey()).signatureEquals(e.getValue())); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestJavaType.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaType + */ + +package jdk.vm.ci.runtime.test; + +import jdk.vm.ci.meta.*; +import static org.junit.Assert.*; + +import org.junit.*; + +/** + * Tests for {@link JavaType}. + */ +public class TestJavaType extends TypeUniverse { + + public TestJavaType() { + } + + @Test + public void getJavaKindTest() { + for (Class c : classes) { + JavaType type = metaAccess.lookupJavaType(c); + JavaKind expected = JavaKind.fromJavaClass(c); + JavaKind actual = type.getJavaKind(); + assertEquals(expected, actual); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestMetaAccessProvider.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestMetaAccessProvider + */ + +package jdk.vm.ci.runtime.test; + +import static jdk.vm.ci.meta.MetaUtil.*; +import static org.junit.Assert.*; + +import java.lang.reflect.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link MetaAccessProvider}. + */ +public class TestMetaAccessProvider extends TypeUniverse { + + @Test + public void lookupJavaTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertNotNull(c.toString(), type); + assertEquals(c.toString(), type.getName(), toInternalName(c.getName())); + assertEquals(c.toString(), type.getName(), toInternalName(type.toJavaName())); + assertEquals(c.toString(), c.getName(), type.toClassName()); + if (!type.isArray()) { + assertEquals(c.toString(), c.getName(), type.toJavaName()); + } + } + } + + @Test + public void lookupJavaMethodTest() { + for (Class c : classes) { + for (Method reflect : c.getDeclaredMethods()) { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(reflect); + assertNotNull(method); + assertTrue(method.getDeclaringClass().equals(metaAccess.lookupJavaType(reflect.getDeclaringClass()))); + } + } + } + + @Test + public void lookupJavaFieldTest() { + for (Class c : classes) { + for (Field reflect : c.getDeclaredFields()) { + ResolvedJavaField field = metaAccess.lookupJavaField(reflect); + assertNotNull(field); + assertTrue(field.getDeclaringClass().equals(metaAccess.lookupJavaType(reflect.getDeclaringClass()))); + } + } + } + + @Test + public void lookupJavaTypeConstantTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + if (c.getJavaKind() == JavaKind.Object && !c.isNull()) { + Object o = cv.boxed; + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertNotNull(type); + assertTrue(type.equals(metaAccess.lookupJavaType(o.getClass()))); + } else { + assertEquals(metaAccess.lookupJavaType(c), null); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestResolvedJavaField.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaField + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link ResolvedJavaField}. + */ +public class TestResolvedJavaField extends FieldUniverse { + + public TestResolvedJavaField() { + } + + @Test + public void getModifiersTest() { + for (Map.Entry e : fields.entrySet()) { + int expected = e.getKey().getModifiers(); + int actual = e.getValue().getModifiers(); + assertEquals(expected, actual); + } + } + + @Test + public void isSyntheticTest() { + for (Map.Entry e : fields.entrySet()) { + boolean expected = e.getKey().isSynthetic(); + boolean actual = e.getValue().isSynthetic(); + assertEquals(expected, actual); + } + } + + @Test + public void getAnnotationsTest() { + for (Map.Entry e : fields.entrySet()) { + Annotation[] expected = e.getKey().getAnnotations(); + Annotation[] actual = e.getValue().getAnnotations(); + assertArrayEquals(expected, actual); + } + } + + @Test + public void getAnnotationTest() { + for (Map.Entry e : fields.entrySet()) { + for (Annotation expected : e.getKey().getAnnotations()) { + if (expected != null) { + Annotation actual = e.getValue().getAnnotation(expected.annotationType()); + assertEquals(expected, actual); + } + } + } + } + + @Test + public void getLocationIdentityTest() { + for (Map.Entry e : fields.entrySet()) { + LocationIdentity identity = e.getValue().getLocationIdentity(); + assertTrue(identity != null); + } + } + + static class ReadConstantValueTestConstants { + String stringField = "field"; + final String constantStringField = "constantField"; + + static final Object CONST1 = new ReadConstantValueTestConstants(); + static final Object CONST2 = null; + static final Object CONST3 = new String(); + } + + @Test + public void readConstantValueTest() throws NoSuchFieldException { + ResolvedJavaField field = metaAccess.lookupJavaField(ReadConstantValueTestConstants.class.getDeclaredField("stringField")); + List receiverConstants = readConstants(ReadConstantValueTestConstants.class); + for (ConstantValue receiver : receiverConstants) { + JavaConstant value = constantReflection.readConstantFieldValue(field, receiver.value); + assertNull(value); + } + + ResolvedJavaField constField = metaAccess.lookupJavaField(ReadConstantValueTestConstants.class.getDeclaredField("constantStringField")); + for (ConstantValue receiver : receiverConstants) { + JavaConstant value = constantReflection.readConstantFieldValue(constField, receiver.value); + if (value != null) { + Object expected = "constantField"; + String actual = ((ReadConstantValueTestConstants) receiver.boxed).constantStringField; + assertTrue(actual + " != " + expected, actual == expected); + } + } + } + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "getDeclaringClass", + "isInternal", + "isFinal" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaField.class.getDeclaredMethods()) { + if (m.isSynthetic()) { + continue; + } + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestResolvedJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaMethod + */ + +package jdk.vm.ci.runtime.test; + +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.invoke.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.vm.ci.meta.*; + +import org.junit.*; + +/** + * Tests for {@link ResolvedJavaMethod}. + */ +public class TestResolvedJavaMethod extends MethodUniverse { + + public TestResolvedJavaMethod() { + } + + /** + * @see ResolvedJavaMethod#getCode() + */ + @Test + public void getCodeTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + byte[] code = m.getCode(); + if (code == null) { + assertTrue(m.getCodeSize() == 0); + } else { + if (m.isAbstract()) { + assertTrue(code.length == 0); + } else if (!m.isNative()) { + assertTrue(code.length > 0); + } + } + } + } + + /** + * @see ResolvedJavaMethod#getCodeSize() + */ + @Test + public void getCodeSizeTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + int codeSize = m.getCodeSize(); + if (m.isAbstract()) { + assertTrue(codeSize == 0); + } else if (!m.isNative()) { + assertTrue(codeSize > 0); + } + } + } + + @Test + public void getModifiersTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + int expected = e.getKey().getModifiers(); + int actual = m.getModifiers(); + assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + int expected = e.getKey().getModifiers(); + int actual = m.getModifiers(); + assertEquals(String.format("%s: 0x%x != 0x%x", m, expected, actual), expected, actual); + } + } + + /** + * @see ResolvedJavaMethod#isClassInitializer() + */ + @Test + public void isClassInitializerTest() { + for (Map.Entry e : methods.entrySet()) { + // Class initializers are hidden from reflection + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isClassInitializer()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isClassInitializer()); + } + } + + @Test + public void isConstructorTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isConstructor()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.isConstructor()); + } + } + + @Test + public void isSyntheticTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isSynthetic(), m.isSynthetic()); + } + } + + @Test + public void isBridgeTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isBridge(), m.isBridge()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(false, m.isBridge()); + } + } + + @Test + public void isVarArgsTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isVarArgs(), m.isVarArgs()); + } + } + + @Test + public void isSynchronizedTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(Modifier.isSynchronized(e.getKey().getModifiers()), m.isSynchronized()); + } + } + + @Test + public void canBeStaticallyBoundTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(m.canBeStaticallyBound(), canBeStaticallyBound(e.getKey())); + } + } + + private static boolean canBeStaticallyBound(Member method) { + int modifiers = method.getModifiers(); + return (Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers) || Modifier.isFinal(method.getDeclaringClass().getModifiers())) && + !Modifier.isAbstract(modifiers); + } + + private static String methodWithExceptionHandlers(String p1, Object o2) { + try { + return p1.substring(100) + o2.toString(); + } catch (IndexOutOfBoundsException e) { + e.printStackTrace(); + } catch (NullPointerException e) { + e.printStackTrace(); + } catch (RuntimeException e) { + e.printStackTrace(); + } + return null; + } + + @Test + public void getExceptionHandlersTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithExceptionHandlers", String.class, Object.class)); + ExceptionHandler[] handlers = method.getExceptionHandlers(); + assertNotNull(handlers); + assertEquals(handlers.length, 3); + handlers[0].getCatchType().equals(metaAccess.lookupJavaType(IndexOutOfBoundsException.class)); + handlers[1].getCatchType().equals(metaAccess.lookupJavaType(NullPointerException.class)); + handlers[2].getCatchType().equals(metaAccess.lookupJavaType(RuntimeException.class)); + } + + private static String nullPointerExceptionOnFirstLine(Object o, String ignored) { + return o.toString() + ignored; + } + + @Test + public void asStackTraceElementTest() throws NoSuchMethodException { + try { + nullPointerExceptionOnFirstLine(null, "ignored"); + Assert.fail("should not reach here"); + } catch (NullPointerException e) { + StackTraceElement expected = e.getStackTrace()[0]; + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); + StackTraceElement actual = method.asStackTraceElement(0); + assertEquals(expected, actual); + } + } + + @Test + public void getConstantPoolTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + ConstantPool cp = m.getConstantPool(); + assertTrue(cp.length() > 0); + } + } + + @Test(timeout = 1000L) + public void getAnnotationTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationTest")); + Test annotation = method.getAnnotation(Test.class); + assertNotNull(annotation); + assertEquals(1000L, annotation.timeout()); + } + + @Test(timeout = 1000L) + public void getAnnotationsTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("getAnnotationsTest")); + Annotation[] annotations = method.getAnnotations(); + assertNotNull(annotations); + assertEquals(1, annotations.length); + assertEquals(1000L, ((Test) annotations[0]).timeout()); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + @interface NonNull { + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + @interface Special { + } + + private static native void methodWithAnnotatedParameters(@NonNull HashMap p1, @Special @NonNull Class p2); + + @Test + public void getParameterAnnotationsTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + Annotation[][] annotations = method.getParameterAnnotations(); + assertEquals(2, annotations.length); + assertEquals(1, annotations[0].length); + assertEquals(NonNull.class, annotations[0][0].annotationType()); + assertEquals(2, annotations[1].length); + assertEquals(Special.class, annotations[1][0].annotationType()); + assertEquals(NonNull.class, annotations[1][1].annotationType()); + } + + @Test + public void getGenericParameterTypesTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + Type[] genericParameterTypes = method.getGenericParameterTypes(); + assertEquals(2, genericParameterTypes.length); + assertEquals("java.util.HashMap", genericParameterTypes[0].toString()); + assertEquals("java.lang.Class", genericParameterTypes[1].toString()); + } + + @Test + public void getMaxLocalsTest() throws NoSuchMethodException { + ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); + assertEquals(0, method1.getMaxLocals()); + assertEquals(2, method2.getMaxLocals()); + + } + + @Test + public void getMaxStackSizeTest() throws NoSuchMethodException { + ResolvedJavaMethod method1 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("methodWithAnnotatedParameters", HashMap.class, Class.class)); + ResolvedJavaMethod method2 = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("nullPointerExceptionOnFirstLine", Object.class, String.class)); + assertEquals(0, method1.getMaxStackSize()); + // some versions of javac produce bytecode with a stacksize of 2 for this method + // JSR 292 also sometimes need one more stack slot + int method2StackSize = method2.getMaxStackSize(); + assertTrue(2 <= method2StackSize && method2StackSize <= 4); + } + + @Test + public void isDefaultTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertEquals(e.getKey().isDefault(), m.isDefault()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isDefault()); + } + } + + @Test + public void hasReceiverTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasReceiver() != Modifier.isStatic(e.getKey().getModifiers())); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasReceiver()); + } + } + + @Test + public void hasBytecodesTest() { + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasBytecodes() == (m.isConcrete() && !m.isNative())); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertTrue(m.hasBytecodes()); + } + } + + @Test + public void isJavaLangObjectInitTest() throws NoSuchMethodException { + ResolvedJavaMethod method = metaAccess.lookupJavaMethod(Object.class.getConstructor()); + assertTrue(method.isJavaLangObjectInit()); + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + assertFalse(m.isJavaLangObjectInit()); + } + for (Map.Entry, ResolvedJavaMethod> e : constructors.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + Constructor key = e.getKey(); + if (key.getDeclaringClass() == Object.class && key.getParameters().length == 0) { + assertTrue(m.isJavaLangObjectInit()); + } else { + assertFalse(m.isJavaLangObjectInit()); + } + } + } + + @Test + public void isSignaturePolymorphicTest() { + ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeExact", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invoke", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeBasic", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToVirtual", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToStatic", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToSpecial", metaAccess)); + assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToInterface", metaAccess)); + assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "type", metaAccess)); + assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(metaAccess.lookupJavaType(Object.class), "toString", metaAccess)); + } + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "invoke", + "newInstance", + "getDeclaringClass", + "getEncoding", + "getProfilingInfo", + "reprofile", + "getCompilerStorage", + "canBeInlined", + "shouldBeInlined", + "getLineNumberTable", + "getLocalVariableTable", + "isInVirtualMethodTable", + "toParameterTypes", + "getParameterAnnotation", + "getSpeculationLog", + "isFinal", + "$jacocoInit" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaMethod.class.getDeclaredMethods()) { + if (Modifier.isStatic(m.getModifiers())) { + continue; + } + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,947 @@ +/* + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" + * @compile TestResolvedJavaType.java TypeUniverse.java TestMetaAccessProvider.java NameAndSignature.java + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaType + */ + +package jdk.vm.ci.runtime.test; + +import static java.lang.reflect.Modifier.*; +import static org.junit.Assert.*; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; +import java.util.*; + +import jdk.vm.ci.common.*; +import jdk.vm.ci.meta.*; +import jdk.vm.ci.meta.Assumptions.*; + +import org.junit.*; + +import sun.reflect.ConstantPool; + +/** + * Tests for {@link ResolvedJavaType}. + */ +public class TestResolvedJavaType extends TypeUniverse { + + public TestResolvedJavaType() { + } + + @Test + public void findInstanceFieldWithOffsetTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Set reflectionFields = getInstanceFields(c, true); + for (Field f : reflectionFields) { + ResolvedJavaField rf = lookupField(type.getInstanceFields(true), f); + assertNotNull(rf); + long offset = isStatic(f.getModifiers()) ? unsafe.staticFieldOffset(f) : unsafe.objectFieldOffset(f); + ResolvedJavaField result = type.findInstanceFieldWithOffset(offset, rf.getJavaKind()); + assertNotNull(result); + assertTrue(fieldsEqual(f, result)); + } + } + } + + @Test + public void isInterfaceTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = c.isInterface(); + boolean actual = type.isInterface(); + assertEquals(expected, actual); + } + } + + @Test + public void isInstanceClassTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = !c.isArray() && !c.isPrimitive() && !c.isInterface(); + boolean actual = type.isInstanceClass(); + assertEquals(expected, actual); + } + } + + @Test + public void isArrayTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + boolean expected = c.isArray(); + boolean actual = type.isArray(); + assertEquals(expected, actual); + } + } + + @Test + public void getModifiersTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + int expected = c.getModifiers() & ModifiersProvider.jvmClassModifiers(); + int actual = type.getModifiers() & ModifiersProvider.jvmClassModifiers(); + Class elementalType = c; + while (elementalType.isArray()) { + elementalType = elementalType.getComponentType(); + } + if (elementalType.isMemberClass()) { + // member class get their modifiers from the inner-class attribute in the JVM and + // from the classfile header in jvmci + expected &= ~(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED); + actual &= ~(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED); + } + assertEquals(String.format("%s: 0x%x != 0x%x", type, expected, actual), expected, actual); + } + } + + @Test + public void isAssignableFromTest() { + Class[] all = classes.toArray(new Class[classes.size()]); + for (int i = 0; i < all.length; i++) { + Class c1 = all[i]; + for (int j = i; j < all.length; j++) { + Class c2 = all[j]; + ResolvedJavaType t1 = metaAccess.lookupJavaType(c1); + ResolvedJavaType t2 = metaAccess.lookupJavaType(c2); + boolean expected = c1.isAssignableFrom(c2); + boolean actual = t1.isAssignableFrom(t2); + assertEquals(expected, actual); + if (expected && t1 != t2) { + assertFalse(t2.isAssignableFrom(t1)); + } + } + } + } + + @Test + public void isInstanceTest() { + for (ConstantValue cv : constants()) { + JavaConstant c = cv.value; + if (c.getJavaKind() == JavaKind.Object && !c.isNull()) { + ResolvedJavaType cType = metaAccess.lookupJavaType(c); + for (ResolvedJavaType t : javaTypes) { + if (t.isAssignableFrom(cType)) { + assertTrue(t.isInstance(c)); + } else { + assertFalse(t.isInstance(c)); + } + } + } + } + } + + private static Class asExactClass(Class c) { + if (c.isArray()) { + if (asExactClass(c.getComponentType()) != null) { + return c; + } + } else { + if (c.isPrimitive() || Modifier.isFinal(c.getModifiers())) { + return c; + } + } + return null; + } + + @Test + public void asExactTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + ResolvedJavaType exactType = type.asExactType(); + Class expected = asExactClass(c); + if (expected == null) { + assertTrue("exact(" + c.getName() + ") != null", exactType == null); + } else { + assertNotNull(exactType); + assertTrue(exactType.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + @Test + public void getSuperclassTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class expected = c.getSuperclass(); + ResolvedJavaType actual = type.getSuperclass(); + if (expected == null) { + assertTrue(actual == null); + } else { + assertNotNull(actual); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + @Test + public void getInterfacesTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class[] expected = c.getInterfaces(); + ResolvedJavaType[] actual = type.getInterfaces(); + assertEquals(expected.length, actual.length); + for (int i = 0; i < expected.length; i++) { + assertTrue(actual[i].equals(metaAccess.lookupJavaType(expected[i]))); + } + } + } + + public Class getSupertype(Class c) { + assert !c.isPrimitive(); + if (c.isArray()) { + Class componentType = c.getComponentType(); + if (componentType.isPrimitive() || componentType == Object.class) { + return Object.class; + } + return getArrayClass(getSupertype(componentType)); + } + if (c.isInterface()) { + return Object.class; + } + return c.getSuperclass(); + } + + public Class findLeastCommonAncestor(Class c1Initial, Class c2Initial) { + if (c1Initial.isPrimitive() || c2Initial.isPrimitive()) { + return null; + } else { + Class c1 = c1Initial; + Class c2 = c2Initial; + while (true) { + if (c1.isAssignableFrom(c2)) { + return c1; + } + if (c2.isAssignableFrom(c1)) { + return c2; + } + c1 = getSupertype(c1); + c2 = getSupertype(c2); + } + } + } + + @Test + public void findLeastCommonAncestorTest() { + Class[] all = classes.toArray(new Class[classes.size()]); + for (int i = 0; i < all.length; i++) { + Class c1 = all[i]; + for (int j = i; j < all.length; j++) { + Class c2 = all[j]; + ResolvedJavaType t1 = metaAccess.lookupJavaType(c1); + ResolvedJavaType t2 = metaAccess.lookupJavaType(c2); + Class expected = findLeastCommonAncestor(c1, c2); + ResolvedJavaType actual = t1.findLeastCommonAncestor(t2); + if (expected == null) { + assertTrue(actual == null); + } else { + assertNotNull(actual); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + } + + private static class Base { + } + + abstract static class Abstract1 extends Base { + } + + interface Interface1 { + } + + static class Concrete1 extends Abstract1 { + } + + static class Concrete2 extends Abstract1 implements Interface1 { + } + + static class Concrete3 extends Concrete2 { + } + + static final class Final1 extends Abstract1 { + } + + abstract static class Abstract4 extends Concrete3 { + } + + void checkConcreteSubtype(ResolvedJavaType type, ResolvedJavaType expected) { + AssumptionResult leafConcreteSubtype = type.findLeafConcreteSubtype(); + if (leafConcreteSubtype == null) { + // findLeafConcreteSubtype() is conservative + } else { + if (expected == null) { + assertNull(leafConcreteSubtype); + } else { + assertTrue(leafConcreteSubtype.getResult().equals(expected)); + } + } + + if (!type.isArray()) { + ResolvedJavaType arrayType = type.getArrayClass(); + AssumptionResult arraySubtype = arrayType.findLeafConcreteSubtype(); + if (arraySubtype != null) { + assertEquals(arraySubtype.getResult(), arrayType); + } else { + // findLeafConcreteSubtype() method is conservative + } + } + } + + @Test + public void findLeafConcreteSubtypeTest() { + ResolvedJavaType base = metaAccess.lookupJavaType(Base.class); + checkConcreteSubtype(base, base); + + ResolvedJavaType a1 = metaAccess.lookupJavaType(Abstract1.class); + ResolvedJavaType c1 = metaAccess.lookupJavaType(Concrete1.class); + + checkConcreteSubtype(base, null); + checkConcreteSubtype(a1, c1); + checkConcreteSubtype(c1, c1); + + ResolvedJavaType i1 = metaAccess.lookupJavaType(Interface1.class); + ResolvedJavaType c2 = metaAccess.lookupJavaType(Concrete2.class); + + checkConcreteSubtype(base, null); + checkConcreteSubtype(a1, null); + checkConcreteSubtype(c1, c1); + checkConcreteSubtype(i1, c2); + checkConcreteSubtype(c2, c2); + + ResolvedJavaType c3 = metaAccess.lookupJavaType(Concrete3.class); + checkConcreteSubtype(c2, null); + checkConcreteSubtype(c3, c3); + + ResolvedJavaType a4 = metaAccess.lookupJavaType(Abstract4.class); + checkConcreteSubtype(c3, null); + checkConcreteSubtype(a4, null); + + ResolvedJavaType a1a = metaAccess.lookupJavaType(Abstract1[].class); + checkConcreteSubtype(a1a, null); + ResolvedJavaType c1a = metaAccess.lookupJavaType(Concrete1[].class); + checkConcreteSubtype(c1a, null); + ResolvedJavaType f1a = metaAccess.lookupJavaType(Final1[].class); + checkConcreteSubtype(f1a, f1a); + + ResolvedJavaType obja = metaAccess.lookupJavaType(Object[].class); + checkConcreteSubtype(obja, null); + + ResolvedJavaType inta = metaAccess.lookupJavaType(int[].class); + checkConcreteSubtype(inta, inta); + } + + interface NoImplementor { + } + + interface SingleImplementorInterface { + } + + static class SingleConcreteImplementor implements SingleImplementorInterface { + } + + interface SingleAbstractImplementorInterface { + } + + abstract static class SingleAbstractImplementor implements SingleAbstractImplementorInterface { + } + + interface MultiImplementorInterface { + } + + static class ConcreteImplementor1 implements MultiImplementorInterface { + } + + static class ConcreteImplementor2 implements MultiImplementorInterface { + } + + interface MultipleAbstractImplementorInterface { + } + + abstract static class MultiAbstractImplementor1 implements MultipleAbstractImplementorInterface { + } + + abstract static class MultiAbstractImplementor2 implements MultipleAbstractImplementorInterface { + } + + interface SingleAbstractImplementorInterface2 { + } + + interface ExtendedSingleImplementorInterface { + } + + abstract static class SingleAbstractImplementor2 implements SingleAbstractImplementorInterface2 { + } + + static class ConcreteTransitiveImplementor1 extends SingleAbstractImplementor2 implements ExtendedSingleImplementorInterface { + } + + static class ConcreteTransitiveImplementor2 extends SingleAbstractImplementor2 implements ExtendedSingleImplementorInterface { + } + + @Test + public void getSingleImplementorTest() { + ResolvedJavaType iNi = metaAccess.lookupJavaType(NoImplementor.class); + assertNull(iNi.getSingleImplementor()); + + ResolvedJavaType iSi = metaAccess.lookupJavaType(SingleImplementorInterface.class); + ResolvedJavaType cSi = metaAccess.lookupJavaType(SingleConcreteImplementor.class); + assertEquals(cSi, iSi.getSingleImplementor()); + + ResolvedJavaType iSai = metaAccess.lookupJavaType(SingleAbstractImplementorInterface.class); + ResolvedJavaType aSai = metaAccess.lookupJavaType(SingleAbstractImplementor.class); + assertEquals(aSai, iSai.getSingleImplementor()); + + ResolvedJavaType iMi = metaAccess.lookupJavaType(MultiImplementorInterface.class); + metaAccess.lookupJavaType(ConcreteImplementor1.class); + metaAccess.lookupJavaType(ConcreteImplementor2.class); + assertEquals(iMi, iMi.getSingleImplementor()); + + ResolvedJavaType iMai = metaAccess.lookupJavaType(MultipleAbstractImplementorInterface.class); + metaAccess.lookupJavaType(MultiAbstractImplementor1.class); + metaAccess.lookupJavaType(MultiAbstractImplementor2.class); + assertEquals(iMai, iMai.getSingleImplementor()); + + ResolvedJavaType iSai2 = metaAccess.lookupJavaType(SingleAbstractImplementorInterface2.class); + ResolvedJavaType aSai2 = metaAccess.lookupJavaType(SingleAbstractImplementor2.class); + metaAccess.lookupJavaType(ConcreteTransitiveImplementor1.class); + metaAccess.lookupJavaType(ConcreteTransitiveImplementor2.class); + assertEquals(aSai2, iSai2.getSingleImplementor()); + } + + @Test(expected = JVMCIError.class) + public void getSingleImplementorTestClassReceiver() { + ResolvedJavaType base = metaAccess.lookupJavaType(Base.class); + base.getSingleImplementor(); + } + + @Test(expected = JVMCIError.class) + public void getSingleImplementorTestPrimitiveReceiver() { + ResolvedJavaType primitive = metaAccess.lookupJavaType(int.class); + primitive.getSingleImplementor(); + } + + @Test + public void getComponentTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class expected = c.getComponentType(); + ResolvedJavaType actual = type.getComponentType(); + if (expected == null) { + assertNull(actual); + } else { + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + @Test + public void getArrayClassTest() { + for (Class c : classes) { + if (c != void.class) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Class expected = getArrayClass(c); + ResolvedJavaType actual = type.getArrayClass(); + assertTrue(actual.equals(metaAccess.lookupJavaType(expected))); + } + } + } + + static class Declarations { + + final Method implementation; + final Set declarations; + + public Declarations(Method impl) { + this.implementation = impl; + declarations = new HashSet<>(); + } + } + + /** + * See Method + * overriding. + */ + static boolean isOverriderOf(Method impl, Method m) { + if (!isPrivate(m.getModifiers()) && !isFinal(m.getModifiers())) { + if (m.getName().equals(impl.getName())) { + if (m.getReturnType() == impl.getReturnType()) { + if (Arrays.equals(m.getParameterTypes(), impl.getParameterTypes())) { + if (isPublic(m.getModifiers()) || isProtected(m.getModifiers())) { + // m is public or protected + return isPublic(impl.getModifiers()) || isProtected(impl.getModifiers()); + } else { + // m is package-private + return impl.getDeclaringClass().getPackage() == m.getDeclaringClass().getPackage(); + } + } + } + } + } + return false; + } + + static final Map, VTable> vtables = new HashMap<>(); + + static class VTable { + + final Map methods = new HashMap<>(); + } + + static synchronized VTable getVTable(Class c) { + VTable vtable = vtables.get(c); + if (vtable == null) { + vtable = new VTable(); + if (c != Object.class) { + VTable superVtable = getVTable(c.getSuperclass()); + vtable.methods.putAll(superVtable.methods); + } + for (Method m : c.getDeclaredMethods()) { + if (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers())) { + if (isAbstract(m.getModifiers())) { + // A subclass makes a concrete method in a superclass abstract + vtable.methods.remove(new NameAndSignature(m)); + } else { + vtable.methods.put(new NameAndSignature(m), m); + } + } + } + vtables.put(c, vtable); + } + return vtable; + } + + static Set findDeclarations(Method impl, Class c) { + Set declarations = new HashSet<>(); + NameAndSignature implSig = new NameAndSignature(impl); + if (c != null) { + for (Method m : c.getDeclaredMethods()) { + if (new NameAndSignature(m).equals(implSig)) { + declarations.add(m); + break; + } + } + if (!c.isInterface()) { + declarations.addAll(findDeclarations(impl, c.getSuperclass())); + } + for (Class i : c.getInterfaces()) { + declarations.addAll(findDeclarations(impl, i)); + } + } + return declarations; + } + + private static void checkResolveMethod(ResolvedJavaType type, ResolvedJavaType context, ResolvedJavaMethod decl, ResolvedJavaMethod expected) { + ResolvedJavaMethod impl = type.resolveConcreteMethod(decl, context); + assertEquals(expected, impl); + } + + @Test + public void resolveMethodTest() { + ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class); + for (Class c : classes) { + if (c.isInterface() || c.isPrimitive()) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (Method m : c.getDeclaredMethods()) { + if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) { + ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m); + ResolvedJavaMethod impl = type.resolveMethod(resolved, context); + ResolvedJavaMethod expected = resolved.isDefault() || resolved.isAbstract() ? resolved : null; + assertEquals(m.toString(), expected, impl); + } else { + // As of JDK 8, interfaces can have static and private methods + } + } + } else { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + VTable vtable = getVTable(c); + for (Method impl : vtable.methods.values()) { + Set decls = findDeclarations(impl, c); + for (Method decl : decls) { + ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl); + if (m.isPublic()) { + ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl); + checkResolveMethod(type, context, m, i); + } + } + } + } + } + } + + @Test + public void resolveConcreteMethodTest() { + ResolvedJavaType context = metaAccess.lookupJavaType(TestResolvedJavaType.class); + for (Class c : classes) { + if (c.isInterface() || c.isPrimitive()) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (Method m : c.getDeclaredMethods()) { + if (JAVA_VERSION <= 1.7D || (!isStatic(m.getModifiers()) && !isPrivate(m.getModifiers()))) { + ResolvedJavaMethod resolved = metaAccess.lookupJavaMethod(m); + ResolvedJavaMethod impl = type.resolveConcreteMethod(resolved, context); + ResolvedJavaMethod expected = resolved.isDefault() ? resolved : null; + assertEquals(m.toString(), expected, impl); + } else { + // As of JDK 8, interfaces can have static and private methods + } + } + } else { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + VTable vtable = getVTable(c); + for (Method impl : vtable.methods.values()) { + Set decls = findDeclarations(impl, c); + for (Method decl : decls) { + ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl); + if (m.isPublic()) { + ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl); + checkResolveMethod(type, context, m, i); + } + } + } + for (Method m : c.getDeclaredMethods()) { + ResolvedJavaMethod impl = type.resolveConcreteMethod(metaAccess.lookupJavaMethod(m), context); + ResolvedJavaMethod expected = isAbstract(m.getModifiers()) ? null : impl; + assertEquals(type + " " + m.toString(), expected, impl); + } + } + } + } + + @Test + public void findUniqueConcreteMethodTest() throws NoSuchMethodException { + ResolvedJavaMethod thisMethod = metaAccess.lookupJavaMethod(getClass().getDeclaredMethod("findUniqueConcreteMethodTest")); + ResolvedJavaMethod ucm = metaAccess.lookupJavaType(getClass()).findUniqueConcreteMethod(thisMethod).getResult(); + assertEquals(thisMethod, ucm); + } + + public static Set getInstanceFields(Class c, boolean includeSuperclasses) { + if (c.isArray() || c.isPrimitive() || c.isInterface()) { + return Collections.emptySet(); + } + Set result = new HashSet<>(); + for (Field f : c.getDeclaredFields()) { + if (!Modifier.isStatic(f.getModifiers())) { + result.add(f); + } + } + if (includeSuperclasses && c != Object.class) { + result.addAll(getInstanceFields(c.getSuperclass(), true)); + } + return result; + } + + public static Set getStaticFields(Class c) { + Set result = new HashSet<>(); + for (Field f : c.getDeclaredFields()) { + if (Modifier.isStatic(f.getModifiers())) { + result.add(f); + } + } + return result; + } + + public boolean fieldsEqual(Field f, ResolvedJavaField rjf) { + return rjf.getDeclaringClass().equals(metaAccess.lookupJavaType(f.getDeclaringClass())) && rjf.getName().equals(f.getName()) && + rjf.getType().resolve(rjf.getDeclaringClass()).equals(metaAccess.lookupJavaType(f.getType())); + } + + public ResolvedJavaField lookupField(ResolvedJavaField[] fields, Field key) { + for (ResolvedJavaField rf : fields) { + if (fieldsEqual(key, rf)) { + return rf; + } + } + return null; + } + + public Field lookupField(Set fields, ResolvedJavaField key) { + for (Field f : fields) { + if (fieldsEqual(f, key)) { + return f; + } + } + return null; + } + + private static boolean isHiddenFromReflection(ResolvedJavaField f) { + if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Throwable.class)) && f.getName().equals("backtrace")) { + return true; + } + if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(ConstantPool.class)) && f.getName().equals("constantPoolOop")) { + return true; + } + if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Class.class)) && f.getName().equals("classLoader")) { + return true; + } + return false; + } + + @Test + public void getInstanceFieldsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (boolean includeSuperclasses : new boolean[]{true, false}) { + Set expected = getInstanceFields(c, includeSuperclasses); + ResolvedJavaField[] actual = type.getInstanceFields(includeSuperclasses); + for (Field f : expected) { + assertNotNull(lookupField(actual, f)); + } + for (ResolvedJavaField rf : actual) { + if (!isHiddenFromReflection(rf)) { + assertEquals(rf.toString(), lookupField(expected, rf) != null, !rf.isInternal()); + } + } + + // Test stability of getInstanceFields + ResolvedJavaField[] actual2 = type.getInstanceFields(includeSuperclasses); + assertArrayEquals(actual, actual2); + } + } + } + + @Test + public void getStaticFieldsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Set expected = getStaticFields(c); + ResolvedJavaField[] actual = type.getStaticFields(); + for (Field f : expected) { + assertNotNull(lookupField(actual, f)); + } + for (ResolvedJavaField rf : actual) { + if (!isHiddenFromReflection(rf)) { + assertEquals(lookupField(expected, rf) != null, !rf.isInternal()); + } + } + + // Test stability of getStaticFields + ResolvedJavaField[] actual2 = type.getStaticFields(); + assertArrayEquals(actual, actual2); + } + } + + @Test + public void getDeclaredMethodsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + Method[] raw = c.getDeclaredMethods(); + Set expected = new HashSet<>(); + for (Method m : raw) { + ResolvedJavaMethod resolvedMethod = metaAccess.lookupJavaMethod(m); + assertNotNull(resolvedMethod); + expected.add(resolvedMethod); + } + Set actual = new HashSet<>(Arrays.asList(type.getDeclaredMethods())); + assertEquals(expected, actual); + } + } + + static class A { + static String name = "foo"; + } + + static class B extends A { + } + + static class C { + } + + static class D { + void foo() { + // use of assertions causes the class to have a + assert getClass() != null; + } + } + + static class SubD extends D { + + } + + @Test + public void getClassInitializerTest() { + assertNotNull(metaAccess.lookupJavaType(A.class).getClassInitializer()); + assertNotNull(metaAccess.lookupJavaType(D.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(B.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(C.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(int.class).getClassInitializer()); + assertNull(metaAccess.lookupJavaType(void.class).getClassInitializer()); + } + + @Test + public void getAnnotationsTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertArrayEquals(c.getAnnotations(), type.getAnnotations()); + } + } + + @Test + public void getAnnotationTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + for (Annotation a : c.getAnnotations()) { + assertEquals(a, type.getAnnotation(a.annotationType())); + } + } + } + + @Test + public void memberClassesTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + assertEquals(c.isLocalClass(), type.isLocal()); + assertEquals(c.isMemberClass(), type.isMember()); + Class enclc = c.getEnclosingClass(); + ResolvedJavaType enclt = type.getEnclosingType(); + assertFalse(enclc == null ^ enclt == null); + if (enclc != null) { + assertEquals(enclt, metaAccess.lookupJavaType(enclc)); + } + } + } + + @Test + public void classFilePathTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + URL path = type.getClassFilePath(); + if (type.isPrimitive() || type.isArray()) { + assertEquals(null, path); + } else { + assertNotNull(path); + String pathString = path.getPath(); + if (type.isLocal() || type.isMember()) { + assertTrue(pathString.indexOf('$') > 0); + } + } + } + } + + @Test + public void isTrustedInterfaceTypeTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + if (TrustedInterface.class.isAssignableFrom(c)) { + assertTrue(type.isTrustedInterfaceType()); + } + } + } + + @Test + public void isLeafTest() { + for (Class c : classes) { + ResolvedJavaType type = metaAccess.lookupJavaType(c); + ResolvedJavaType arrayType = c != void.class ? metaAccess.lookupJavaType(getArrayClass(c)) : null; + if (c.isPrimitive()) { + assertTrue(type.isLeaf()); + assertTrue(arrayType == null || arrayType.isLeaf()); + } else { + assertTrue(c.toString(), type.isLeaf() == arrayType.isLeaf()); + if (!c.isArray()) { + assertTrue(c.toString(), type.isLeaf() == Modifier.isFinal(c.getModifiers())); + } + } + } + } + + @Test + public void findMethodTest() { + try { + ResolvedJavaMethod findFoo = metaAccess.lookupJavaType(D.class).findMethod("foo", metaAccess.parseMethodDescriptor("()V")); + ResolvedJavaMethod expectedFoo = metaAccess.lookupJavaMethod(D.class.getDeclaredMethod("foo")); + assertEquals(expectedFoo, findFoo); + + ResolvedJavaMethod wrongReturnTypeFoo = metaAccess.lookupJavaType(D.class).findMethod("foo", metaAccess.parseMethodDescriptor("()I")); + assertNull(wrongReturnTypeFoo); + + ResolvedJavaMethod wrongArgumentsFoo = metaAccess.lookupJavaType(D.class).findMethod("foo", metaAccess.parseMethodDescriptor("(I)V")); + assertNull(wrongArgumentsFoo); + + ResolvedJavaMethod wrongNameFoo = metaAccess.lookupJavaType(D.class).findMethod("bar", metaAccess.parseMethodDescriptor("()V")); + assertNull(wrongNameFoo); + + ResolvedJavaMethod wrongClassFoo = metaAccess.lookupJavaType(SubD.class).findMethod("foo", metaAccess.parseMethodDescriptor("()V")); + assertNull(wrongClassFoo); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException(e); + } + } + + private Method findTestMethod(Method apiMethod) { + String testName = apiMethod.getName() + "Test"; + for (Method m : getClass().getDeclaredMethods()) { + if (m.getName().equals(testName) && m.getAnnotation(Test.class) != null) { + return m; + } + } + return null; + } + + // @formatter:off + private static final String[] untestedApiMethods = { + "initialize", + "isPrimitive", + "newArray", + "getDeclaredConstructors", + "isInitialized", + "isLinked", + "getJavaClass", + "getObjectHub", + "hasFinalizableSubclass", + "hasFinalizer", + "getSourceFileName", + "getClassFilePath", + "isLocal", + "isJavaLangObject", + "isMember", + "getElementalType", + "getEnclosingType", + "$jacocoInit", + "isCpiSet", + "getCorrespondingCpi", + "setCorrespondingCpi" + }; + // @formatter:on + + /** + * Ensures that any new methods added to {@link ResolvedJavaMethod} either have a test written + * for them or are added to {@link #untestedApiMethods}. + */ + @Test + public void testCoverage() { + Set known = new HashSet<>(Arrays.asList(untestedApiMethods)); + for (Method m : ResolvedJavaType.class.getDeclaredMethods()) { + if (findTestMethod(m) == null) { + assertTrue("test missing for " + m, known.contains(m.getName())); + } else { + assertFalse("test should be removed from untestedApiMethods" + m, known.contains(m.getName())); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.vm.ci.runtime.test; + +import static java.lang.reflect.Modifier.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.Queue; +import java.util.stream.*; + +import jdk.vm.ci.meta.*; +import jdk.vm.ci.runtime.*; + +import org.junit.*; + +import sun.misc.*; + +//JaCoCo Exclude + +/** + * Context for type related tests. + */ +public class TypeUniverse { + + public static final Unsafe unsafe; + public static final double JAVA_VERSION = Double.valueOf(System.getProperty("java.specification.version")); + + public static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess(); + public static final ConstantReflectionProvider constantReflection = JVMCI.getRuntime().getHostJVMCIBackend().getConstantReflection(); + public static final Collection> classes = new HashSet<>(); + public static final Set javaTypes; + public static final Map, Class> arrayClasses = new HashMap<>(); + + private static List constants; + + public class InnerClass { + + } + + public static class InnerStaticClass { + + } + + public static final class InnerStaticFinalClass { + + } + + private class PrivateInnerClass { + + } + + protected class ProtectedInnerClass { + + } + + static { + Unsafe theUnsafe = null; + try { + theUnsafe = Unsafe.getUnsafe(); + } catch (Exception e) { + try { + Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeField.setAccessible(true); + theUnsafe = (Unsafe) theUnsafeField.get(null); + } catch (Exception e1) { + throw (InternalError) new InternalError("unable to initialize unsafe").initCause(e1); + } + } + unsafe = theUnsafe; + + Class[] initialClasses = {void.class, boolean.class, byte.class, short.class, char.class, int.class, float.class, long.class, double.class, Object.class, Class.class, boolean[].class, + byte[].class, short[].class, char[].class, int[].class, float[].class, long[].class, double[].class, Object[].class, Class[].class, List[].class, boolean[][].class, + byte[][].class, short[][].class, char[][].class, int[][].class, float[][].class, long[][].class, double[][].class, Object[][].class, Class[][].class, List[][].class, + ClassLoader.class, String.class, Serializable.class, Cloneable.class, Test.class, TestMetaAccessProvider.class, List.class, Collection.class, Map.class, Queue.class, + HashMap.class, LinkedHashMap.class, IdentityHashMap.class, AbstractCollection.class, AbstractList.class, ArrayList.class, TrustedInterface.class, InnerClass.class, + InnerStaticClass.class, InnerStaticFinalClass.class, PrivateInnerClass.class, ProtectedInnerClass.class}; + for (Class c : initialClasses) { + addClass(c); + } + + javaTypes = Collections.unmodifiableSet(classes.stream().map(c -> metaAccess.lookupJavaType(c)).collect(Collectors.toSet())); + } + + static class ConstantsUniverse { + static final Object[] ARRAYS = classes.stream().map(c -> c != void.class && !c.isArray() ? Array.newInstance(c, 42) : null).filter(o -> o != null).collect(Collectors.toList()).toArray(); + static final Object CONST1 = new ArrayList<>(); + static final Object CONST2 = new ArrayList<>(); + static final Object CONST3 = new IdentityHashMap<>(); + static final Object CONST4 = new LinkedHashMap<>(); + static final Object CONST5 = new TreeMap<>(); + static final Object CONST6 = new ArrayDeque<>(); + static final Object CONST7 = new LinkedList<>(); + static final Object CONST8 = "a string"; + static final Object CONST9 = 42; + static final Object CONST10 = String.class; + static final Object CONST11 = String[].class; + } + + public static List constants() { + if (constants == null) { + List res = readConstants(JavaConstant.class); + res.addAll(readConstants(ConstantsUniverse.class)); + constants = res; + } + return constants; + } + + public static class ConstantValue { + public final String name; + public final JavaConstant value; + public final Object boxed; + + public ConstantValue(String name, JavaConstant value, Object boxed) { + this.name = name; + this.value = value; + this.boxed = boxed; + } + + @Override + public String toString() { + return name + "=" + value; + } + + public String getSimpleName() { + return name.substring(name.lastIndexOf('.') + 1); + } + } + + /** + * Reads the value of all {@code static final} fields from a given class into an array of + * {@link ConstantValue}s. + */ + public static List readConstants(Class fromClass) { + try { + List res = new ArrayList<>(); + for (Field field : fromClass.getDeclaredFields()) { + if (isStatic(field.getModifiers()) && isFinal(field.getModifiers())) { + JavaField javaField = metaAccess.lookupJavaField(field); + Object boxed = field.get(null); + if (boxed instanceof JavaConstant) { + res.add(new ConstantValue(javaField.format("%H.%n"), (JavaConstant) boxed, boxed)); + } else { + JavaConstant value = constantReflection.readConstantFieldValue(javaField, null); + if (value != null) { + res.add(new ConstantValue(javaField.format("%H.%n"), value, boxed)); + if (boxed instanceof Object[]) { + Object[] arr = (Object[]) boxed; + for (int i = 0; i < arr.length; i++) { + JavaConstant element = constantReflection.readArrayElement(value, i); + if (element != null) { + res.add(new ConstantValue(javaField.format("%H.%n[" + i + "]"), element, arr[i])); + } + } + } + } + } + } + } + return res; + } catch (Exception e) { + throw new AssertionError(e); + } + } + + public synchronized Class getArrayClass(Class componentType) { + Class arrayClass = arrayClasses.get(componentType); + if (arrayClass == null) { + arrayClass = Array.newInstance(componentType, 0).getClass(); + arrayClasses.put(componentType, arrayClass); + } + return arrayClass; + } + + public static int dimensions(Class c) { + if (c.getComponentType() != null) { + return 1 + dimensions(c.getComponentType()); + } + return 0; + } + + private static void addClass(Class c) { + if (classes.add(c)) { + if (c.getSuperclass() != null) { + addClass(c.getSuperclass()); + } + for (Class sc : c.getInterfaces()) { + addClass(sc); + } + for (Class dc : c.getDeclaredClasses()) { + addClass(dc); + } + for (Method m : c.getDeclaredMethods()) { + addClass(m.getReturnType()); + for (Class p : m.getParameterTypes()) { + addClass(p); + } + } + + if (c != void.class && dimensions(c) < 2) { + Class arrayClass = Array.newInstance(c, 0).getClass(); + arrayClasses.put(c, arrayClass); + addClass(arrayClass); + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java --- a/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoops.java Thu Oct 22 11:13:08 2015 -0700 @@ -25,8 +25,8 @@ /** * @test * @bug 8080289 - * @summary Sink stores out of loops if possible - * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+PrintCompilation -XX:CompileCommand=dontinline,TestMoveStoresOutOfLoops::test* TestMoveStoresOutOfLoops + * @summary Move stores out of loops if possible + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:CompileCommand=dontinline,TestMoveStoresOutOfLoops::test* TestMoveStoresOutOfLoops * */ diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoopsStoreNoCtrl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/TestMoveStoresOutOfLoopsStoreNoCtrl.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8134288 + * @summary Store nodes may not have a control if used to update profiling + * @run main/othervm -XX:-ProfileInterpreter -XX:-TieredCompilation -XX:-BackgroundCompilation TestMoveStoresOutOfLoopsStoreNoCtrl + * + */ + +public class TestMoveStoresOutOfLoopsStoreNoCtrl { + + static void test(boolean flag) { + for (int i = 0; i < 20000; i++) { + if (flag) { + int j = 0; + do { + j++; + } while(j < 10); + } + } + } + + static public void main(String[] args) { + test(false); + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Double.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Double.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8138583 + * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : double abs & neg test + * @requires os.arch=="aarch64" + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Double + */ + +public class SumRedAbsNeg_Double +{ + public static void main(String[] args) throws Exception { + double[] a = new double[256*1024]; + double[] b = new double[256*1024]; + double[] c = new double[256*1024]; + double[] d = new double[256*1024]; + sumReductionInit(a,b,c); + double total = 0; + double valid = 3.6028590866691944E19; + + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + double[] a, + double[] b, + double[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static double sumReductionImplement( + double[] a, + double[] b, + double[] c, + double[] d, + double total) + { + for(int i = 0; i < a.length; i++) + { + d[i] = Math.abs(-a[i] * -b[i]) + Math.abs(-a[i] * -c[i]) + Math.abs(-b[i] * -c[i]); + total += d[i]; + } + return total; + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Float.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/loopopts/superword/SumRedAbsNeg_Float.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8138583 + * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : float abs & neg test + * @requires os.arch=="aarch64" + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=4 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=8 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=16 -XX:CompileThresholdScaling=0.1 SumRedAbsNeg_Float + */ + +public class SumRedAbsNeg_Float +{ + public static void main(String[] args) throws Exception { + float[] a = new float[256*1024]; + float[] b = new float[256*1024]; + float[] c = new float[256*1024]; + float[] d = new float[256*1024]; + sumReductionInit(a,b,c); + float total = 0; + float valid = (float)4.611686E18; + + for(int j = 0; j < 2000; j++) { + total = sumReductionImplement(a,b,c,d,total); + } + + if(total == valid) { + System.out.println("Success"); + } else { + System.out.println("Invalid sum of elements variable in total: " + total); + System.out.println("Expected value = " + valid); + throw new Exception("Failed"); + } + } + + public static void sumReductionInit( + float[] a, + float[] b, + float[] c) + { + for(int j = 0; j < 1; j++) + { + for(int i = 0; i < a.length; i++) + { + a[i] = i * 1 + j; + b[i] = i * 1 - j; + c[i] = i + j; + } + } + } + + public static float sumReductionImplement( + float[] a, + float[] b, + float[] c, + float[] d, + float total) + { + for(int i = 0; i < a.length; i++) + { + d[i] = Math.abs(-a[i] * -b[i]) + Math.abs(-a[i] * -c[i]) + Math.abs(-b[i] * -c[i]); + total += d[i]; + } + return total; + } + +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/loopopts/superword/SumRedSqrt_Double.java --- a/hotspot/test/compiler/loopopts/superword/SumRedSqrt_Double.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/loopopts/superword/SumRedSqrt_Double.java Thu Oct 22 11:13:08 2015 -0700 @@ -24,7 +24,9 @@ /** * @test +* @bug 8135028 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double sqrt test +* @requires os.arch=="x86" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedSqrt_Double * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-SuperWordReductions -XX:LoopUnrollLimit=250 -XX:LoopMaxUnroll=2 -XX:CompileThresholdScaling=0.1 SumRedSqrt_Double diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/oracle/CheckCompileCommandOption.java --- a/hotspot/test/compiler/oracle/CheckCompileCommandOption.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/oracle/CheckCompileCommandOption.java Thu Oct 22 11:13:08 2015 -0700 @@ -66,7 +66,6 @@ "CompileCommand: option com/oracle/Test.test bool MyBoolOption1 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption2 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption3 = true", - "CompileCommand: option com/oracle/Test.test bool MyBoolOption4 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption5 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption6 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption7 = true", @@ -74,7 +73,6 @@ "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption9 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption10 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption11 = true", - "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption12 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption13 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption14 = true", "CompileCommand: option com/oracle/Test.test(I) bool MyBoolOption15 = true", @@ -96,7 +94,6 @@ "-XX:CompileCommand=option,com/oracle/Test.test,MyBoolOption1", "-XX:CompileCommand=option,com/oracle/Test,test,MyBoolOption2", "-XX:CompileCommand=option,com.oracle.Test::test,MyBoolOption3", - "-XX:CompileCommand=option,com/oracle/Test::test,MyBoolOption4", "-XX:CompileCommand=option,com/oracle/Test.test,MyBoolOption5,MyBoolOption6", "-XX:CompileCommand=option,com/oracle/Test,test,MyBoolOption7,MyBoolOption8", "-version" @@ -108,7 +105,6 @@ "CompileCommand: option com/oracle/Test.test bool MyBoolOption1 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption2 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption3 = true", - "CompileCommand: option com/oracle/Test.test bool MyBoolOption4 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption5 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption6 = true", "CompileCommand: option com/oracle/Test.test bool MyBoolOption7 = true", @@ -198,7 +194,7 @@ out.shouldContain(expected_output); } - out.shouldNotContain("CompileCommand: An error occured during parsing"); + out.shouldNotContain("CompileCommand: An error occurred during parsing"); out.shouldHaveExitValue(0); } @@ -209,7 +205,7 @@ pb = ProcessTools.createJavaProcessBuilder(arguments); out = new OutputAnalyzer(pb.start()); - out.shouldContain("CompileCommand: An error occured during parsing"); + out.shouldContain("CompileCommand: An error occurred during parsing"); out.shouldHaveExitValue(0); } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/oracle/MethodMatcherTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/oracle/MethodMatcherTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 MethodMatcherTest + * @library /testlibrary /../../test/lib + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI MethodMatcherTest + * @summary Testing of compiler/MethodMatcher + * @bug 8135068 + */ + +import java.lang.reflect.Method; +import java.util.ArrayList; + +import sun.hotspot.WhiteBox; + +public class MethodMatcherTest { + + /** Instance of WhiteBox */ + protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + Method helper; + Method getDate; + Method inner; + Method toString; + + static final int MATCH = 1; + static final int NO_MATCH = 0; + static final int PARSING_FAILURE = -1; + + public MethodMatcherTest() { + } + + public void test() throws Exception { + // instantiate before calling getMethod on innerHelper + TestCases testCases = new TestCases(); + + helper = getMethod(MethodMatcherTest.class, "helper"); + getDate = getMethod(java.util.Date.class, "getDate"); + inner = getMethod(TestCases.class, "innerHelper"); + toString = getMethod(String.class, "toString"); + + testCases.add(helper, "pool/sub/Klass.method(I[Ljava/lang/String;Ljava/lang/Integer;[B[[D)V", NO_MATCH); + + // These should be improved to parsing failed in the future + testCases.add(helper, "*Klass*,*$method*::", NO_MATCH); + testCases.add(helper, "*Klass *+*", NO_MATCH); + testCases.add(helper, "*Klass*::*method*", NO_MATCH); + + testCases.add(helper, "*,**", PARSING_FAILURE); + testCases.add(helper, "*,*(I[Ljava/lang/String;Lj]ava/lang/Integer;[B[[D)V", PARSING_FAILURE); + testCases.add(helper, "*,*)method*.", PARSING_FAILURE); + testCases.add(helper, "{pool.subpack.Klass}* *", PARSING_FAILURE); + testCases.add(helper, "*Klass met]hod/", PARSING_FAILURE); + testCases.add(helper, "pool::su@%b::Klass* *)method.", PARSING_FAILURE); + testCases.add(helper, "0pool/sub/Klass,*{method}*.(I[Ljava/lang/String;Lj]ava/lang/Integer;[B[[D)V", PARSING_FAILURE); + testCases.add(helper, "*Klass nonexistent::)(I[Ljava/lang/String;Ljava/lang/Integer;[B[[D)V", PARSING_FAILURE); + testCases.add(helper, "pool,su]b,Klass*,*)method*/", PARSING_FAILURE); + testCases.add(helper, "_pool,sub,Klass*,met@%hod,(0)V", PARSING_FAILURE); + + testCases.add(helper, "*.*", MATCH); + testCases.add(helper, "MethodMatcherTest.*", MATCH); + testCases.add(helper, "MethodMatcherTest.helper", MATCH); + testCases.add(helper, "MethodMatcherTest.helper()", MATCH); + testCases.add(helper, "MethodMatcherTest.helper()V", MATCH); + testCases.add(helper, "MethodMatcherTest.helper()V;", NO_MATCH); + testCases.add(helper, "MethodMatcherTest.helper()I", NO_MATCH); + testCases.add(helper, "MethodMatcherTest.helperX", NO_MATCH); + testCases.add(helper, "MethodMatcherTestX.helper;", NO_MATCH); + testCases.add(helper, "abc.*", NO_MATCH); + testCases.add(helper, "*.abc", NO_MATCH); + + testCases.add(getDate, "*.*", MATCH); + testCases.add(getDate, "*.getDate", MATCH); + testCases.add(getDate, "java/util/Date.getDate", MATCH); + testCases.add(getDate, "java/util/Date.*", MATCH); + + testCases.add(inner, "*.*", MATCH); + testCases.add(inner, "MethodMatcherTest$TestCases.innerHelper", MATCH); + testCases.add(inner, "MethodMatcherTest*.innerHelper", MATCH); + testCases.add(inner, "MethodMatcherTest$*.innerHelper", MATCH); + testCases.add(inner, "*$TestCases.innerHelper", MATCH); + testCases.add(inner, "*TestCases.innerHelper", MATCH); + testCases.add(inner, "TestCases.innerHelper", NO_MATCH); + testCases.add(inner, "MethodMatcherTest.innerHelper", NO_MATCH); + + testCases.add(toString, "*.*", MATCH); + testCases.add(toString, "java/lang/String.toString", MATCH); + testCases.add(toString, "java.lang.String::toString", MATCH); + + testCases.add(toString, "java/lang/String::toString", PARSING_FAILURE); + testCases.add(toString, "java.lang/String::toString", PARSING_FAILURE); + testCases.add(toString, "java.lang/String.toString", PARSING_FAILURE); + testCases.add(toString, "java::lang::String::toString", PARSING_FAILURE); + + testCases.add(toString, "java/lang/String.toString(*)", PARSING_FAILURE); + testCases.add(toString, "java/lang/String.toString(L*", PARSING_FAILURE); + testCases.add(toString, "java/lang/String.toString*(lsd)l", NO_MATCH); + testCases.add(toString, "java/lang/String.toString(lsd)l", NO_MATCH); + testCases.add(toString, "java/lang/String.toString (", MATCH); + testCases.add(toString, "java/lang/String.toString ()", MATCH); + testCases.add(toString, "java/lang/String.toString ()L", MATCH); + testCases.add(toString, "java/lang/String.toString ()Lj", MATCH); + testCases.add(toString, "java/lang/String.toString ()Ls", NO_MATCH); + testCases.add(toString, "java/lang/String.toString*(", MATCH); + testCases.add(toString, "java/lang/String.toString* (", MATCH); + testCases.add(toString, "java/lang/String.toString*(;", NO_MATCH); + testCases.add(toString, "java/lang/String.toString*();sf", NO_MATCH); + testCases.add(toString, "java/lang/String.toString*()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString ()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString ()Ljava/lang/String", MATCH); + testCases.add(toString, "java/lang/String.toString ()L", MATCH); + testCases.add(toString, "java/lang/String.toString ()I;", NO_MATCH); + + testCases.add(toString, "*Internal.*", NO_MATCH); + testCases.add(toString, "*Internal.**", PARSING_FAILURE); + testCases.add(toString, "*Internal.***", PARSING_FAILURE); + testCases.add(toString, "*Internal.*a**", PARSING_FAILURE); + testCases.add(toString, "*Internal.**a*", PARSING_FAILURE); + + testCases.add(toString, "java.lang.String::(Ljava/lang/String;)V", NO_MATCH); + testCases.add(toString, "java.lang.String::(Ljava/lang/String;)V", NO_MATCH); + testCases.add(toString, "java.lang.String::(Ljava/lang/String;)V", PARSING_FAILURE); + + testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", MATCH); + testCases.add(toString, "java/lang/String.toString()Ljava/lang/String;", PARSING_FAILURE); + testCases.add(toString, "java/lang/.toString()Ljava/lang/String;", PARSING_FAILURE); + testCases.add(toString, "java/lang/.toString()Ljava/lang/String;", PARSING_FAILURE); + + int failures = 0; + for (TestCase t : testCases) { + System.out.println("Test case: " + t.pattern); + if (!t.test()) { + failures++; + System.out.println(" * FAILED"); + } + } + if (failures != 0) { + throw new Exception("There where " + failures + " failures in this test"); + } + } + + public static void main(String... args) throws Exception { + MethodMatcherTest test = new MethodMatcherTest(); + test.test(); + } + + public void helper() { + + } + + private static Method getMethod(Class klass, String name, Class... parameterTypes) { + try { + return klass.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("exception on getting method Helper." + name, e); + } + } + + class TestCase { + String pattern; + Method testTarget; + int expectedResult; + + public TestCase(Method testTarget, String pattern, int expectedResult) { + this.testTarget = testTarget; + this.pattern = pattern; + this.expectedResult = expectedResult; + } + + public String resultAsStr(int errorCode) { + switch (errorCode) { + case PARSING_FAILURE: + return "Parsing failed"; + case NO_MATCH: + return "No match"; + case MATCH: + return "Match"; + default: + return "Unknown error"; + } + } + + boolean test() { + int result = WHITE_BOX.matchesMethod(testTarget, pattern); + if (result != expectedResult) { + System.out + .println("FAIL Wrong result, Got: " + resultAsStr(result) + "\n TestCase: " + this.toString()); + return false; + } + return true; + } + + @Override + public String toString() { + return "Method: '" + testTarget.toString() + "' Pattern: '" + pattern + "' Expected: " + + resultAsStr(expectedResult); + } + + public void innerHelper() { + } + } + + class TestCases extends ArrayList { + private static final long serialVersionUID = 1L; + + public boolean add(Method testTarget, String pattern, int expectedResult) { + return super.add(new TestCase(testTarget, pattern, expectedResult)); + } + + public void innerHelper() { + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/oracle/TestCompileCommand.java --- a/hotspot/test/compiler/oracle/TestCompileCommand.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/oracle/TestCompileCommand.java Thu Oct 22 11:13:08 2015 -0700 @@ -40,7 +40,7 @@ private static final String[][] ARGUMENTS = { { - "-XX:CompileCommand=print,*01234567890123456789012345678901234567890123456789,*0123456789012345678901234567890123456789", + "-XX:CompileCommand=print,*01234567890123456789012345678901234567890123456789.*0123456789012345678901234567890123456789", "-version" } }; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/oracle/command1.txt --- a/hotspot/test/compiler/oracle/command1.txt Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/oracle/command1.txt Thu Oct 22 11:13:08 2015 -0700 @@ -1,12 +1,10 @@ option,com/oracle/Test.test,MyBoolOption1 option,com/oracle/Test,test,MyBoolOption2 option,com.oracle.Test::test,MyBoolOption3 -option,com/oracle/Test::test,MyBoolOption4 option,com/oracle/Test.test,MyBoolOption5,MyBoolOption6 option,com/oracle/Test,test,MyBoolOption7,MyBoolOption8 option,com/oracle/Test.test(I),MyBoolOption9 option,com/oracle/Test,test,(I),MyBoolOption10 option,com.oracle.Test::test(I),MyBoolOption11 -option,com/oracle/Test::test(I),MyBoolOption12 option,com/oracle/Test.test(I),MyBoolOption13,MyBoolOption14 option,com/oracle/Test,test(I),MyBoolOption15,MyBoolOption16 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/startup/SmallCodeCacheStartup.java --- a/hotspot/test/compiler/startup/SmallCodeCacheStartup.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/startup/SmallCodeCacheStartup.java Thu Oct 22 11:13:08 2015 -0700 @@ -23,6 +23,7 @@ /* * @test + * @ignore 8134286 * @bug 8023014 * @summary Test ensures that there is no crash if there is not enough ReservedCodeCacheSize * to initialize all compiler threads. The option -Xcomp gives the VM more time to diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/compiler/testlibrary/CompilerUtils.java --- a/hotspot/test/compiler/testlibrary/CompilerUtils.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/compiler/testlibrary/CompilerUtils.java Thu Oct 22 11:13:08 2015 -0700 @@ -21,6 +21,8 @@ * questions. */ +package compiler.testlibrary; + import jdk.test.lib.Asserts; import jdk.test.lib.Platform; import java.util.stream.IntStream; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/gc/arguments/TestG1ConcMarkStepDurationMillis.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/arguments/TestG1ConcMarkStepDurationMillis.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,110 @@ +/* +* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 only, as +* published by the Free Software Foundation. +* +* This code is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* version 2 for more details (a copy is included in the LICENSE file that +* accompanied this code). +* +* You should have received a copy of the GNU General Public License version +* 2 along with this work; if not, write to the Free Software Foundation, +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Please 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 TestG1ConcMarkStepDurationMillis + * @key gc + * @requires vm.gc=="null" | vm.gc=="G1" + * @summary Tests argument processing for double type flag, G1ConcMarkStepDurationMillis + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + */ + +import jdk.test.lib.*; +import java.util.*; +import java.util.regex.*; + +public class TestG1ConcMarkStepDurationMillis { + + static final int PASS = 0; + static final int FAIL_IMPROPER_VALUE = 1; + static final int FAIL_OUT_RANGE = 2; + + static final String DOUBLE_1 = "1.0"; + static final String DOUBLE_MAX = "1.79e+308"; + + static final String DOUBLE_NEG_EXP = "1.0e-30"; + static final String NEG_DOUBLE_1 = "-1.0"; + + static final String DOUBLE_INF = "1.79e+309"; + static final String NEG_DOUBLE_INF = "-1.79e+309"; + static final String DOUBLE_NAN = "abe+309"; + static final String WRONG_DOUBLE_1 = "1.79e+308e"; + static final String WRONG_DOUBLE_2 = "1.79ee+308"; + + public static void main(String args[]) throws Exception { + // Pass cases + runG1ConcMarkStepDurationMillisTest(DOUBLE_1, PASS); + runG1ConcMarkStepDurationMillisTest(DOUBLE_MAX, PASS); + + // Fail cases: out of range + runG1ConcMarkStepDurationMillisTest(DOUBLE_NEG_EXP, FAIL_OUT_RANGE); + runG1ConcMarkStepDurationMillisTest(NEG_DOUBLE_1, FAIL_OUT_RANGE); + + // Fail cases: not double + runG1ConcMarkStepDurationMillisTest(DOUBLE_INF, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(NEG_DOUBLE_INF, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(DOUBLE_NAN, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(WRONG_DOUBLE_1, FAIL_IMPROPER_VALUE); + runG1ConcMarkStepDurationMillisTest(WRONG_DOUBLE_2, FAIL_IMPROPER_VALUE); + } + + private static void runG1ConcMarkStepDurationMillisTest(String expectedValue, int expectedResult) throws Exception { + List vmOpts = new ArrayList<>(); + + Collections.addAll(vmOpts, "-XX:+UseG1GC", "-XX:G1ConcMarkStepDurationMillis="+expectedValue, "-XX:+PrintFlagsFinal", "-version"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(expectedResult == PASS ? 0 : 1); + String stdout = output.getStdout(); + if (expectedResult == PASS) { + checkG1ConcMarkStepDurationMillisConsistency(stdout, expectedValue); + } else if (expectedResult == FAIL_IMPROPER_VALUE) { + output.shouldContain("Improperly specified VM option"); + } else if (expectedResult == FAIL_OUT_RANGE) { + output.shouldContain("outside the allowed range"); + } + } + + private static void checkG1ConcMarkStepDurationMillisConsistency(String output, String expectedValue) { + double actualValue = getDoubleValue("G1ConcMarkStepDurationMillis", output); + + if (Double.parseDouble(expectedValue) != actualValue) { + throw new RuntimeException( + "Actual G1ConcMarkStepDurationMillis(" + Double.toString(actualValue) + + ") is not equal to expected value(" + expectedValue + ")"); + } + } + + public static double getDoubleValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + String match = m.group(); + return Double.parseDouble(match.substring(match.lastIndexOf(" ") + 1, match.length())); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/gc/arguments/TestG1HeapRegionSize.java --- a/hotspot/test/gc/arguments/TestG1HeapRegionSize.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/gc/arguments/TestG1HeapRegionSize.java Thu Oct 22 11:13:08 2015 -0700 @@ -25,42 +25,59 @@ * @test TestG1HeapRegionSize * @key gc * @bug 8021879 + * @requires vm.gc=="null" | vm.gc=="G1" * @summary Verify that the flag G1HeapRegionSize is updated properly * @modules java.management/sun.management - * @run main/othervm -Xmx64m TestG1HeapRegionSize 1048576 - * @run main/othervm -XX:G1HeapRegionSize=2m -Xmx64m TestG1HeapRegionSize 2097152 - * @run main/othervm -XX:G1HeapRegionSize=3m -Xmx64m TestG1HeapRegionSize 2097152 - * @run main/othervm -XX:G1HeapRegionSize=64m -Xmx256m TestG1HeapRegionSize 33554432 + * @library /testlibrary + * @run main TestG1HeapRegionSize */ -import com.sun.management.HotSpotDiagnosticMXBean; -import com.sun.management.VMOption; -import java.lang.management.ManagementFactory; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import java.util.ArrayList; +import java.util.Arrays; + +import jdk.test.lib.*; public class TestG1HeapRegionSize { - public static void main(String[] args) { - HotSpotDiagnosticMXBean diagnostic = - ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); + private static void checkG1HeapRegionSize(String[] flags, int expectedValue, int exitValue) throws Exception { + ArrayList flagList = new ArrayList(); + flagList.addAll(Arrays.asList(flags)); + flagList.add("-XX:+UseG1GC"); + flagList.add("-XX:+PrintFlagsFinal"); + flagList.add("-version"); - String expectedValue = getExpectedValue(args); - VMOption option = diagnostic.getVMOption("UseG1GC"); - if (option.getValue().equals("false")) { - System.out.println("Skipping this test. It is only a G1 test."); - return; - } + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(flagList.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(exitValue); - option = diagnostic.getVMOption("G1HeapRegionSize"); - if (!expectedValue.equals(option.getValue())) { - throw new RuntimeException("Wrong value for G1HeapRegionSize. Expected " + expectedValue + " but got " + option.getValue()); + if (exitValue == 0) { + String stdout = output.getStdout(); + int flagValue = getFlagValue("G1HeapRegionSize", stdout); + if (flagValue != expectedValue) { + throw new RuntimeException("Wrong value for G1HeapRegionSize. Expected " + expectedValue + " but got " + flagValue); + } } } - private static String getExpectedValue(String[] args) { - if (args.length != 1) { - throw new RuntimeException("Wrong number of arguments. Expected 1 but got " + args.length); + private static int getFlagValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?=\\s+\\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); } - return args[0]; + String match = m.group(); + return Integer.parseInt(match.substring(match.lastIndexOf(" ") + 1, match.length())); } + public static void main(String args[]) throws Exception { + final int M = 1024 * 1024; + + checkG1HeapRegionSize(new String[] { "-Xmx64m" /* default is 1m */ }, 1*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx64m", "-XX:G1HeapRegionSize=2m" }, 2*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx64m", "-XX:G1HeapRegionSize=3m" }, 2*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx256m", "-XX:G1HeapRegionSize=32m" }, 32*M, 0); + checkG1HeapRegionSize(new String[] { "-Xmx256m", "-XX:G1HeapRegionSize=64m" }, 32*M, 1); + } } diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/gc/arguments/TestHeapFreeRatio.java --- a/hotspot/test/gc/arguments/TestHeapFreeRatio.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/gc/arguments/TestHeapFreeRatio.java Thu Oct 22 11:13:08 2015 -0700 @@ -72,7 +72,7 @@ output.shouldHaveExitValue(1); break; case COMBINATION_INVALID: - output.shouldContain("must be greater than or equal to MinHeapFreeRatio"); + output.shouldContain("must be less than or equal to MaxHeapFreeRatio"); output.shouldContain("Error"); output.shouldHaveExitValue(1); break; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/gc/arguments/TestInitialTenuringThreshold.java --- a/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/gc/arguments/TestInitialTenuringThreshold.java Thu Oct 22 11:13:08 2015 -0700 @@ -25,6 +25,7 @@ * @test TestInitialTenuringThreshold * @key gc * @bug 8014765 + * @requires vm.gc=="Parallel" * @summary Tests argument processing for initial tenuring threshold * @library /testlibrary * @modules java.base/sun.misc @@ -39,6 +40,7 @@ public static void runWithThresholds(int initial, int max, boolean shouldfail) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseParallelGC", "-XX:InitialTenuringThreshold=" + String.valueOf(initial), "-XX:MaxTenuringThreshold=" + String.valueOf(max), "-version" diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/gc/arguments/TestObjectTenuringFlags.java --- a/hotspot/test/gc/arguments/TestObjectTenuringFlags.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/gc/arguments/TestObjectTenuringFlags.java Thu Oct 22 11:13:08 2015 -0700 @@ -25,6 +25,7 @@ * @test TestObjectTenuringFlags * @key gc * @bug 6521376 + * @requires vm.gc=="Parallel" * @summary Tests argument processing for NeverTenure, AlwaysTenure, * and MaxTenuringThreshold * @library /testlibrary @@ -157,7 +158,7 @@ if (tenuringFlags.length > 0) { Collections.addAll(vmOpts, tenuringFlags); } - Collections.addAll(vmOpts, "-XX:+PrintFlagsFinal", "-version"); + Collections.addAll(vmOpts, "-XX:+UseParallelGC", "-XX:+PrintFlagsFinal", "-version"); ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(vmOpts.toArray(new String[vmOpts.size()])); OutputAnalyzer output = new OutputAnalyzer(pb.start()); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/gc/g1/mixedgc/TestLogging.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/g1/mixedgc/TestLogging.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 TestLogging + * @summary Check that a mixed GC is reflected in the gc logs + * @requires vm.gc=="G1" | vm.gc=="null" + * @library /testlibrary /../../test/lib + * @ignore 8138607 + * @modules java.management + * @build sun.hotspot.WhiteBox gc.g1.mixedgc.TestLogging + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run driver gc.g1.mixedgc.TestLogging + */ + +package gc.g1.mixedgc; + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; + +/** + * Test spawns MixedGCProvoker in a separate VM and expects to find a message + * telling that a mixed gc has happened + */ +public class TestLogging { + private static final String[] COMMON_OPTIONS = new String[]{ + "-Xbootclasspath/a:.", "-XX:+UseG1GC", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:SurvivorRatio=1", // Survivor-to-eden ratio is 1:1 + "-Xms10M", "-Xmx10M", + "-XX:MaxTenuringThreshold=1", // promote objects after first gc + "-XX:InitiatingHeapOccupancyPercent=0", // marking cycle happens + // each time + "-XX:G1MixedGCCountTarget=4", + "-XX:MaxGCPauseMillis=30000", // to have enough time + "-XX:G1HeapRegionSize=1m", "-XX:G1HeapWastePercent=0", + "-XX:G1MixedGCLiveThresholdPercent=100"}; + + public static final int ALLOCATION_SIZE = 20000; + public static final int ALLOCATION_COUNT = 15; + + public static void main(String args[]) throws Exception { + // Test turns logging on by giving -XX:+PrintGC flag + test("-XX:+PrintGC"); + // Test turns logging on by giving -XX:+PrintGCDetails + test("-XX:+PrintGCDetails"); + } + + private static void test(String vmFlag) throws Exception { + System.out.println(String.format("%s: running with %s flag", TestLogging.class.getSimpleName(), vmFlag)); + OutputAnalyzer output = spawnMixedGCProvoker(vmFlag); + System.out.println(output.getStdout()); + output.shouldHaveExitValue(0); + output.shouldContain("GC pause (G1 Evacuation Pause) (mixed)"); + } + + /** + * Method spawns MixedGCProvoker with addition flags set + * + * @parameter extraFlags -flags to be added to the common options set + */ + private static OutputAnalyzer spawnMixedGCProvoker(String... extraFlags) + throws Exception { + List testOpts = new ArrayList<>(); + Collections.addAll(testOpts, COMMON_OPTIONS); + Collections.addAll(testOpts, extraFlags); + testOpts.add(MixedGCProvoker.class.getName()); + System.out.println(testOpts); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(false, + testOpts.toArray(new String[testOpts.size()])); + return new OutputAnalyzer(pb.start()); + } +} + +/** + * Utility class to guarantee a mixed GC. The class allocates several arrays and + * promotes them to the oldgen. After that it tries to provoke mixed GC by + * allocating new objects. + * + * The necessary condition for guaranteed mixed GC is running MixedGCProvoker is + * running in VM with the following flags: -XX:MaxTenuringThreshold=1, -Xms10M, + * -Xmx10M, -XX:G1MixedGCLiveThresholdPercent=100, -XX:G1HeapWastePercent=0, + * -XX:G1HeapRegionSize=1m + */ +class MixedGCProvoker { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final List liveOldObjects = new ArrayList<>(); + private static final List newObjects = new ArrayList<>(); + + private static void allocateOldObjects() throws Exception { + List deadOldObjects = new ArrayList<>(); + // Allocates buffer and promotes it to the old gen. Mix live and dead old + // objects + for (int i = 0; i < TestLogging.ALLOCATION_COUNT; ++i) { + liveOldObjects.add(new byte[TestLogging.ALLOCATION_SIZE * 10]); + deadOldObjects.add(new byte[TestLogging.ALLOCATION_SIZE * 10]); + } + + // need only 2 promotions to promote objects to the old gen + WB.youngGC(); + WB.youngGC(); + // check it is promoted & keep alive + Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects), + "List of the objects is suppose to be in OldGen"); + Asserts.assertTrue(WB.isObjectInOldGen(deadOldObjects), + "List of the objects is suppose to be in OldGen"); + } + + + /** + * Waits until Concurent Mark Cycle finishes + * @param wb Whitebox instance + * @param sleepTime sleep time + */ + public static void waitTillCMCFinished(WhiteBox wb, int sleepTime) { + while (wb.g1InConcurrentMark()) { + if (sleepTime > -1) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + System.out.println("Got InterruptedException while waiting for ConcMarkCycle to finish"); + } + } + } + } + + + + public static void main(String args[]) throws Exception { + // allocate old objects + allocateOldObjects(); + waitTillCMCFinished(WB, 0); + WB.g1StartConcMarkCycle(); + waitTillCMCFinished(WB, 0); + + WB.youngGC(); + System.out.println("Allocating new objects to provoke mixed GC"); + // allocate more objects to provoke GC + for (int i = 0; i < (TestLogging.ALLOCATION_COUNT * 20); i++) { + newObjects.add(new byte[TestLogging.ALLOCATION_SIZE]); + } + // check that liveOldObjects still alive + Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects), + "List of the objects is suppose to be in OldGen"); + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/gc/logging/TestPrintReferences.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/logging/TestPrintReferences.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 TestPrintReferences + * @bug 8136991 + * @summary Validate the reference processing logging + * @key gc + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + */ + +import jdk.test.lib.ProcessTools; +import jdk.test.lib.OutputAnalyzer; + +public class TestPrintReferences { + public static void main(String[] args) throws Exception { + ProcessBuilder pb_enabled = + ProcessTools.createJavaProcessBuilder("-XX:+PrintGCDetails", "-XX:+PrintReferenceGC", "-Xmx10M", GCTest.class.getName()); + OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start()); + + String countRegex = "[0-9]+ refs"; + String timeRegex = "[0-9]+[.,][0-9]+ secs"; + + output.shouldMatch( + "#[0-9]+: \\[SoftReference, " + countRegex + ", " + timeRegex + "\\]" + + "#[0-9]+: \\[WeakReference, " + countRegex + ", " + timeRegex + "\\]" + + "#[0-9]+: \\[FinalReference, " + countRegex + ", " + timeRegex + "\\]" + + "#[0-9]+: \\[PhantomReference, " + countRegex + ", " + timeRegex + "\\]" + + "#[0-9]+: \\[JNI Weak Reference, (" + countRegex + ", )?" + timeRegex + "\\]"); + + output.shouldHaveExitValue(0); + } + + static class GCTest { + public static void main(String [] args) { + System.gc(); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/6888954/vmerrors.sh --- a/hotspot/test/runtime/6888954/vmerrors.sh Thu Oct 22 08:47:43 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please 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 6888954 -# @bug 8015884 -# @summary exercise HotSpot error handling code -# @author John Coomes -# @run shell vmerrors.sh - -# Repeatedly invoke java with a command-line option that causes HotSpot to -# produce an error report and terminate just after initialization. Each -# invocation is identified by a small integer, , which provokes a different -# error (assertion failure, guarantee failure, fatal error, etc.). The output -# from stdout/stderr is written to .out and the hs_err_pidXXX.log file is -# renamed to .log. -# -# The automated checking done by this script is minimal. When updating the -# fatal error handler it is more useful to run it manually or to use the -retain -# option with the jtreg so that test directories are not removed automatically. -# To run stand-alone: -# -# TESTJAVA=/java/home/dir -# TESTVMOPTS=... -# export TESTJAVA TESTVMOPTS -# sh test/runtime/6888954/vmerrors.sh - -if [ "${TESTSRC}" = "" ] -then - TESTSRC=${PWD} - echo "TESTSRC not set. Using "${TESTSRC}" as default" -fi -echo "TESTSRC=${TESTSRC}" - -## Adding common setup Variables for running shell tests. -. ${TESTSRC}/../../test_env.sh - -ulimit -c 0 # no core files - -i=1 -rc=0 - -assert_re='(assert|guarantee)[(](str|num).*failed: *' -# for bad_data_ptr_re: -# EXCEPTION_ACCESS_VIOLATION - Win-* -# SIGILL - MacOS X -# SIGSEGV - Linux-*, Solaris SPARC-*, Solaris X86-* -# -bad_data_ptr_re='(SIGILL|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).* at pc=' -# -# for bad_func_ptr_re: -# EXCEPTION_ACCESS_VIOLATION - Win-* -# SIGBUS - Solaris SPARC-64 -# SIGSEGV - Linux-*, Solaris SPARC-32, Solaris X86-* -# SIGILL - Aix -# -# Note: would like to use "pc=0x00*0f," in the pattern, but Solaris SPARC-* -# gets its signal at a PC in test_error_handler(). -# -bad_func_ptr_re='(SIGBUS|SIGSEGV|SIGILL|EXCEPTION_ACCESS_VIOLATION).* at pc=' -guarantee_re='guarantee[(](str|num).*failed: *' -fatal_re='fatal error: *' -tail_1='.*expected null' -tail_2='.*num=' - -for re in \ - "${assert_re}${tail_1}" "${assert_re}${tail_2}" \ - "${guarantee_re}${tail_1}" "${guarantee_re}${tail_2}" \ - "${fatal_re}${tail_1}" "${fatal_re}${tail_2}" \ - "${fatal_re}.*truncated" "ChunkPool::allocate" \ - "ShouldNotCall" "ShouldNotReachHere" \ - "Unimplemented" "$bad_data_ptr_re" \ - "$bad_func_ptr_re" - -do - i2=$i - [ $i -lt 10 ] && i2=0$i - - "$TESTJAVA/bin/java" $TESTOPTS -XX:+IgnoreUnrecognizedVMOptions \ - -XX:-TransmitErrorReport -XX:-CreateMinidumpOnCrash \ - -XX:ErrorHandlerTest=${i} -version > ${i2}.out 2>&1 - - # If ErrorHandlerTest is ignored (product build), stop. - # - # Using the built-in variable $! to get the pid does not work reliably on - # windows; use a wildcard instead. - mv hs_err_pid*.log ${i2}.log || exit $rc - - for f in ${i2}.log ${i2}.out - do - egrep -- "$re" $f > $$ - if [ $? -ne 0 ] - then - echo "ErrorHandlerTest=$i failed ($f)" - rc=1 - fi - done - rm -f $$ - - i=`expr $i + 1` -done - -exit $rc diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java --- a/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/runtime/CommandLine/CompilerConfigFileWarning.java Thu Oct 22 11:13:08 2015 -0700 @@ -46,7 +46,7 @@ pb = ProcessTools.createJavaProcessBuilder("-XX:CompileCommandFile=hs_comp.txt", "-version"); output = new OutputAnalyzer(pb.start()); output.shouldContain("CompileCommand: unrecognized command"); - output.shouldContain("aaa aaa"); + output.shouldContain("aaa, aaa"); // Skip on debug builds since we'll always read the file there if (!Platform.isDebugBuild()) { diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Thu Oct 22 11:13:08 2015 -0700 @@ -51,6 +51,32 @@ */ allOptionsAsMap.remove("CICompilerCount"); + /* + * Exclude below options as their maximum value would consume too much memory + * and would affect other tests that run in parallel. + */ + allOptionsAsMap.remove("G1ConcRefinementThreads"); + allOptionsAsMap.remove("G1RSetRegionEntries"); + allOptionsAsMap.remove("G1RSetSparseRegionEntries"); + + /* + * Remove parameters controlling the code cache. As these + * parameters have implications on the physical memory + * reserved by the VM, setting them to large values may hang + * the system and/or may cause concurrently executed tests to + * fail. These parameters are rigorously checked when the code + * cache is initialized (see + * hotspot/src/shared/vm/code/codeCache.cpp), therefore + * omitting testing for them does not pose a problem. + */ + allOptionsAsMap.remove("InitialCodeCacheSize"); + allOptionsAsMap.remove("CodeCacheMinimumUseSpace"); + allOptionsAsMap.remove("ReservedCodeCacheSize"); + allOptionsAsMap.remove("NonProfiledCodeHeapSize"); + allOptionsAsMap.remove("ProfiledCodeHeapSize"); + allOptionsAsMap.remove("NonNMethodCodeHeapSize"); + allOptionsAsMap.remove("CodeCacheExpansionSize"); + allOptions = new ArrayList<>(allOptionsAsMap.values()); Asserts.assertGT(allOptions.size(), 0, "Options with ranges not found!"); diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/TestVMOptionsFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/TestVMOptionsFile.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8061999 + * @summary Test "-XX:VMOptionsFile" VM option + * @library /testlibrary + * @modules jdk.management + * @run main TestVMOptionsFile + */ + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermissions; +import java.nio.file.attribute.AclEntry; +import java.nio.file.attribute.AclEntryPermission; +import java.nio.file.attribute.AclEntryType; +import java.nio.file.attribute.AclFileAttributeView; +import java.nio.file.attribute.UserPrincipal; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import jdk.test.lib.Asserts; +import jdk.test.lib.DynamicVMOption; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class TestVMOptionsFile { + + /* Various valid VM Option files */ + private static final String VM_OPTION_FILE_EMPTY = "optionfile_empty"; + private static final String VM_OPTION_FILE_TABS_AND_SPACES = "optionfile_only_tabsandspaces"; + private static final String VM_OPTION_FILE_1 = "optionfile_1"; + private static final String VM_OPTION_FILE_2 = "optionFILE_2"; + private static final String VM_OPTION_FILE_3 = "optionfile_3"; + private static final String VM_OPTION_FILE_QUOTE = "optionfile_quote"; + private static final String VM_OPTION_FILE_BIG = "optionfile_big"; + private static final int REPEAT_COUNT = 512; + /* Name of the file with flags for VM_OPTION_FILE_2 Option file */ + private static final String FLAGS_FILE = "flags_file"; + /* VM Option file with a lot of options with quote on separate lines */ + private static final String VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE = "optionfile_lot_of_options_quote"; + /* Number of properties defined in VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE */ + private static final int NUM_OF_PROP_IN_FILE_LOT_OF_OPTIONS_QUOTE = 70; + /* VM Option file with long property */ + private static final String VM_OPTION_FILE_WITH_LONG_PROPERTY = "optionfile_long_property"; + private static final String LONG_PROPERTY_NAME = "veryl'" + String.format("%1536s", "").replace(' ', 'o') + "ng'name"; + private static final String LONG_PROPERTY_VALUE = String.format("%2096s", "").replaceAll(" ", "long"); + /* 2 VM Option files with unmatched quotes */ + private static final String VM_OPTION_FILE_UNMATCHED_QUOTE_1 = "optionfile_unmatched_quote_1"; + private static final String VM_OPTION_FILE_UNMATCHED_QUOTE_2 = "optionfile_unmatched_quote_2"; + /* VM Option file with bad option in it */ + private static final String VM_OPTION_FILE_WITH_BAD_OPTION = "optionfile_bad_option"; + /* VM Option file with "-XX:VMOptionsFile=" option in it */ + private static final String VM_OPTION_FILE_WITH_VM_OPTION_FILE = "optionfile_with_optionfile"; + /* VM Option file with "-XX:VMOptionsFile=" option in it, where file is the same option file */ + private static final String VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE = "optionfile_with_same_optionfile"; + /* VM Option file without read permissions(not accessible) */ + private static final String VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS = "optionfile_wo_read_perm"; + /* VM Option file which does not exist */ + private static final String NOT_EXISTING_FILE = "not_exist_junk2123"; + + /* JAVA_TOOL_OPTIONS environment variable */ + private static final String JAVA_TOOL_OPTIONS = "JAVA_TOOL_OPTIONS"; + /* _JAVA_OPTIONS environment variable */ + private static final String JAVA_OPTIONS = "_JAVA_OPTIONS"; + + /* Exit code for JVM, zero - for success, non-zero for failure */ + private static final int JVM_SUCCESS = 0; + private static final int JVM_FAIL_WITH_EXIT_CODE_1 = 1; + + /* Current working directory */ + private static final String CURRENT_DIR = System.getProperty("user.dir"); + + /* Source directory */ + private static final String SOURCE_DIR = System.getProperty("test.src", "."); + + /* VM Options which are passed to the JVM */ + private static final List VMParams = new ArrayList<>(); + /* Argument passed to the PrintPropertyAndOptions.main */ + private static final Set appParams = new LinkedHashSet<>(); + + private static OutputAnalyzer output; + + private static final String PRINT_PROPERTY_FORMAT = "Property %s=%s"; + private static final String PRINT_VM_OPTION_FORMAT = "Virtual Machine option %s=%s"; + + /* + * Get absoulte path to file from folder with sources + */ + private static String getAbsolutePathFromSource(String fileName) { + return SOURCE_DIR + File.separator + fileName; + } + + /* + * Make file non-readable by modifying its permissions. + * If file supports "posix" attributes, then modify it. + * Otherwise check for "acl" attributes. + */ + private static void makeFileNonReadable(String file) throws IOException { + Path filePath = Paths.get(file); + Set supportedAttr = filePath.getFileSystem().supportedFileAttributeViews(); + + if (supportedAttr.contains("posix")) { + Files.setPosixFilePermissions(filePath, PosixFilePermissions.fromString("-w--w----")); + } else if (supportedAttr.contains("acl")) { + UserPrincipal fileOwner = Files.getOwner(filePath); + + AclFileAttributeView view = Files.getFileAttributeView(filePath, AclFileAttributeView.class); + + AclEntry entry = AclEntry.newBuilder() + .setType(AclEntryType.DENY) + .setPrincipal(fileOwner) + .setPermissions(AclEntryPermission.READ_DATA) + .build(); + + List acl = view.getAcl(); + acl.add(0, entry); + view.setAcl(acl); + } + } + + private static void copyFromSource(String fileName) throws IOException { + Files.copy(Paths.get(getAbsolutePathFromSource(fileName)), + Paths.get(fileName), StandardCopyOption.REPLACE_EXISTING); + } + + private static void createOptionFiles() throws IOException { + FileWriter fw = new FileWriter(VM_OPTION_FILE_WITH_VM_OPTION_FILE); + + /* Create VM option file with following parameters "-XX:VMOptionFile= */ + fw.write("-XX:VMOptionsFile=" + getAbsolutePathFromSource(VM_OPTION_FILE_1)); + fw.close(); + + /* Create VM option file with following parameters "-XX:MinHeapFreeRatio=12 -XX:VMOptionFile= */ + fw = new FileWriter(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE); + fw.write("-XX:MinHeapFreeRatio=12 -XX:VMOptionsFile=" + (new File(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE)).getCanonicalPath()); + fw.close(); + + /* Create VM option file with long property */ + fw = new FileWriter(VM_OPTION_FILE_WITH_LONG_PROPERTY); + fw.write("-D" + LONG_PROPERTY_NAME + "=" + LONG_PROPERTY_VALUE); + fw.close(); + + /* Create big VM option file */ + fw = new FileWriter(VM_OPTION_FILE_BIG); + fw.write("-XX:MinHeapFreeRatio=17\n"); + for (int i = 0; i < REPEAT_COUNT; i++) { + if (i == REPEAT_COUNT / 2) { + fw.write("-XX:+PrintVMOptions "); + } + fw.write("-Dmy.property=value" + (i + 1) + "\n"); + } + fw.write("-XX:MaxHeapFreeRatio=85\n"); + fw.close(); + + /* Copy valid VM option file and change its permission to make it not accessible */ + Files.copy(Paths.get(getAbsolutePathFromSource(VM_OPTION_FILE_1)), + Paths.get(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS), + StandardCopyOption.REPLACE_EXISTING); + + makeFileNonReadable(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS); + + /* Copy valid VM option file to perform test with relative path */ + copyFromSource(VM_OPTION_FILE_2); + + /* Copy flags file to the current working folder */ + copyFromSource(FLAGS_FILE); + + /* Create a new empty file */ + new File(VM_OPTION_FILE_EMPTY).createNewFile(); + } + + /* + * Add parameters to the VM Parameters list + */ + private static void addVMParam(String... params) { + VMParams.addAll(Arrays.asList(params)); + } + + /* + * Add VM option name to the application arguments list + */ + private static void addVMOptionsToCheck(String... params) { + for (String param : params) { + appParams.add("vmoption=" + param); + } + } + + /* + * Add property to the VM Params list and to the application arguments list + */ + private static void addProperty(String propertyName, String propertyValue) { + addVMParam("-D" + propertyName + "=" + propertyValue); + } + + /* + * Add "-XX:VMOptionsfile" parameter to the VM Params list + */ + private static void addVMOptionsFile(String fileName) { + addVMParam("-XX:VMOptionsFile=" + fileName); + } + + private static void outputShouldContain(String expectedString) { + output.shouldContain(expectedString); + } + + private static void outputShouldNotContain(String expectedString) { + output.shouldNotContain(expectedString); + } + + private static ProcessBuilder createProcessBuilder() throws Exception { + ProcessBuilder pb; + List runJava = new ArrayList<>(); + + runJava.addAll(VMParams); + runJava.add(PrintPropertyAndOptions.class.getName()); + runJava.addAll(appParams); + + pb = ProcessTools.createJavaProcessBuilder(runJava.toArray(new String[0])); + + VMParams.clear(); + appParams.clear(); + + return pb; + } + + private static void runJavaCheckExitValue(ProcessBuilder pb, int expectedExitValue) throws Exception { + output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(expectedExitValue); + } + + private static void runJavaCheckExitValue(int expectedExitValue) throws Exception { + runJavaCheckExitValue(createProcessBuilder(), expectedExitValue); + } + + /* + * Update environment variable in passed ProcessBuilder object to the passed value + */ + private static void updateEnvironment(ProcessBuilder pb, String name, String value) { + pb.environment().put(name, value); + } + + /* + * Check property value by examining output + */ + private static void checkProperty(String property, String expectedValue) { + outputShouldContain(String.format(PRINT_PROPERTY_FORMAT, property, expectedValue)); + } + + /* + * Check VM Option value by examining output + */ + private static void checkVMOption(String vmOption, String expectedValue) { + outputShouldContain(String.format(PRINT_VM_OPTION_FORMAT, vmOption, expectedValue)); + } + + private static void testVMOptions() throws Exception { + /* Check that empty VM Option file is accepted without errors */ + addVMOptionsFile(VM_OPTION_FILE_EMPTY); + + runJavaCheckExitValue(JVM_SUCCESS); + + /* Check that VM Option file with tabs and spaces is accepted without errors */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_TABS_AND_SPACES)); + + runJavaCheckExitValue(JVM_SUCCESS); + + /* Check that parameters are gotten from first VM Option file. Pass absolute path to the VM Option file */ + addVMParam("-showversion"); + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1)); + addVMOptionsToCheck("SurvivorRatio", "MinHeapFreeRatio"); + + runJavaCheckExitValue(JVM_SUCCESS); + outputShouldContain("interpreted mode"); + checkProperty("optfile_1", "option_file_1"); + checkVMOption("SurvivorRatio", "16"); + checkVMOption("MinHeapFreeRatio", "22"); + + /* + * Check that parameters are gotten from second VM Option file which also contains flags file. + * Flags file and option file contains NewRatio, but since options from VM Option file + * are processed later NewRatio should be set to value from VM Option file + * Pass relative path to the VM Option file in form "vmoptionfile" + */ + addVMOptionsFile(VM_OPTION_FILE_2); + addVMOptionsToCheck("UseGCOverheadLimit", "NewRatio", "MinHeapFreeRatio", "MaxFDLimit", "AlwaysPreTouch"); + + runJavaCheckExitValue(JVM_SUCCESS); + checkProperty("javax.net.ssl.keyStorePassword", "someVALUE123+"); + checkVMOption("UseGCOverheadLimit", "true"); + checkVMOption("NewRatio", "4"); + checkVMOption("MinHeapFreeRatio", "3"); + checkVMOption("MaxFDLimit", "true"); + checkVMOption("AlwaysPreTouch", "false"); + + /* Check that parameters are gotten from third VM Option file which contains a mix of the options */ + addVMParam("-showversion"); + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_3)); + addVMOptionsToCheck("UseGCOverheadLimit", "NewRatio"); + + runJavaCheckExitValue(JVM_SUCCESS); + outputShouldContain("interpreted mode"); + checkProperty("other.secret.data", "qwerty"); + checkProperty("property", "second"); + checkVMOption("UseGCOverheadLimit", "false"); + checkVMOption("NewRatio", "16"); + + /* Check that quotes are processed normally in VM Option file */ + addVMParam("-showversion"); + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_QUOTE)); + addVMOptionsToCheck("ErrorFile"); + + runJavaCheckExitValue(JVM_SUCCESS); + + outputShouldContain("interpreted mode"); + checkProperty("my.quote.single", "Property in single quote. Here a double qoute\" Add some slashes \\/"); + checkProperty("my.quote.double", "Double qoute. Include single '."); + checkProperty("javax.net.ssl.trustStorePassword", "data @+NEW"); + checkVMOption("ErrorFile", "./my error file"); + + /* + * Verify that VM Option file accepts a file with 70 properties and with two options on separate + * lines and properties that use quotes a lot. + */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_LOT_OF_OPTIONS_QUOTE)); + addVMOptionsToCheck("MinHeapFreeRatio", "MaxHeapFreeRatio"); + + runJavaCheckExitValue(JVM_SUCCESS); + + for (int i = 1; i <= NUM_OF_PROP_IN_FILE_LOT_OF_OPTIONS_QUOTE; i++) { + checkProperty(String.format("prop%02d", i), String.format("%02d", i)); + } + checkVMOption("MinHeapFreeRatio", "7"); + checkVMOption("MaxHeapFreeRatio", "96"); + + /* + * Verify that VM Option file accepts a file with very long property. + */ + addVMOptionsFile(VM_OPTION_FILE_WITH_LONG_PROPERTY); + + runJavaCheckExitValue(JVM_SUCCESS); + + checkProperty(LONG_PROPERTY_NAME.replaceAll("'", ""), LONG_PROPERTY_VALUE); + + /* + * Verify that VM Option file accepts a big VM Option file + */ + addVMOptionsFile(VM_OPTION_FILE_BIG); + addVMOptionsToCheck("MinHeapFreeRatio"); + addVMOptionsToCheck("MaxHeapFreeRatio"); + + runJavaCheckExitValue(JVM_SUCCESS); + + outputShouldContain("VM option '+PrintVMOptions'"); + checkProperty("my.property", "value" + REPEAT_COUNT); + checkVMOption("MinHeapFreeRatio", "17"); + checkVMOption("MaxHeapFreeRatio", "85"); + } + + private static ProcessBuilder prepareTestCase(int testCase) throws Exception { + ProcessBuilder pb; + + Asserts.assertTrue(0 < testCase && testCase < 6, "testCase should be from 1 to 5"); + + addVMParam("-showversion"); + addVMOptionsToCheck("MinHeapFreeRatio", "SurvivorRatio", "NewRatio"); + + if (testCase < 5) { + addVMParam("-XX:Flags=flags_file", "-XX:-PrintVMOptions"); + addProperty("shared.property", "command_line_before"); + addProperty("clb", "unique_command_line_before"); + addVMParam("-XX:MinHeapFreeRatio=7"); + } + + if (testCase < 4) { + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1)); + } + + if (testCase < 3) { + addVMParam("-XX:MinHeapFreeRatio=9", "-XX:-PrintVMOptions"); + addProperty("shared.property", "command_line_after"); + addProperty("cla", "unique_command_line_after"); + } + + /* Create ProcessBuilder after all setup is done to update environment variables */ + pb = createProcessBuilder(); + + if (testCase < 2) { + updateEnvironment(pb, JAVA_OPTIONS, "-Dshared.property=somevalue -Djo=unique_java_options " + + "-XX:MinHeapFreeRatio=18 -Dshared.property=java_options -XX:MinHeapFreeRatio=11 -XX:+PrintVMOptions"); + } + + if (testCase < 6) { + updateEnvironment(pb, JAVA_TOOL_OPTIONS, "-Dshared.property=qwerty -Djto=unique_java_tool_options " + + "-XX:MinHeapFreeRatio=15 -Dshared.property=java_tool_options -XX:MinHeapFreeRatio=6 -XX:+PrintVMOptions"); + } + + return pb; + } + + private static void testVMOptionsLastArgumentsWins() throws Exception { + ProcessBuilder pb; + + /* + * "shared.property" property and "MinHeapFreeRatio" XX VM Option are defined + * in flags file, JAVA_TOOL_OPTIONS and _JAVA_OPTIONS environment variables, + * on command line before VM Option file, on command line after VM Option file + * and also in VM Option file. Verify that last argument wins. Also check + * unique properties and VM Options. + * Here is the order of options processing and last argument wins: + * 1) Flags file + * 2) JAVA_TOOL_OPTIONS environment variables + * 3) Pseudo command line from launcher + * 4) _JAVA_OPTIONS + * In every category arguments processed from left to right and from up to down + * and the last processed arguments wins, i.e. if argument is defined several + * times the value of argument will be equal to the last processed argument. + * + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from _JAVA_OPTIONS environment variable + */ + pb = prepareTestCase(1); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldContain("interpreted mode"); + outputShouldContain("VM option '+PrintVMOptions'"); + checkProperty("shared.property", "java_options"); + checkVMOption("MinHeapFreeRatio", "11"); + /* Each category defines its own properties */ + checkProperty("jto", "unique_java_tool_options"); + checkProperty("jo", "unique_java_options"); + checkProperty("clb", "unique_command_line_before"); + checkProperty("optfile_1", "option_file_1"); + checkProperty("cla", "unique_command_line_after"); + /* SurvivorRatio defined only in VM Option file */ + checkVMOption("SurvivorRatio", "16"); + /* NewRatio defined only in flags file */ + checkVMOption("NewRatio", "5"); + + /* + * The same as previous but without _JAVA_OPTIONS environment variable. + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from pseudo command line after VM Option file + */ + pb = prepareTestCase(2); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldContain("interpreted mode"); + checkProperty("shared.property", "command_line_after"); + checkVMOption("MinHeapFreeRatio", "9"); + + /* + * The same as previous but without arguments in pseudo command line after + * VM Option file. + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from VM Option file. + */ + pb = prepareTestCase(3); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldContain("interpreted mode"); + outputShouldContain("VM option '+PrintVMOptions'"); + checkProperty("shared.property", "vmoptfile"); + checkVMOption("MinHeapFreeRatio", "22"); + + /* + * The same as previous but without arguments in VM Option file. + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from pseudo command line. + */ + pb = prepareTestCase(4); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldNotContain("VM option '+PrintVMOptions'"); + checkProperty("shared.property", "command_line_before"); + checkVMOption("MinHeapFreeRatio", "7"); + + /* + * The same as previous but without arguments from pseudo command line. + * "shared.property" property and "MinHeapFreeRatio" should be equal to the + * value from JAVA_TOOL_OPTIONS environment variable. + */ + pb = prepareTestCase(5); + + runJavaCheckExitValue(pb, JVM_SUCCESS); + + outputShouldContain("VM option '+PrintVMOptions'"); + checkProperty("shared.property", "java_tool_options"); + checkVMOption("MinHeapFreeRatio", "6"); + } + + private static void testVMOptionsInvalid() throws Exception { + ProcessBuilder pb; + + /* Pass directory instead of file */ + addVMOptionsFile(CURRENT_DIR); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + + /* Pass not existing file */ + addVMOptionsFile(getAbsolutePathFromSource(NOT_EXISTING_FILE)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Could not open options file"); + + /* Pass VM option file with bad option */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITH_BAD_OPTION)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Unrecognized VM option"); + + /* Pass VM option file with same VM option file option in it */ + addVMOptionsFile(VM_OPTION_FILE_WITH_SAME_VM_OPTION_FILE); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("VM options file is only supported on the command line"); + + /* Pass VM option file with VM option file option in it */ + addVMOptionsFile(VM_OPTION_FILE_WITH_VM_OPTION_FILE); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("VM options file is only supported on the command line"); + + /* Pass VM option file which is not accessible (without read permissions) */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_WITHOUT_READ_PERMISSIONS)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Could not open options file"); + + /* Pass two VM option files */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_1)); + addVMOptionsFile(VM_OPTION_FILE_2); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Only one VM Options file is supported on the command line"); + + /* Pass empty option file i.e. pass "-XX:VMOptionsFile=" */ + addVMOptionsFile(""); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Could not open options file"); + + /* Pass VM option file with unmatched single quote */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_UNMATCHED_QUOTE_1)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Unmatched quote in"); + + /* Pass VM option file with unmatched double quote in X option */ + addVMOptionsFile(getAbsolutePathFromSource(VM_OPTION_FILE_UNMATCHED_QUOTE_2)); + + runJavaCheckExitValue(JVM_FAIL_WITH_EXIT_CODE_1); + outputShouldContain("Unmatched quote in"); + } + + public static void main(String[] args) throws Exception { + /* + * Preparation before actual testing - create two VM Option files + * which contains VM Option file in it and copy other files to the + * current working folder + */ + createOptionFiles(); + + testVMOptions(); /* Test VM Option file general functionality */ + testVMOptionsLastArgumentsWins(); /* Verify that last argument wins */ + testVMOptionsInvalid(); /* Test invalid VM Option file functionality */ + + } + + public static class PrintPropertyAndOptions { + + public static void main(String[] arguments) { + String vmOption; + Properties properties = System.getProperties(); + + for (String propertyName : properties.stringPropertyNames()) { + System.out.println(String.format(PRINT_PROPERTY_FORMAT, propertyName, System.getProperty(propertyName, "NOT DEFINED"))); + } + + for (String arg : arguments) { + if (arg.startsWith("vmoption=")) { + vmOption = arg.substring(9); + System.out.println(String.format(PRINT_VM_OPTION_FORMAT, vmOption, new DynamicVMOption(vmOption).getValue())); + } + } + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/flags_file --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/flags_file Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,5 @@ ++MaxFDLimit +-AlwaysPreTouch +MinHeapFreeRatio=3 +MaxHeapFreeRatio=89 +NewRatio=5 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/optionFILE_2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionFILE_2 Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,4 @@ +-XX:+UseGCOverheadLimit +-XX:Flags=flags_file +-Djavax.net.ssl.keyStorePassword=someVALUE123+ +-XX:NewRatio=4 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_1 Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +-Dshared.property=othervalue -XX:MinHeapFreeRatio=13 -Doptfile_1=option_file_1 -Xint -XX:SurvivorRatio=16 -Xminf0.22 -Dshared.property=vmoptfile -XX:+PrintVMOptions diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_3 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_3 Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,8 @@ +-Xcomp -Dproperty=first + + -Xint +-XX:+UseGCOverheadLimit + + -XX:NewRatio=4 -XX:-UseGCOverheadLimit -Dproperty=second + +-Dother.secret.data=qwerty -XX:NewRatio=16 diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_bad_option --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_bad_option Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +-Dmy.property=user1 -XX:bad_option -Xint diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_lot_of_options_quote --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_lot_of_options_quote Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,72 @@ +-Dprop01='01' +-Dprop02='02' +-Dprop03='03' +-Dprop04='04' +-Dprop05='05' +-D"pr"op06='06' +-Dprop07='07' +-Dprop08='08' +-Dprop09="09" +-Dprop"10=10" +-Dprop11='11' +'-Dprop12=12' +-Dprop13='13' +-Dprop14='14' +-Dprop15='15' +-Dprop16='16' +-Dprop17='17' +-Dprop18='18' +-Dprop19='19' +-Dprop20='20' +-Dprop21='21' +-Dprop22='22' +-Dprop23='23' +-Dpr'o'p24='24' +-Dprop25='25' +-Dprop26='26' +-Dprop27='27' +-Dprop28='28' +-XX:MinHeapFreeRatio=7 +-D"prop29=29" +-Dprop30='30' +-Dprop31='31' +-Dprop32="32" +-Dprop33='33' +-Dprop34='34' +-Dprop35='35' +'-Dpr'op36='36' +-Dprop37='37' +-Dprop38='38' +-Dprop39='39' +-Dprop40='40' +-Dprop41='41' +-Dprop42='42' +-Dprop43='43' +-Dprop44='44' +-Dprop45='45' +-D"prop46="'46' +-Dprop47='47' +-Dprop48='48' +-Dprop49='49' -XX:MaxHeapFreeRatio=96 +"-"Dprop50='50' +-Dprop51='51' +-Dprop52='52' +-Dprop53='53' +-Dprop54='54' +-Dprop55='55' +-Dprop56='56' +-Dprop57='57' +-"D"prop58='58' +-Dprop59='59' +'-Dprop60=''60' +-Dprop61='61' +-Dprop62='62' +-Dprop63='63' +-Dprop64=64 +-Dprop65=65 +-Dprop66=66 +-Dprop67=67 +-Dprop68=68 +-Dprop69=69 +-Dprop70=70 + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_only_tabsandspaces --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_only_tabsandspaces Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,4 @@ + + + + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_quote --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_quote Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +'-Dmy.quote.single'='Property in single quote. Here a double qoute" Add some slashes \/' -D"my.quote.double"="Double qoute. Include single '." -'Xi'n"t" -X"X:ErrorFile"=./my' error file' -Djavax.net.ssl.trustStorePassword='data @+NEW' diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_1 Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +-Dmy.quote.single='Unmatched single quote with embedded double " quote diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_2 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/CommandLine/VMOptionsFile/optionfile_unmatched_quote_2 Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,1 @@ +-"Xloggc:Unmatched quote in X option diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/runtime/ErrorHandling/ErrorHandler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/ErrorHandling/ErrorHandler.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 6888954 + * @bug 8015884 + * @summary Exercise HotSpot error handling code by invoking java with + * -XX:ErrorHandlerTest option to cause an error report. Check the results. + * @library /testlibrary + * @run driver ErrorHandler + */ + +import jdk.test.lib.*; + +public class ErrorHandler { + + public static OutputAnalyzer runTest(int testcase) throws Exception { + return new OutputAnalyzer( + ProcessTools.createJavaProcessBuilder( + "-XX:-TransmitErrorReport", "-XX:-CreateCoredumpOnCrash", "-XX:ErrorHandlerTest=" + testcase) + .start()); + } + + public static void main(String[] args) throws Exception { + // Test is only applicable for debug builds + if (!Platform.isDebugBuild()) { + return; + } + // Keep this in sync with hotspot/src/share/vm/utilities/debug.cpp + int i = 1; + String[] strings = { + "assert(str == NULL) failed: expected null", + "assert(num == 1023 && *str == 'X') failed: num=", + "guarantee(str == NULL) failed: expected null", + "guarantee(num == 1023 && *str == 'X') failed: num=", + "fatal error: expected null", + "fatal error: num=", + "fatal error: this message should be truncated during formatting", + "ChunkPool::allocate", + "Error: ShouldNotCall()", + "Error: ShouldNotReachHere()", + "Error: Unimplemented()" + }; + + String[] patterns = { + "(SIGILL|SIGSEGV|EXCEPTION_ACCESS_VIOLATION).* at pc=", + "(SIGBUS|SIGSEGV|SIGILL|EXCEPTION_ACCESS_VIOLATION).* at pc=" + }; + + for (String s : strings) { + runTest(i++).shouldContain(s); + } + + for (String p : patterns) { + runTest(i++).shouldMatch(p); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/serviceability/logging/TestBasicLogOutput.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/logging/TestBasicLogOutput.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 TestBasicLogOutput + * @summary Ensure logging can be enabled and successfully prints to stdout. + * @library /testlibrary + */ + +import jdk.test.lib.ProcessTools; +import jdk.test.lib.OutputAnalyzer; + +public class TestBasicLogOutput { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:all=trace", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldMatch("\\[logging *\\]"); // expected tag(s) + output.shouldContain("Log configuration fully initialized."); // expected message + output.shouldHaveExitValue(0); + } +} + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/serviceability/sa/DeadlockDetectionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/sa/DeadlockDetectionTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + + +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.apps.LingeredAppWithDeadlock; + +import jdk.test.lib.Utils; +import jdk.test.lib.Platform; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +/* + * @test + * @summary Test deadlock detection + * @library /../../test/lib/share/classes + * @library /testlibrary + * @modules java.management + * @build jdk.test.lib.* + * @build jdk.test.lib.apps.* + * @build DeadlockDetectionTest + * @run main DeadlockDetectionTest + */ + +public class DeadlockDetectionTest { + + private static LingeredAppWithDeadlock theApp = null; + private static ProcessBuilder processBuilder = new ProcessBuilder(); + + private static OutputAnalyzer jstack(String... toolArgs) throws Exception { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb"); + launcher.addToolArg("jstack"); + if (toolArgs != null) { + for (String toolArg : toolArgs) { + launcher.addToolArg(toolArg); + } + } + + processBuilder.command(launcher.getCommand()); + System.out.println(processBuilder.command().stream().collect(Collectors.joining(" "))); + OutputAnalyzer output = ProcessTools.executeProcess(processBuilder); + System.out.println(output.getOutput()); + + return output; + } + + public static void main(String[] args) throws Exception { + System.out.println("Starting DeadlockDetectionTest"); + + if (!Platform.shouldSAAttach()) { + // Silently skip the test if we don't have enough permissions to attach + // Not all conditions checked by function is relevant to SA but it's worth + // to check + System.err.println("Error! Insufficient permissions to attach."); + return; + } + + + if (!LingeredApp.isLastModifiedWorking()) { + // Exact behaviour of the test depends on operating system and the test nature, + // so just print the warning and continue + System.err.println("Warning! Last modified time doesn't work."); + } + + try { + List vmArgs = new ArrayList(); + vmArgs.add("-XX:+UsePerfData"); + vmArgs.addAll(Utils.getVmOptions()); + + theApp = new LingeredAppWithDeadlock(); + LingeredApp.startApp(vmArgs, theApp); + OutputAnalyzer output = jstack("--pid", Long.toString(theApp.getPid())); + System.out.println(output.getOutput()); + + if (output.getExitValue() == 3) { + System.out.println("Test can't run for some reason. Skipping"); + } + else { + output.shouldHaveExitValue(0); + output.shouldContain("Found a total of 1 deadlock."); + } + + } finally { + LingeredApp.stopApp(theApp); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/test_env.sh --- a/hotspot/test/test_env.sh Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/test_env.sh Thu Oct 22 11:13:08 2015 -0700 @@ -111,7 +111,8 @@ exit 1 fi -${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xinternalversion > vm_version.out 2>&1 +${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xinternalversion | sed -e 's/[(][^)]*[)]//g' -e 's/ by "[^"]*"//g' > vm_version.out 2>&1 +echo "INT_VERSION=`cat vm_version.out 2>&1`" VM_TYPE="unknown" grep "Server" vm_version.out > ${NULL} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java --- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java Thu Oct 22 11:13:08 2015 -0700 @@ -24,7 +24,7 @@ package sun.hotspot.tools.ctw; import sun.hotspot.WhiteBox; -import sun.misc.SharedSecrets; +import jdk.internal.misc.SharedSecrets; import sun.reflect.ConstantPool; import java.lang.reflect.Executable; diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/testlibrary/jdk/test/lib/FileInstaller.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/jdk/test/lib/FileInstaller.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.test.lib; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.BasicFileAttributes; + +/** + * Copy a resource: file or directory recursively, using relative path(src and dst) + * which are applied to test source directory(src) and current directory(dst) + */ +public class FileInstaller { + /** + * @param args source and destination + * @throws IOException if an I/O error occurs + */ + public static void main(String[] args) throws IOException { + if (args.length != 2) { + throw new IllegalArgumentException("Unexpected number of arguments for file copy"); + } + Path src = Paths.get(Utils.TEST_SRC, args[0]); + Path dst = Paths.get(args[1]); + if (src.toFile().exists()) { + if (src.toFile().isDirectory()) { + Files.walkFileTree(src, new CopyFileVisitor(src, dst)); + } else { + Path dstDir = dst.getParent(); + if (!dstDir.toFile().exists()) { + Files.createDirectories(dstDir); + } + Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING); + } + } else { + throw new IOException("Can't find source " + src); + } + } + + private static class CopyFileVisitor extends SimpleFileVisitor { + private final Path copyFrom; + private final Path copyTo; + + public CopyFileVisitor(Path copyFrom, Path copyTo) { + this.copyFrom = copyFrom; + this.copyTo = copyTo; + } + + @Override + public FileVisitResult preVisitDirectory(Path file, + BasicFileAttributes attrs) throws IOException { + Path relativePath = file.relativize(copyFrom); + Path destination = copyTo.resolve(relativePath); + if (!destination.toFile().exists()) { + Files.createDirectories(destination); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + if (!file.toFile().isFile()) { + return FileVisitResult.CONTINUE; + } + Path relativePath = copyFrom.relativize(file); + Path destination = copyTo.resolve(relativePath); + Files.copy(file, destination, StandardCopyOption.COPY_ATTRIBUTES); + return FileVisitResult.CONTINUE; + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/testlibrary/jdk/test/lib/Pair.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/jdk/test/lib/Pair.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.test.lib; + +import java.util.Objects; + +/** + * Pair - a two element tuple + * + * @param first type + * @param second type + */ +public class Pair { + public final F first; + public final S second; + + public Pair(F first, S second) { + this.first = first; + this.second = second; + } + + @Override + public String toString() { + return "(" + first + ":" + second + ")"; + } + + @Override + public boolean equals(Object other) { + if (other instanceof Pair) { + Pair otherPair = (Pair) other; + return Objects.equals(first, otherPair.first) && + Objects.equals(second, otherPair.second); + } + return false; + } + + @Override + public int hashCode() { + if (first == null) { + return (second == null) ? 0 : second.hashCode(); + } else if (second == null) { + return first.hashCode(); + } else { + return first.hashCode() * 17 + second.hashCode(); + } + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/testlibrary/jdk/test/lib/Triple.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/jdk/test/lib/Triple.java Thu Oct 22 11:13:08 2015 -0700 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 jdk.test.lib; + +import java.util.Objects; + +/** + * Triple - a three element tuple + * + * @param first element type + * @param second element type + * @param third element type + */ +public class Triple { + private final Pair> container; + + /** + * Constructor + * + * @param first first element of the triple + * @param second second element of the triple + * @param third third element of the triple + */ + public Triple(F first, S second, T third) { + container = new Pair<>(first, new Pair<>(second, third)); + } + + /** + * Gets first element of the triple + */ + public F getFirst() { + return container.first; + } + + /** + * Gets second element of the triple + */ + public S getSecond() { + return container.second.first; + } + + /** + * Gets third element of the triple + */ + public T getThird() { + return container.second.second; + } + + @Override + public int hashCode() { + return container.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Triple) { + Triple objTriple = (Triple) obj; + return Objects.equals(container.first, objTriple.container.first) + && Objects.equals(container.second, + objTriple.container.second); + } + return false; + } + + @Override + public String toString() { + return "(" + getFirst() + " : " + getSecond() + " : " + getThird() + ")"; + } +} diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/testlibrary/jdk/test/lib/Utils.java --- a/hotspot/test/testlibrary/jdk/test/lib/Utils.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/testlibrary/jdk/test/lib/Utils.java Thu Oct 22 11:13:08 2015 -0700 @@ -23,25 +23,31 @@ package jdk.test.lib; +import java.io.File; import static jdk.test.lib.Asserts.assertTrue; import java.io.IOException; import java.lang.reflect.Field; import java.net.InetAddress; +import java.net.MalformedURLException; import java.net.ServerSocket; +import java.net.URL; +import java.net.URLClassLoader; import java.net.UnknownHostException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.function.BooleanSupplier; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import sun.misc.Unsafe; /** @@ -50,6 +56,11 @@ public final class Utils { /** + * Returns the value of 'test.class.path' system property. + */ + public static final String TEST_CLASS_PATH = System.getProperty("test.class.path", "."); + + /** * Returns the sequence used by operating system to separate lines. */ public static final String NEW_LINE = System.getProperty("line.separator"); @@ -64,6 +75,11 @@ */ public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); + /** + * Returns the value of 'test.src' system property. + */ + public static final String TEST_SRC = System.getProperty("test.src", "").trim(); + private static Unsafe unsafe = null; /** @@ -374,6 +390,28 @@ } /** + * Returns random element of non empty collection + * + * @param a type of collection element + * @param collection collection of elements + * @return random element of collection + * @throws IllegalArgumentException if collection is empty + */ + public static T getRandomElement(Collection collection) + throws IllegalArgumentException { + if (collection.isEmpty()) { + throw new IllegalArgumentException("Empty collection"); + } + Random random = getRandomInstance(); + int elementIndex = 1 + random.nextInt(collection.size() - 1); + Iterator iterator = collection.iterator(); + while (--elementIndex != 0) { + iterator.next(); + } + return iterator.next(); + } + + /** * Wait for condition to be true * * @param condition, a condition to wait for @@ -430,26 +468,114 @@ } /** + * Ensures a requested class is loaded + * @param aClass class to load + */ + public static void ensureClassIsLoaded(Class aClass) { + if (aClass == null) { + throw new Error("Requested null class"); + } + try { + Class.forName(aClass.getName(), /* initialize = */ true, + ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException e) { + throw new Error("Class not found", e); + } + } + /** + * @param parent a class loader to be the parent for the returned one + * @return an UrlClassLoader with urls made of the 'test.class.path' jtreg + * property and with the given parent + */ + public static URLClassLoader getTestClassPathURLClassLoader(ClassLoader parent) { + URL[] urls = Arrays.stream(TEST_CLASS_PATH.split(File.pathSeparator)) + .map(Paths::get) + .map(Path::toUri) + .map(x -> { + try { + return x.toURL(); + } catch (MalformedURLException ex) { + throw new Error("Test issue. JTREG property" + + " 'test.class.path'" + + " is not defined correctly", ex); + } + }).toArray(URL[]::new); + return new URLClassLoader(urls, parent); + } + + /** * Runs runnable and checks that it throws expected exception. If exceptionException is null it means * that we expect no exception to be thrown. * @param runnable what we run * @param expectedException expected exception */ public static void runAndCheckException(Runnable runnable, Class expectedException) { + runAndCheckException(runnable, t -> { + if (t == null) { + if (expectedException != null) { + throw new AssertionError("Didn't get expected exception " + expectedException.getSimpleName()); + } + } else { + String message = "Got unexpected exception " + t.getClass().getSimpleName(); + if (expectedException == null) { + throw new AssertionError(message, t); + } else if (!expectedException.isAssignableFrom(t.getClass())) { + message += " instead of " + expectedException.getSimpleName(); + throw new AssertionError(message, t); + } + } + }); + } + + /** + * Runs runnable and makes some checks to ensure that it throws expected exception. + * @param runnable what we run + * @param checkException a consumer which checks that we got expected exception and raises a new exception otherwise + */ + public static void runAndCheckException(Runnable runnable, Consumer checkException) { try { runnable.run(); - if (expectedException != null) { - throw new AssertionError("Didn't get expected exception " + expectedException.getSimpleName()); - } + checkException.accept(null); } catch (Throwable t) { - if (expectedException == null) { - throw new AssertionError("Got unexpected exception ", t); - } - if (!expectedException.isAssignableFrom(t.getClass())) { - throw new AssertionError(String.format("Got unexpected exception %s instead of %s", - t.getClass().getSimpleName(), expectedException.getSimpleName()), t); - } + checkException.accept(t); } } + /** + * Converts to VM type signature + * + * @param type Java type to convert + * @return string representation of VM type + */ + public static String toJVMTypeSignature(Class type) { + if (type.isPrimitive()) { + if (type == boolean.class) { + return "Z"; + } else if (type == byte.class) { + return "B"; + } else if (type == char.class) { + return "C"; + } else if (type == double.class) { + return "D"; + } else if (type == float.class) { + return "F"; + } else if (type == int.class) { + return "I"; + } else if (type == long.class) { + return "J"; + } else if (type == short.class) { + return "S"; + } else if (type == void.class) { + return "V"; + } else { + throw new Error("Unsupported type: " + type); + } + } + String result = type.getName().replaceAll("\\.", "/"); + if (!type.isArray()) { + return "L" + result + ";"; + } + return result; + } } + diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/DoubleTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -36,9 +36,7 @@ public class DoubleTest { private static final String FLAG_NAME = "CompileThresholdScaling"; - private static final Double[] TESTS = {0d, -0d, -1d, 1d, - Double.MAX_VALUE, Double.MIN_VALUE, Double.NaN, - Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}; + private static final Double[] TESTS = {0d, -0d, 1d, Double.MAX_VALUE}; public static void main(String[] args) throws Exception { VmFlagTest.runTest(FLAG_NAME, TESTS, diff -r 5e522d8ea16c -r 643e2fbeccc3 hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java Thu Oct 22 08:47:43 2015 -0700 +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java Thu Oct 22 11:13:08 2015 -0700 @@ -29,7 +29,7 @@ * @build IntxTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI IntxTest + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-ProfileInterpreter IntxTest * @summary testing of WB::set/getIntxVMFlag() * @author igor.ignatyev@oracle.com */ @@ -37,8 +37,7 @@ public class IntxTest { private static final String FLAG_NAME = "OnStackReplacePercentage"; private static final String FLAG_DEBUG_NAME = "InlineFrequencyCount"; - private static final Long[] TESTS = {0L, 100L, -1L, - (long) Integer.MAX_VALUE, (long) Integer.MIN_VALUE}; + private static final Long[] TESTS = {0L, 100L, (long) Integer.MAX_VALUE}; public static void main(String[] args) throws Exception { VmFlagTest.runTest(FLAG_NAME, TESTS,