Merge
This commit is contained in:
commit
1c350e9d11
@ -112,7 +112,9 @@ static jmethodID setThreadIntegerRegisterSet_ID = 0;
|
||||
return;}
|
||||
|
||||
static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) {
|
||||
env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
|
||||
jclass clazz = env->FindClass("sun/jvm/hotspot/debugger/DebuggerException");
|
||||
CHECK_EXCEPTION;
|
||||
env->ThrowNew(clazz, errMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -310,15 +312,18 @@ static bool getWindbgInterfaces(JNIEnv* env, jobject obj) {
|
||||
static bool setImageAndSymbolPath(JNIEnv* env, jobject obj) {
|
||||
jboolean isCopy;
|
||||
jclass clazz = env->GetObjectClass(obj);
|
||||
CHECK_EXCEPTION_(false);
|
||||
jstring path;
|
||||
const char* buf;
|
||||
|
||||
path = (jstring) env->GetStaticObjectField(clazz, imagePath_ID);
|
||||
CHECK_EXCEPTION_(false);
|
||||
buf = env->GetStringUTFChars(path, &isCopy);
|
||||
CHECK_EXCEPTION_(false);
|
||||
AutoJavaString imagePath(env, path, buf);
|
||||
|
||||
path = (jstring) env->GetStaticObjectField(clazz, symbolPath_ID);
|
||||
CHECK_EXCEPTION_(false);
|
||||
buf = env->GetStringUTFChars(path, &isCopy);
|
||||
CHECK_EXCEPTION_(false);
|
||||
AutoJavaString symbolPath(env, path, buf);
|
||||
|
@ -95,6 +95,7 @@ MINIMAL1_VM_TARGETS=productminimal1 fastdebugminimal1 debugminimal1
|
||||
COMMON_VM_PRODUCT_TARGETS=product product1 docs export_product
|
||||
COMMON_VM_FASTDEBUG_TARGETS=fastdebug fastdebug1 docs export_fastdebug
|
||||
COMMON_VM_DEBUG_TARGETS=debug debug1 docs export_debug
|
||||
COMMON_VM_OPTIMIZED_TARGETS=optimized optimized1 docs export_optimized
|
||||
|
||||
# JDK directory list
|
||||
JDK_DIRS=bin include jre lib demo
|
||||
@ -111,20 +112,21 @@ ifdef BUILD_CLIENT_ONLY
|
||||
all_product: product1 docs export_product
|
||||
all_fastdebug: fastdebug1 docs export_fastdebug
|
||||
all_debug: debug1 docs export_debug
|
||||
all_optimized: optimized1 docs export_optimized
|
||||
else
|
||||
ifeq ($(MACOSX_UNIVERSAL),true)
|
||||
all_product: universal_product
|
||||
all_fastdebug: universal_fastdebug
|
||||
all_debug: universal_debug
|
||||
all_optimized: universal_optimized
|
||||
else
|
||||
all_product: $(COMMON_VM_PRODUCT_TARGETS)
|
||||
all_fastdebug: $(COMMON_VM_FASTDEBUG_TARGETS)
|
||||
all_debug: $(COMMON_VM_DEBUG_TARGETS)
|
||||
all_optimized: $(COMMON_VM_OPTIMIZED_TARGETS)
|
||||
endif
|
||||
endif
|
||||
|
||||
all_optimized: optimized optimized1 docs export_optimized
|
||||
|
||||
allzero: all_productzero all_fastdebugzero
|
||||
all_productzero: productzero docs export_product
|
||||
all_fastdebugzero: fastdebugzero docs export_fastdebug
|
||||
@ -890,3 +892,5 @@ include $(GAMMADIR)/make/jprt.gmk
|
||||
create_jdk copy_jdk update_jdk test_jdk \
|
||||
copy_product_jdk copy_fastdebug_jdk copy_debug_jdk \
|
||||
$(HS_ALT_MAKE)/Makefile.make remove_old_debuginfo
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -256,36 +256,36 @@ check_j2se_version:
|
||||
|
||||
$(SUBDIRS_TIERED): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=tiered
|
||||
+$(BUILDTREE) VARIANT=tiered
|
||||
|
||||
$(SUBDIRS_C2): $(BUILDTREE_MAKE)
|
||||
ifeq ($(FORCE_TIERED),1)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
|
||||
+$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
|
||||
else
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=compiler2
|
||||
+$(BUILDTREE) VARIANT=compiler2
|
||||
endif
|
||||
|
||||
$(SUBDIRS_C1): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=compiler1
|
||||
+$(BUILDTREE) VARIANT=compiler1
|
||||
|
||||
$(SUBDIRS_CORE): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=core
|
||||
+$(BUILDTREE) VARIANT=core
|
||||
|
||||
$(SUBDIRS_ZERO): $(BUILDTREE_MAKE) platform_zero
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH)
|
||||
+$(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH)
|
||||
|
||||
$(SUBDIRS_SHARK): $(BUILDTREE_MAKE) platform_zero
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH)
|
||||
+$(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH)
|
||||
|
||||
$(SUBDIRS_MINIMAL1): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=minimal1
|
||||
+$(BUILDTREE) VARIANT=minimal1
|
||||
|
||||
|
||||
platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in
|
||||
@ -379,3 +379,5 @@ include $(GAMMADIR)/make/cscope.make
|
||||
.PHONY: all compiler1 compiler2 core zero shark
|
||||
.PHONY: clean clean_compiler1 clean_compiler2 clean_core clean_zero clean_shark docs clean_docs
|
||||
.PHONY: checks check_os_version check_j2se_version
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -173,7 +173,7 @@ all: $(SUBMAKE_DIRS)
|
||||
# Run make in each subdirectory recursively.
|
||||
$(SUBMAKE_DIRS): $(SIMPLE_DIRS) FORCE
|
||||
$(QUIETLY) [ -d $@ ] || { mkdir -p $@; }
|
||||
$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F)
|
||||
+$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F)
|
||||
$(QUIETLY) touch $@
|
||||
|
||||
$(SIMPLE_DIRS):
|
||||
@ -364,3 +364,5 @@ sa.make: $(BUILDTREE_MAKE)
|
||||
FORCE:
|
||||
|
||||
.PHONY: all FORCE
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -69,7 +69,13 @@ AD_Files_If_Required = $(AD_Files_If_Required/$(TYPE))
|
||||
|
||||
# Wierd argument adjustment for "gnumake -j..."
|
||||
adjust-mflags = $(GENERATED)/adjust-mflags
|
||||
MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"`
|
||||
# If SPEC is set, it's from configure and it's already controlling concurrency
|
||||
# for us. Skip setting -j with HOTSPOT_BUILD_JOBS.
|
||||
ifeq ($(SPEC), )
|
||||
MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"`
|
||||
else
|
||||
MFLAGS-adjusted = -r $(MFLAGS)
|
||||
endif
|
||||
|
||||
|
||||
# default target: update lists, make vm
|
||||
@ -116,7 +122,7 @@ $(adjust-mflags): $(GAMMADIR)/make/$(Platform_os_family)/makefiles/adjust-mflags
|
||||
@+mv $@+ $@
|
||||
|
||||
the_vm: vm_build_preliminaries $(adjust-mflags)
|
||||
@$(UpdatePCH)
|
||||
+@$(UpdatePCH)
|
||||
@$(MAKE) -f vm.make $(MFLAGS-adjusted)
|
||||
|
||||
install gamma: the_vm
|
||||
@ -125,7 +131,7 @@ install gamma: the_vm
|
||||
# next rules support "make foo.[ois]"
|
||||
|
||||
%.o %.i %.s:
|
||||
$(UpdatePCH)
|
||||
+$(UpdatePCH)
|
||||
$(MAKE) -f vm.make $(MFLAGS) $@
|
||||
#$(MAKE) -f vm.make $@
|
||||
|
||||
@ -142,3 +148,5 @@ realclean:
|
||||
.PHONY: default vm_build_preliminaries
|
||||
.PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean
|
||||
.PHONY: checks check_os_version install
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -250,36 +250,36 @@ check_j2se_version:
|
||||
|
||||
$(SUBDIRS_TIERED): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=tiered
|
||||
+$(BUILDTREE) VARIANT=tiered
|
||||
|
||||
$(SUBDIRS_C2): $(BUILDTREE_MAKE)
|
||||
ifeq ($(FORCE_TIERED),1)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
|
||||
+$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
|
||||
else
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=compiler2
|
||||
+$(BUILDTREE) VARIANT=compiler2
|
||||
endif
|
||||
|
||||
$(SUBDIRS_C1): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=compiler1
|
||||
+$(BUILDTREE) VARIANT=compiler1
|
||||
|
||||
$(SUBDIRS_CORE): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=core
|
||||
+$(BUILDTREE) VARIANT=core
|
||||
|
||||
$(SUBDIRS_ZERO): $(BUILDTREE_MAKE) platform_zero
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH)
|
||||
+$(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH)
|
||||
|
||||
$(SUBDIRS_SHARK): $(BUILDTREE_MAKE) platform_zero
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH)
|
||||
+$(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH)
|
||||
|
||||
$(SUBDIRS_MINIMAL1): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=minimal1
|
||||
+$(BUILDTREE) VARIANT=minimal1
|
||||
|
||||
platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in
|
||||
$(SED) 's/@ZERO_ARCHDEF@/$(ZERO_ARCHDEF)/g;s/@ZERO_LIBARCH@/$(ZERO_LIBARCH)/g;' < $< > $@
|
||||
@ -392,3 +392,5 @@ include $(GAMMADIR)/make/cscope.make
|
||||
.PHONY: clean clean_compiler1 clean_compiler2 clean_core clean_zero clean_shark docs clean_docs
|
||||
.PHONY: checks check_os_version check_j2se_version
|
||||
.PHONY: $(HS_ALT_MAKE)/$(OSNAME)/Makefile.make
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -178,7 +178,7 @@ all: $(SUBMAKE_DIRS)
|
||||
# Run make in each subdirectory recursively.
|
||||
$(SUBMAKE_DIRS): $(SIMPLE_DIRS) FORCE
|
||||
$(QUIETLY) [ -d $@ ] || { mkdir -p $@; }
|
||||
$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F)
|
||||
+$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F)
|
||||
$(QUIETLY) touch $@
|
||||
|
||||
$(SIMPLE_DIRS):
|
||||
@ -378,3 +378,5 @@ dtrace.make: $(BUILDTREE_MAKE)
|
||||
FORCE:
|
||||
|
||||
.PHONY: all FORCE
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -69,7 +69,13 @@ AD_Files_If_Required = $(AD_Files_If_Required/$(TYPE))
|
||||
|
||||
# Wierd argument adjustment for "gnumake -j..."
|
||||
adjust-mflags = $(GENERATED)/adjust-mflags
|
||||
MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"`
|
||||
# If SPEC is set, it's from configure and it's already controlling concurrency
|
||||
# for us. Skip setting -j with HOTSPOT_BUILD_JOBS.
|
||||
ifeq ($(SPEC), )
|
||||
MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"`
|
||||
else
|
||||
MFLAGS-adjusted = -r $(MFLAGS)
|
||||
endif
|
||||
|
||||
|
||||
# default target: update lists, make vm
|
||||
@ -125,7 +131,7 @@ $(adjust-mflags): $(GAMMADIR)/make/$(Platform_os_family)/makefiles/adjust-mflags
|
||||
@+mv $@+ $@
|
||||
|
||||
the_vm: vm_build_preliminaries $(adjust-mflags)
|
||||
@$(UpdatePCH)
|
||||
+@$(UpdatePCH)
|
||||
@$(MAKE) -f vm.make $(MFLAGS-adjusted)
|
||||
|
||||
install : the_vm
|
||||
@ -134,7 +140,7 @@ install : the_vm
|
||||
# next rules support "make foo.[ois]"
|
||||
|
||||
%.o %.i %.s:
|
||||
$(UpdatePCH)
|
||||
+$(UpdatePCH)
|
||||
$(MAKE) -f vm.make $(MFLAGS) $@
|
||||
#$(MAKE) -f vm.make $@
|
||||
|
||||
@ -151,3 +157,5 @@ realclean:
|
||||
.PHONY: default vm_build_preliminaries
|
||||
.PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean
|
||||
.PHONY: checks check_os_version install
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -25,6 +25,8 @@
|
||||
# macosx universal builds
|
||||
universal_product:
|
||||
$(MAKE) MACOSX_UNIVERSAL=true all_product_universal
|
||||
universal_optimized:
|
||||
$(MAKE) MACOSX_UNIVERSAL=true all_optimized_universal
|
||||
universal_fastdebug:
|
||||
$(MAKE) MACOSX_UNIVERSAL=true all_fastdebug_universal
|
||||
universal_debug:
|
||||
@ -36,6 +38,10 @@ all_product_universal:
|
||||
# $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_PRODUCT_TARGETS)
|
||||
$(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_PRODUCT_TARGETS)
|
||||
$(QUIETLY) $(MAKE) BUILD_FLAVOR=product EXPORT_SUBDIR= universalize
|
||||
all_optimized_universal:
|
||||
# $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_OPTIMIZED_TARGETS)
|
||||
$(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_OPTIMIZED_TARGETS)
|
||||
$(QUIETLY) $(MAKE) BUILD_FLAVOR=optimized EXPORT_SUBDIR=/optimized universalize
|
||||
all_fastdebug_universal:
|
||||
# $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_FASTDEBUG_TARGETS)
|
||||
$(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_FASTDEBUG_TARGETS)
|
||||
@ -98,13 +104,15 @@ copy_universal:
|
||||
export_product_jdk::
|
||||
$(MAKE) EXPORT_SUBDIR= export_universal
|
||||
export_optimized_jdk::
|
||||
$(MAKE) EXPORT_SUBDIR= export_universal
|
||||
$(MAKE) EXPORT_SUBDIR=/optimized export_universal
|
||||
export_fastdebug_jdk::
|
||||
$(MAKE) EXPORT_SUBDIR=/fastdebug export_universal
|
||||
export_debug_jdk::
|
||||
$(MAKE) EXPORT_SUBDIR=/debug export_universal
|
||||
copy_product_jdk::
|
||||
$(MAKE) COPY_SUBDIR= copy_universal
|
||||
copy_optimized_jdk::
|
||||
$(MAKE) COPY_SUBDIR=/optimized copy_universal
|
||||
copy_fastdebug_jdk::
|
||||
$(MAKE) COPY_SUBDIR=/fastdebug copy_universal
|
||||
copy_debug_jdk::
|
||||
@ -112,5 +120,6 @@ copy_debug_jdk::
|
||||
|
||||
.PHONY: universal_product universal_fastdebug universal_debug \
|
||||
all_product_universal all_fastdebug_universal all_debug_universal \
|
||||
universal_optimized all_optimized_universal \
|
||||
universalize export_universal copy_universal \
|
||||
$(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST)
|
||||
|
@ -256,36 +256,36 @@ check_j2se_version:
|
||||
|
||||
$(SUBDIRS_TIERED): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=tiered
|
||||
+$(BUILDTREE) VARIANT=tiered
|
||||
|
||||
$(SUBDIRS_C2): $(BUILDTREE_MAKE)
|
||||
ifeq ($(FORCE_TIERED),1)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
|
||||
+$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
|
||||
else
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=compiler2
|
||||
+$(BUILDTREE) VARIANT=compiler2
|
||||
endif
|
||||
|
||||
$(SUBDIRS_C1): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=compiler1
|
||||
+$(BUILDTREE) VARIANT=compiler1
|
||||
|
||||
$(SUBDIRS_CORE): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=core
|
||||
+$(BUILDTREE) VARIANT=core
|
||||
|
||||
$(SUBDIRS_ZERO): $(BUILDTREE_MAKE) platform_zero
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH)
|
||||
+$(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH)
|
||||
|
||||
$(SUBDIRS_SHARK): $(BUILDTREE_MAKE) platform_zero
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH)
|
||||
+$(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH)
|
||||
|
||||
$(SUBDIRS_MINIMAL1): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=minimal1
|
||||
+$(BUILDTREE) VARIANT=minimal1
|
||||
|
||||
|
||||
platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in
|
||||
@ -399,3 +399,5 @@ include $(GAMMADIR)/make/cscope.make
|
||||
.PHONY: clean clean_compiler1 clean_compiler2 clean_core clean_zero clean_shark docs clean_docs
|
||||
.PHONY: checks check_os_version check_j2se_version
|
||||
.PHONY: $(HS_ALT_MAKE)/$(OSNAME)/Makefile.make
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -172,7 +172,7 @@ all: $(SUBMAKE_DIRS)
|
||||
# Run make in each subdirectory recursively.
|
||||
$(SUBMAKE_DIRS): $(SIMPLE_DIRS) FORCE
|
||||
$(QUIETLY) [ -d $@ ] || { mkdir -p $@; }
|
||||
$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F)
|
||||
+$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F)
|
||||
$(QUIETLY) touch $@
|
||||
|
||||
$(SIMPLE_DIRS):
|
||||
@ -377,3 +377,5 @@ dtrace.make: $(BUILDTREE_MAKE)
|
||||
FORCE:
|
||||
|
||||
.PHONY: all FORCE
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -69,7 +69,13 @@ AD_Files_If_Required = $(AD_Files_If_Required/$(TYPE))
|
||||
|
||||
# Wierd argument adjustment for "gnumake -j..."
|
||||
adjust-mflags = $(GENERATED)/adjust-mflags
|
||||
MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"`
|
||||
# If SPEC is set, it's from configure and it's already controlling concurrency
|
||||
# for us. Skip setting -j with HOTSPOT_BUILD_JOBS.
|
||||
ifeq ($(SPEC), )
|
||||
MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"`
|
||||
else
|
||||
MFLAGS-adjusted = -r $(MFLAGS)
|
||||
endif
|
||||
|
||||
|
||||
# default target: update lists, make vm
|
||||
@ -119,7 +125,7 @@ $(adjust-mflags): $(GAMMADIR)/make/$(Platform_os_family)/makefiles/adjust-mflags
|
||||
@+mv $@+ $@
|
||||
|
||||
the_vm: vm_build_preliminaries $(adjust-mflags)
|
||||
@$(UpdatePCH)
|
||||
+@$(UpdatePCH)
|
||||
@$(MAKE) -f vm.make $(MFLAGS-adjusted)
|
||||
|
||||
install: the_vm
|
||||
@ -128,7 +134,7 @@ install: the_vm
|
||||
# next rules support "make foo.[ois]"
|
||||
|
||||
%.o %.i %.s:
|
||||
$(UpdatePCH)
|
||||
+$(UpdatePCH)
|
||||
$(MAKE) -f vm.make $(MFLAGS) $@
|
||||
#$(MAKE) -f vm.make $@
|
||||
|
||||
@ -145,3 +151,5 @@ realclean:
|
||||
.PHONY: default vm_build_preliminaries
|
||||
.PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean
|
||||
.PHONY: checks check_os_version install
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -200,24 +200,24 @@ check_j2se_version:
|
||||
|
||||
$(SUBDIRS_TIERED): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=tiered
|
||||
+$(BUILDTREE) VARIANT=tiered
|
||||
|
||||
$(SUBDIRS_C2): $(BUILDTREE_MAKE)
|
||||
ifeq ($(FORCE_TIERED),1)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
|
||||
+$(BUILDTREE) VARIANT=tiered FORCE_TIERED=1
|
||||
else
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=compiler2
|
||||
+$(BUILDTREE) VARIANT=compiler2
|
||||
endif
|
||||
|
||||
$(SUBDIRS_C1): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=compiler1
|
||||
+$(BUILDTREE) VARIANT=compiler1
|
||||
|
||||
$(SUBDIRS_CORE): $(BUILDTREE_MAKE)
|
||||
$(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks
|
||||
$(BUILDTREE) VARIANT=core
|
||||
+$(BUILDTREE) VARIANT=core
|
||||
|
||||
# Define INSTALL=y at command line to automatically copy JVM into JAVA_HOME
|
||||
|
||||
@ -292,3 +292,5 @@ include $(GAMMADIR)/make/cscope.make
|
||||
.PHONY: all compiler1 compiler2 core
|
||||
.PHONY: clean clean_compiler1 clean_compiler2 clean_core docs clean_docs
|
||||
.PHONY: checks check_os_version check_j2se_version
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -165,7 +165,7 @@ all: $(SUBMAKE_DIRS)
|
||||
# Run make in each subdirectory recursively.
|
||||
$(SUBMAKE_DIRS): $(SIMPLE_DIRS) FORCE
|
||||
$(QUIETLY) [ -d $@ ] || { mkdir -p $@; }
|
||||
$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F)
|
||||
+$(QUIETLY) cd $@ && $(BUILDTREE) TARGET=$(@F)
|
||||
$(QUIETLY) touch $@
|
||||
|
||||
$(SIMPLE_DIRS):
|
||||
@ -364,3 +364,5 @@ dtrace.make: $(BUILDTREE_MAKE)
|
||||
FORCE:
|
||||
|
||||
.PHONY: all FORCE
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -62,7 +62,13 @@ AD_Files_If_Required = $(AD_Files_If_Required/$(TYPE))
|
||||
|
||||
# Wierd argument adjustment for "gnumake -j..."
|
||||
adjust-mflags = $(GENERATED)/adjust-mflags
|
||||
MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"`
|
||||
# If SPEC is set, it's from configure and it's already controlling concurrency
|
||||
# for us. Skip setting -j with HOTSPOT_BUILD_JOBS.
|
||||
ifeq ($(SPEC), )
|
||||
MFLAGS-adjusted = -r `$(adjust-mflags) "$(MFLAGS)" "$(HOTSPOT_BUILD_JOBS)"`
|
||||
else
|
||||
MFLAGS-adjusted = -r $(MFLAGS)
|
||||
endif
|
||||
|
||||
|
||||
# default target: update lists, make vm
|
||||
@ -136,3 +142,5 @@ realclean:
|
||||
.PHONY: default vm_build_preliminaries
|
||||
.PHONY: lists ad_stuff jvmti_stuff trace_stuff sa_stuff the_vm clean realclean
|
||||
.PHONY: checks check_os_version install
|
||||
|
||||
.NOTPARALLEL:
|
||||
|
@ -143,7 +143,7 @@ else
|
||||
LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle
|
||||
endif # sparcWorks
|
||||
|
||||
LIBS += -lkstat
|
||||
LIBS += -lkstat -lpicl
|
||||
|
||||
# By default, link the *.o into the library, not the executable.
|
||||
LINK_INTO$(LINK_INTO) = LIBJVM
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
int VM_Version::_features = VM_Version::unknown_m;
|
||||
const char* VM_Version::_features_str = "";
|
||||
unsigned int VM_Version::_L2_cache_line_size = 0;
|
||||
|
||||
void VM_Version::initialize() {
|
||||
_features = determine_features();
|
||||
@ -192,7 +193,7 @@ void VM_Version::initialize() {
|
||||
}
|
||||
|
||||
assert(BlockZeroingLowLimit > 0, "invalid value");
|
||||
if (has_block_zeroing()) {
|
||||
if (has_block_zeroing() && cache_line_size > 0) {
|
||||
if (FLAG_IS_DEFAULT(UseBlockZeroing)) {
|
||||
FLAG_SET_DEFAULT(UseBlockZeroing, true);
|
||||
}
|
||||
@ -202,7 +203,7 @@ void VM_Version::initialize() {
|
||||
}
|
||||
|
||||
assert(BlockCopyLowLimit > 0, "invalid value");
|
||||
if (has_block_zeroing()) { // has_blk_init() && is_T4(): core's local L2 cache
|
||||
if (has_block_zeroing() && cache_line_size > 0) { // has_blk_init() && is_T4(): core's local L2 cache
|
||||
if (FLAG_IS_DEFAULT(UseBlockCopy)) {
|
||||
FLAG_SET_DEFAULT(UseBlockCopy, true);
|
||||
}
|
||||
@ -252,49 +253,6 @@ void VM_Version::initialize() {
|
||||
// buf is started with ", " or is empty
|
||||
_features_str = os::strdup(strlen(buf) > 2 ? buf + 2 : buf);
|
||||
|
||||
// There are three 64-bit SPARC families that do not overlap, e.g.,
|
||||
// both is_ultra3() and is_sparc64() cannot be true at the same time.
|
||||
// Within these families, there can be more than one chip, e.g.,
|
||||
// is_T4() and is_T7() machines are also is_niagara().
|
||||
if (is_ultra3()) {
|
||||
assert(_L1_data_cache_line_size == 0, "overlap with Ultra3 family");
|
||||
// Ref: UltraSPARC III Cu Processor
|
||||
_L1_data_cache_line_size = 64;
|
||||
}
|
||||
if (is_niagara()) {
|
||||
assert(_L1_data_cache_line_size == 0, "overlap with niagara family");
|
||||
// All Niagara's are sun4v's, but not all sun4v's are Niagaras, e.g.,
|
||||
// Fujitsu SPARC64 is sun4v, but we don't want it in this block.
|
||||
//
|
||||
// Ref: UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
|
||||
// Appendix F.1.3.1 Cacheable Accesses
|
||||
// -> 16-byte L1 cache line size
|
||||
//
|
||||
// Ref: UltraSPARC T2: A Highly-Threaded, Power-Efficient, SPARC SOC
|
||||
// Section III: SPARC Processor Core
|
||||
// -> 16-byte L1 cache line size
|
||||
//
|
||||
// Ref: Oracle's SPARC T4-1, SPARC T4-2, SPARC T4-4, and SPARC T4-1B Server Architecture
|
||||
// Section SPARC T4 Processor Cache Architecture
|
||||
// -> 32-byte L1 cache line size (no longer see that info on this ref)
|
||||
//
|
||||
// XXX - still need a T7 reference here
|
||||
//
|
||||
if (is_T7()) { // T7 or newer
|
||||
_L1_data_cache_line_size = 64;
|
||||
} else if (is_T4()) { // T4 or newer (until T7)
|
||||
_L1_data_cache_line_size = 32;
|
||||
} else { // T1 or newer (until T4)
|
||||
_L1_data_cache_line_size = 16;
|
||||
}
|
||||
}
|
||||
if (is_sparc64()) {
|
||||
guarantee(_L1_data_cache_line_size == 0, "overlap with SPARC64 family");
|
||||
// Ref: Fujitsu SPARC64 VII Processor
|
||||
// Section 4 Cache System
|
||||
_L1_data_cache_line_size = 64;
|
||||
}
|
||||
|
||||
// UseVIS is set to the smallest of what hardware supports and what
|
||||
// the command line requires. I.e., you cannot set UseVIS to 3 on
|
||||
// older UltraSparc which do not support it.
|
||||
@ -401,6 +359,7 @@ void VM_Version::initialize() {
|
||||
#ifndef PRODUCT
|
||||
if (PrintMiscellaneous && Verbose) {
|
||||
tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size());
|
||||
tty->print_cr("L2 cache line size: %u", L2_cache_line_size());
|
||||
tty->print("Allocation");
|
||||
if (AllocatePrefetchStyle <= 0) {
|
||||
tty->print_cr(": no prefetching");
|
||||
|
@ -96,6 +96,9 @@ protected:
|
||||
static int _features;
|
||||
static const char* _features_str;
|
||||
|
||||
static unsigned int _L2_cache_line_size;
|
||||
static unsigned int L2_cache_line_size() { return _L2_cache_line_size; }
|
||||
|
||||
static void print_features();
|
||||
static int determine_features();
|
||||
static int platform_features(int features);
|
||||
@ -167,9 +170,8 @@ public:
|
||||
|
||||
static const char* cpu_features() { return _features_str; }
|
||||
|
||||
static intx prefetch_data_size() {
|
||||
return is_T4() && !is_T7() ? 32 : 64; // default prefetch block size on sparc
|
||||
}
|
||||
// default prefetch block size on sparc
|
||||
static intx prefetch_data_size() { return L2_cache_line_size(); }
|
||||
|
||||
// Prefetch
|
||||
static intx prefetch_copy_interval_in_bytes() {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define CPU_X86_VM_ASSEMBLER_X86_HPP
|
||||
|
||||
#include "asm/register.hpp"
|
||||
#include "vm_version_x86.hpp"
|
||||
|
||||
class BiasedLockingCounters;
|
||||
|
||||
@ -1292,14 +1293,34 @@ private:
|
||||
if (order_constraint & StoreLoad) {
|
||||
// All usable chips support "locked" instructions which suffice
|
||||
// as barriers, and are much faster than the alternative of
|
||||
// using cpuid instruction. We use here a locked add [esp],0.
|
||||
// using cpuid instruction. We use here a locked add [esp-C],0.
|
||||
// This is conveniently otherwise a no-op except for blowing
|
||||
// flags.
|
||||
// flags, and introducing a false dependency on target memory
|
||||
// location. We can't do anything with flags, but we can avoid
|
||||
// memory dependencies in the current method by locked-adding
|
||||
// somewhere else on the stack. Doing [esp+C] will collide with
|
||||
// something on stack in current method, hence we go for [esp-C].
|
||||
// It is convenient since it is almost always in data cache, for
|
||||
// any small C. We need to step back from SP to avoid data
|
||||
// dependencies with other things on below SP (callee-saves, for
|
||||
// example). Without a clear way to figure out the minimal safe
|
||||
// distance from SP, it makes sense to step back the complete
|
||||
// cache line, as this will also avoid possible second-order effects
|
||||
// with locked ops against the cache line. Our choice of offset
|
||||
// is bounded by x86 operand encoding, which should stay within
|
||||
// [-128; +127] to have the 8-byte displacement encoding.
|
||||
//
|
||||
// Any change to this code may need to revisit other places in
|
||||
// the code where this idiom is used, in particular the
|
||||
// orderAccess code.
|
||||
|
||||
int offset = -VM_Version::L1_line_size();
|
||||
if (offset < -128) {
|
||||
offset = -128;
|
||||
}
|
||||
|
||||
lock();
|
||||
addl(Address(rsp, 0), 0);// Assert the lock# signal here
|
||||
addl(Address(rsp, offset), 0);// Assert the lock# signal here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -820,14 +820,10 @@ address InterpreterGenerator::generate_Reference_get_entry(void) {
|
||||
}
|
||||
|
||||
address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
assert(synchronized == false, "should be");
|
||||
|
||||
return generate_entry((address) CppInterpreter::native_entry);
|
||||
}
|
||||
|
||||
address InterpreterGenerator::generate_normal_entry(bool synchronized) {
|
||||
assert(synchronized == false, "should be");
|
||||
|
||||
return generate_entry((address) CppInterpreter::normal_entry);
|
||||
}
|
||||
|
||||
|
@ -1644,8 +1644,20 @@ static bool _print_ascii_file(const char* filename, outputStream* st) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) {
|
||||
outputStream * out = (outputStream *) param;
|
||||
out->print_cr(PTR_FORMAT " \t%s", base_address, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os::print_dll_info(outputStream *st) {
|
||||
st->print_cr("Dynamic libraries:");
|
||||
if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
}
|
||||
}
|
||||
|
||||
int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) {
|
||||
#ifdef RTLD_DI_LINKMAP
|
||||
Dl_info dli;
|
||||
void *handle;
|
||||
@ -1654,36 +1666,41 @@ void os::print_dll_info(outputStream *st) {
|
||||
|
||||
if (dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli) == 0 ||
|
||||
dli.dli_fname == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
handle = dlopen(dli.dli_fname, RTLD_LAZY);
|
||||
if (handle == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
dlinfo(handle, RTLD_DI_LINKMAP, &map);
|
||||
if (map == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
dlclose(handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (map->l_prev != NULL)
|
||||
map = map->l_prev;
|
||||
|
||||
while (map != NULL) {
|
||||
st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name);
|
||||
// Value for top_address is returned as 0 since we don't have any information about module size
|
||||
if (callback(map->l_name, (address)map->l_addr, (address)0, param)) {
|
||||
dlclose(handle);
|
||||
return 1;
|
||||
}
|
||||
map = map->l_next;
|
||||
}
|
||||
|
||||
dlclose(handle);
|
||||
#elif defined(__APPLE__)
|
||||
for (uint32_t i = 1; i < _dyld_image_count(); i++) {
|
||||
st->print_cr(PTR_FORMAT " \t%s", _dyld_get_image_header(i),
|
||||
_dyld_get_image_name(i));
|
||||
// Value for top_address is returned as 0 since we don't have any information about module size
|
||||
if (callback(_dyld_get_image_name(i), (address)_dyld_get_image_header(i), (address)0, param)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -2120,6 +2120,40 @@ void os::print_dll_info(outputStream *st) {
|
||||
}
|
||||
}
|
||||
|
||||
int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) {
|
||||
FILE *procmapsFile = NULL;
|
||||
|
||||
// Open the procfs maps file for the current process
|
||||
if ((procmapsFile = fopen("/proc/self/maps", "r")) != NULL) {
|
||||
// Allocate PATH_MAX for file name plus a reasonable size for other fields.
|
||||
char line[PATH_MAX + 100];
|
||||
|
||||
// Read line by line from 'file'
|
||||
while (fgets(line, sizeof(line), procmapsFile) != NULL) {
|
||||
u8 base, top, offset, inode;
|
||||
char permissions[5];
|
||||
char device[6];
|
||||
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);
|
||||
|
||||
// Filter by device id '00:00' so that we only get file system mapped files.
|
||||
if (strcmp(device, "00:00") != 0) {
|
||||
|
||||
// Call callback with the fields of interest
|
||||
if(callback(name, (address)base, (address)top, param)) {
|
||||
// Oops abort, callback aborted
|
||||
fclose(procmapsFile);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(procmapsFile);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os::print_os_info_brief(outputStream* st) {
|
||||
os::Linux::print_distro_info(st);
|
||||
|
||||
|
@ -215,6 +215,9 @@ void os::Posix::print_uname_info(outputStream* st) {
|
||||
struct utsname name;
|
||||
uname(&name);
|
||||
st->print("%s ", name.sysname);
|
||||
#ifdef ASSERT
|
||||
st->print("%s ", name.nodename);
|
||||
#endif
|
||||
st->print("%s ", name.release);
|
||||
st->print("%s ", name.version);
|
||||
st->print("%s", name.machine);
|
||||
|
@ -1722,41 +1722,54 @@ bool os::dll_address_to_library_name(address addr, char* buf,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prints the names and full paths of all opened dynamic libraries
|
||||
// for current process
|
||||
void os::print_dll_info(outputStream * st) {
|
||||
int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) {
|
||||
Dl_info dli;
|
||||
void *handle;
|
||||
Link_map *map;
|
||||
Link_map *p;
|
||||
|
||||
st->print_cr("Dynamic libraries:"); st->flush();
|
||||
|
||||
if (dladdr(CAST_FROM_FN_PTR(void *, os::print_dll_info), &dli) == 0 ||
|
||||
// Sanity check?
|
||||
if (dladdr(CAST_FROM_FN_PTR(void *, os::get_loaded_modules_info), &dli) == 0 ||
|
||||
dli.dli_fname == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
handle = dlopen(dli.dli_fname, RTLD_LAZY);
|
||||
|
||||
void * handle = dlopen(dli.dli_fname, RTLD_LAZY);
|
||||
if (handle == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Link_map *map;
|
||||
dlinfo(handle, RTLD_DI_LINKMAP, &map);
|
||||
if (map == NULL) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
return;
|
||||
dlclose(handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (map->l_prev != NULL)
|
||||
while (map->l_prev != NULL) {
|
||||
map = map->l_prev;
|
||||
}
|
||||
|
||||
while (map != NULL) {
|
||||
st->print_cr(PTR_FORMAT " \t%s", map->l_addr, map->l_name);
|
||||
// Iterate through all map entries and call callback with fields of interest
|
||||
if(callback(map->l_name, (address)map->l_addr, (address)0, param)) {
|
||||
dlclose(handle);
|
||||
return 1;
|
||||
}
|
||||
map = map->l_next;
|
||||
}
|
||||
|
||||
dlclose(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) {
|
||||
outputStream * out = (outputStream *) param;
|
||||
out->print_cr(PTR_FORMAT " \t%s", base_address, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void os::print_dll_info(outputStream * st) {
|
||||
st->print_cr("Dynamic libraries:"); st->flush();
|
||||
if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) {
|
||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||
}
|
||||
}
|
||||
|
||||
// Loads .dll/.so and
|
||||
|
@ -1301,120 +1301,6 @@ static bool _addr_in_ntdll( address addr )
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Enumerate all modules for a given process ID
|
||||
//
|
||||
// Notice that Windows 95/98/Me and Windows NT/2000/XP have
|
||||
// different API for doing this. We use PSAPI.DLL on NT based
|
||||
// Windows and ToolHelp on 95/98/Me.
|
||||
|
||||
// Callback function that is called by enumerate_modules() on
|
||||
// every DLL module.
|
||||
// Input parameters:
|
||||
// int pid,
|
||||
// char* module_file_name,
|
||||
// address module_base_addr,
|
||||
// unsigned module_size,
|
||||
// void* param
|
||||
typedef int (*EnumModulesCallbackFunc)(int, char *, address, unsigned, void *);
|
||||
|
||||
// enumerate_modules for Windows NT, using PSAPI
|
||||
static int _enumerate_modules_winnt( int pid, EnumModulesCallbackFunc func, void * param)
|
||||
{
|
||||
HANDLE hProcess;
|
||||
|
||||
# define MAX_NUM_MODULES 128
|
||||
HMODULE modules[MAX_NUM_MODULES];
|
||||
static char filename[MAX_PATH];
|
||||
int result = 0;
|
||||
|
||||
if (!os::PSApiDll::PSApiAvailable()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
||||
FALSE, pid);
|
||||
if (hProcess == NULL) return 0;
|
||||
|
||||
DWORD size_needed;
|
||||
if (!os::PSApiDll::EnumProcessModules(hProcess, modules,
|
||||
sizeof(modules), &size_needed)) {
|
||||
CloseHandle(hProcess);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// number of modules that are currently loaded
|
||||
int num_modules = size_needed / sizeof(HMODULE);
|
||||
|
||||
for (int i = 0; i < MIN2(num_modules, MAX_NUM_MODULES); i++) {
|
||||
// Get Full pathname:
|
||||
if (!os::PSApiDll::GetModuleFileNameEx(hProcess, modules[i],
|
||||
filename, sizeof(filename))) {
|
||||
filename[0] = '\0';
|
||||
}
|
||||
|
||||
MODULEINFO modinfo;
|
||||
if (!os::PSApiDll::GetModuleInformation(hProcess, modules[i],
|
||||
&modinfo, sizeof(modinfo))) {
|
||||
modinfo.lpBaseOfDll = NULL;
|
||||
modinfo.SizeOfImage = 0;
|
||||
}
|
||||
|
||||
// Invoke callback function
|
||||
result = func(pid, filename, (address)modinfo.lpBaseOfDll,
|
||||
modinfo.SizeOfImage, param);
|
||||
if (result) break;
|
||||
}
|
||||
|
||||
CloseHandle(hProcess);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// enumerate_modules for Windows 95/98/ME, using TOOLHELP
|
||||
static int _enumerate_modules_windows( int pid, EnumModulesCallbackFunc func, void *param)
|
||||
{
|
||||
HANDLE hSnapShot;
|
||||
static MODULEENTRY32 modentry;
|
||||
int result = 0;
|
||||
|
||||
if (!os::Kernel32Dll::HelpToolsAvailable()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get a handle to a Toolhelp snapshot of the system
|
||||
hSnapShot = os::Kernel32Dll::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
|
||||
if (hSnapShot == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// iterate through all modules
|
||||
modentry.dwSize = sizeof(MODULEENTRY32);
|
||||
bool not_done = os::Kernel32Dll::Module32First( hSnapShot, &modentry ) != 0;
|
||||
|
||||
while (not_done) {
|
||||
// invoke the callback
|
||||
result=func(pid, modentry.szExePath, (address)modentry.modBaseAddr,
|
||||
modentry.modBaseSize, param);
|
||||
if (result) break;
|
||||
|
||||
modentry.dwSize = sizeof(MODULEENTRY32);
|
||||
not_done = os::Kernel32Dll::Module32Next( hSnapShot, &modentry ) != 0;
|
||||
}
|
||||
|
||||
CloseHandle(hSnapShot);
|
||||
return result;
|
||||
}
|
||||
|
||||
int enumerate_modules( int pid, EnumModulesCallbackFunc func, void * param )
|
||||
{
|
||||
// Get current process ID if caller doesn't provide it.
|
||||
if (!pid) pid = os::current_process_id();
|
||||
|
||||
if (os::win32::is_nt()) return _enumerate_modules_winnt (pid, func, param);
|
||||
else return _enumerate_modules_windows(pid, func, param);
|
||||
}
|
||||
|
||||
struct _modinfo {
|
||||
address addr;
|
||||
char* full_path; // point to a char buffer
|
||||
@ -1422,13 +1308,13 @@ struct _modinfo {
|
||||
address base_addr;
|
||||
};
|
||||
|
||||
static int _locate_module_by_addr(int pid, char * mod_fname, address base_addr,
|
||||
unsigned size, void * param) {
|
||||
static int _locate_module_by_addr(const char * mod_fname, address base_addr,
|
||||
address top_address, void * param) {
|
||||
struct _modinfo *pmod = (struct _modinfo *)param;
|
||||
if (!pmod) return -1;
|
||||
|
||||
if (base_addr <= pmod->addr &&
|
||||
base_addr+size > pmod->addr) {
|
||||
if (base_addr <= pmod->addr &&
|
||||
top_address > pmod->addr) {
|
||||
// if a buffer is provided, copy path name to the buffer
|
||||
if (pmod->full_path) {
|
||||
jio_snprintf(pmod->full_path, pmod->buflen, "%s", mod_fname);
|
||||
@ -1453,8 +1339,7 @@ bool os::dll_address_to_library_name(address addr, char* buf,
|
||||
mi.addr = addr;
|
||||
mi.full_path = buf;
|
||||
mi.buflen = buflen;
|
||||
int pid = os::current_process_id();
|
||||
if (enumerate_modules(pid, _locate_module_by_addr, (void *)&mi)) {
|
||||
if (get_loaded_modules_info(_locate_module_by_addr, (void *)&mi)) {
|
||||
// buf already contains path name
|
||||
if (offset) *offset = addr - mi.base_addr;
|
||||
return true;
|
||||
@ -1479,14 +1364,14 @@ bool os::dll_address_to_function_name(address addr, char *buf,
|
||||
}
|
||||
|
||||
// save the start and end address of jvm.dll into param[0] and param[1]
|
||||
static int _locate_jvm_dll(int pid, char* mod_fname, address base_addr,
|
||||
unsigned size, void * param) {
|
||||
static int _locate_jvm_dll(const char* mod_fname, address base_addr,
|
||||
address top_address, void * param) {
|
||||
if (!param) return -1;
|
||||
|
||||
if (base_addr <= (address)_locate_jvm_dll &&
|
||||
base_addr+size > (address)_locate_jvm_dll) {
|
||||
if (base_addr <= (address)_locate_jvm_dll &&
|
||||
top_address > (address)_locate_jvm_dll) {
|
||||
((address*)param)[0] = base_addr;
|
||||
((address*)param)[1] = base_addr + size;
|
||||
((address*)param)[1] = top_address;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -1497,8 +1382,7 @@ address vm_lib_location[2]; // start and end address of jvm.dll
|
||||
// check if addr is inside jvm.dll
|
||||
bool os::address_is_in_vm(address addr) {
|
||||
if (!vm_lib_location[0] || !vm_lib_location[1]) {
|
||||
int pid = os::current_process_id();
|
||||
if (!enumerate_modules(pid, _locate_jvm_dll, (void *)vm_lib_location)) {
|
||||
if (!get_loaded_modules_info(_locate_jvm_dll, (void *)vm_lib_location)) {
|
||||
assert(false, "Can't find jvm module.");
|
||||
return false;
|
||||
}
|
||||
@ -1508,14 +1392,13 @@ bool os::address_is_in_vm(address addr) {
|
||||
}
|
||||
|
||||
// print module info; param is outputStream*
|
||||
static int _print_module(int pid, char* fname, address base,
|
||||
unsigned size, void* param) {
|
||||
static int _print_module(const char* fname, address base_address,
|
||||
address top_address, void* param) {
|
||||
if (!param) return -1;
|
||||
|
||||
outputStream* st = (outputStream*)param;
|
||||
|
||||
address end_addr = base + size;
|
||||
st->print(PTR_FORMAT " - " PTR_FORMAT " \t%s\n", base, end_addr, fname);
|
||||
st->print(PTR_FORMAT " - " PTR_FORMAT " \t%s\n", base_address, top_address, fname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1644,11 +1527,60 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void os::print_dll_info(outputStream *st) {
|
||||
int pid = os::current_process_id();
|
||||
st->print_cr("Dynamic libraries:");
|
||||
enumerate_modules(pid, _print_module, (void *)st);
|
||||
get_loaded_modules_info(_print_module, (void *)st);
|
||||
}
|
||||
|
||||
int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) {
|
||||
HANDLE hProcess;
|
||||
|
||||
# define MAX_NUM_MODULES 128
|
||||
HMODULE modules[MAX_NUM_MODULES];
|
||||
static char filename[MAX_PATH];
|
||||
int result = 0;
|
||||
|
||||
if (!os::PSApiDll::PSApiAvailable()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pid = os::current_process_id();
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
||||
FALSE, pid);
|
||||
if (hProcess == NULL) return 0;
|
||||
|
||||
DWORD size_needed;
|
||||
if (!os::PSApiDll::EnumProcessModules(hProcess, modules,
|
||||
sizeof(modules), &size_needed)) {
|
||||
CloseHandle(hProcess);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// number of modules that are currently loaded
|
||||
int num_modules = size_needed / sizeof(HMODULE);
|
||||
|
||||
for (int i = 0; i < MIN2(num_modules, MAX_NUM_MODULES); i++) {
|
||||
// Get Full pathname:
|
||||
if (!os::PSApiDll::GetModuleFileNameEx(hProcess, modules[i],
|
||||
filename, sizeof(filename))) {
|
||||
filename[0] = '\0';
|
||||
}
|
||||
|
||||
MODULEINFO modinfo;
|
||||
if (!os::PSApiDll::GetModuleInformation(hProcess, modules[i],
|
||||
&modinfo, sizeof(modinfo))) {
|
||||
modinfo.lpBaseOfDll = NULL;
|
||||
modinfo.SizeOfImage = 0;
|
||||
}
|
||||
|
||||
// Invoke callback function
|
||||
result = callback(filename, (address)modinfo.lpBaseOfDll,
|
||||
(address)((u8)modinfo.lpBaseOfDll + (u8)modinfo.SizeOfImage), param);
|
||||
if (result) break;
|
||||
}
|
||||
|
||||
CloseHandle(hProcess);
|
||||
return result;
|
||||
}
|
||||
|
||||
void os::print_os_info_brief(outputStream* st) {
|
||||
@ -1656,8 +1588,17 @@ void os::print_os_info_brief(outputStream* st) {
|
||||
}
|
||||
|
||||
void os::print_os_info(outputStream* st) {
|
||||
st->print("OS:");
|
||||
|
||||
#ifdef ASSERT
|
||||
char buffer[1024];
|
||||
DWORD size = sizeof(buffer);
|
||||
st->print(" HostName: ");
|
||||
if (GetComputerNameEx(ComputerNameDnsHostname, buffer, &size)) {
|
||||
st->print("%s", buffer);
|
||||
} else {
|
||||
st->print("N/A");
|
||||
}
|
||||
#endif
|
||||
st->print(" OS:");
|
||||
os::win32::print_windows_version(st);
|
||||
}
|
||||
|
||||
|
@ -563,3 +563,8 @@ void os::verify_stack_alignment() {
|
||||
assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment");
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// PPC does not require the additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -1030,3 +1030,8 @@ void os::setup_fpu() {
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// JDK-8050147 requires the full cache line bang for x86.
|
||||
return VM_Version::L1_line_size();
|
||||
}
|
||||
|
@ -465,3 +465,8 @@ extern "C" {
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// Zero does not require an additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -612,3 +612,8 @@ void os::verify_stack_alignment() {
|
||||
assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment");
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// PPC does not require the additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -752,3 +752,8 @@ size_t os::Linux::default_guard_size(os::ThreadType thr_type) {
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// SPARC does not require the additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -930,3 +930,8 @@ void os::workaround_expand_exec_shield_cs_limit() {
|
||||
// keep the page mapped so CS limit isn't reduced.
|
||||
#endif
|
||||
}
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// JDK-8050147 requires the full cache line bang for x86.
|
||||
return VM_Version::L1_line_size();
|
||||
}
|
||||
|
@ -495,3 +495,8 @@ extern "C" {
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// Zero does not require an additional stack banging.
|
||||
return 0;
|
||||
}
|
||||
|
@ -774,3 +774,8 @@ add_func_t* os::atomic_add_func = os::atomic_add_bootstrap;
|
||||
void os::verify_stack_alignment() {
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// SPARC does not require an additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
@ -28,10 +28,140 @@
|
||||
#include "runtime/os.hpp"
|
||||
#include "vm_version_sparc.hpp"
|
||||
|
||||
# include <sys/auxv.h>
|
||||
# include <sys/auxv_SPARC.h>
|
||||
# include <sys/systeminfo.h>
|
||||
# include <kstat.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/auxv_SPARC.h>
|
||||
#include <sys/systeminfo.h>
|
||||
#include <kstat.h>
|
||||
#include <picl.h>
|
||||
|
||||
extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result);
|
||||
extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result);
|
||||
|
||||
class PICL {
|
||||
// Get a value of the integer property. The value in the tree can be either 32 or 64 bit
|
||||
// depending on the platform. The result is converted to int.
|
||||
static int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) {
|
||||
picl_propinfo_t pinfo;
|
||||
picl_prophdl_t proph;
|
||||
if (picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS ||
|
||||
picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) {
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
|
||||
if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) {
|
||||
assert(false, "Invalid property type");
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
if (pinfo.size == sizeof(int64_t)) {
|
||||
int64_t val;
|
||||
if (picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) {
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
*result = static_cast<int>(val);
|
||||
} else if (pinfo.size == sizeof(int32_t)) {
|
||||
int32_t val;
|
||||
if (picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) {
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
*result = static_cast<int>(val);
|
||||
} else {
|
||||
assert(false, "Unexpected integer property size");
|
||||
return PICL_FAILURE;
|
||||
}
|
||||
return PICL_SUCCESS;
|
||||
}
|
||||
|
||||
// Visitor and a state machine that visits integer properties and verifies that the
|
||||
// values are the same. Stores the unique value observed.
|
||||
class UniqueValueVisitor {
|
||||
enum {
|
||||
INITIAL, // Start state, no assignments happened
|
||||
ASSIGNED, // Assigned a value
|
||||
INCONSISTENT // Inconsistent value seen
|
||||
} _state;
|
||||
int _value;
|
||||
public:
|
||||
UniqueValueVisitor() : _state(INITIAL) { }
|
||||
int value() {
|
||||
assert(_state == ASSIGNED, "Precondition");
|
||||
return _value;
|
||||
}
|
||||
void set_value(int value) {
|
||||
assert(_state == INITIAL, "Precondition");
|
||||
_value = value;
|
||||
_state = ASSIGNED;
|
||||
}
|
||||
bool is_initial() { return _state == INITIAL; }
|
||||
bool is_assigned() { return _state == ASSIGNED; }
|
||||
bool is_inconsistent() { return _state == INCONSISTENT; }
|
||||
void set_inconsistent() { _state = INCONSISTENT; }
|
||||
|
||||
static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) {
|
||||
UniqueValueVisitor *state = static_cast<UniqueValueVisitor*>(arg);
|
||||
assert(!state->is_inconsistent(), "Precondition");
|
||||
int curr;
|
||||
if (PICL::get_int_property(nodeh, name, &curr) == PICL_SUCCESS) {
|
||||
if (!state->is_assigned()) { // first iteration
|
||||
state->set_value(curr);
|
||||
} else if (curr != state->value()) { // following iterations
|
||||
state->set_inconsistent();
|
||||
}
|
||||
}
|
||||
if (state->is_inconsistent()) {
|
||||
return PICL_WALK_TERMINATE;
|
||||
}
|
||||
return PICL_WALK_CONTINUE;
|
||||
}
|
||||
};
|
||||
|
||||
int _L1_data_cache_line_size;
|
||||
int _L2_cache_line_size;
|
||||
public:
|
||||
static int get_l1_data_cache_line_size(picl_nodehdl_t nodeh, void *state) {
|
||||
return UniqueValueVisitor::visit(nodeh, "l1-dcache-line-size", state);
|
||||
}
|
||||
static int get_l2_cache_line_size(picl_nodehdl_t nodeh, void *state) {
|
||||
return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state);
|
||||
}
|
||||
|
||||
PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0) {
|
||||
if (picl_initialize() == PICL_SUCCESS) {
|
||||
picl_nodehdl_t rooth;
|
||||
if (picl_get_root(&rooth) == PICL_SUCCESS) {
|
||||
UniqueValueVisitor L1_state;
|
||||
// Visit all "cpu" class instances
|
||||
picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper);
|
||||
if (L1_state.is_initial()) { // Still initial, iteration found no values
|
||||
// Try walk all "core" class instances, it might be a Fujitsu machine
|
||||
picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper);
|
||||
}
|
||||
if (L1_state.is_assigned()) { // Is there a value?
|
||||
_L1_data_cache_line_size = L1_state.value();
|
||||
}
|
||||
|
||||
UniqueValueVisitor L2_state;
|
||||
picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper);
|
||||
if (L2_state.is_initial()) {
|
||||
picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper);
|
||||
}
|
||||
if (L2_state.is_assigned()) {
|
||||
_L2_cache_line_size = L2_state.value();
|
||||
}
|
||||
}
|
||||
picl_shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; }
|
||||
unsigned int L2_cache_line_size() const { return _L2_cache_line_size; }
|
||||
};
|
||||
|
||||
extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) {
|
||||
return PICL::get_l1_data_cache_line_size(nodeh, result);
|
||||
}
|
||||
extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) {
|
||||
return PICL::get_l2_cache_line_size(nodeh, result);
|
||||
}
|
||||
|
||||
// We need to keep these here as long as we have to build on Solaris
|
||||
// versions before 10.
|
||||
@ -211,5 +341,10 @@ int VM_Version::platform_features(int features) {
|
||||
kstat_close(kc);
|
||||
}
|
||||
|
||||
// Figure out cache line sizes using PICL
|
||||
PICL picl;
|
||||
_L1_data_cache_line_size = picl.L1_data_cache_line_size();
|
||||
_L2_cache_line_size = picl.L2_cache_line_size();
|
||||
|
||||
return features;
|
||||
}
|
||||
|
@ -918,3 +918,8 @@ void os::verify_stack_alignment() {
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// JDK-8050147 requires the full cache line bang for x86.
|
||||
return VM_Version::L1_line_size();
|
||||
}
|
||||
|
@ -639,3 +639,8 @@ void os::verify_stack_alignment() {
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int os::extra_bang_size_in_bytes() {
|
||||
// JDK-8050147 requires the full cache line bang for x86.
|
||||
return VM_Version::L1_line_size();
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ address LIR_Assembler::pc() const {
|
||||
// removes the need to bang the stack in the deoptimization blob which
|
||||
// in turn simplifies stack overflow handling.
|
||||
int LIR_Assembler::bang_size_in_bytes() const {
|
||||
return MAX2(initial_frame_size_in_bytes(), _compilation->interpreter_frame_size());
|
||||
return MAX2(initial_frame_size_in_bytes() + os::extra_bang_size_in_bytes(), _compilation->interpreter_frame_size());
|
||||
}
|
||||
|
||||
void LIR_Assembler::emit_exception_entries(ExceptionInfoList* info_list) {
|
||||
|
@ -926,7 +926,7 @@ void ciEnv::validate_compile_task_dependencies(ciMethod* target) {
|
||||
#ifdef ASSERT
|
||||
if (!counter_changed && !PrintCompilation) {
|
||||
// Print out the compile task that failed
|
||||
_task->print_line();
|
||||
_task->print_tty();
|
||||
}
|
||||
#endif
|
||||
assert(counter_changed, "failed dependencies, but counter didn't change");
|
||||
|
@ -1528,7 +1528,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
|
||||
if (TieredCompilation && TieredStopAtLevel >= CompLevel_full_optimization) {
|
||||
// Clobber the first compile and force second tier compilation
|
||||
nmethod* nm = m->code();
|
||||
if (nm != NULL) {
|
||||
if (nm != NULL && !m->is_method_handle_intrinsic()) {
|
||||
// Throw out the code so that the code cache doesn't fill up
|
||||
nm->make_not_entrant();
|
||||
m->clear_code();
|
||||
@ -1547,7 +1547,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
|
||||
}
|
||||
|
||||
nmethod* nm = m->code();
|
||||
if (nm != NULL) {
|
||||
if (nm != NULL && !m->is_method_handle_intrinsic()) {
|
||||
// Throw out the code so that the code cache doesn't fill up
|
||||
nm->make_not_entrant();
|
||||
m->clear_code();
|
||||
|
@ -746,7 +746,7 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
|
||||
// mark metadata seen on the stack and code cache so we can delete
|
||||
// unneeded entries.
|
||||
bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
|
||||
MetadataOnStackMark md_on_stack;
|
||||
MetadataOnStackMark md_on_stack(has_redefined_a_class);
|
||||
if (has_redefined_a_class) {
|
||||
// purge_previous_versions also cleans weak method links. Because
|
||||
// one method's MDO can reference another method from another
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -41,7 +41,7 @@ NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;)
|
||||
// Walk metadata on the stack and mark it so that redefinition doesn't delete
|
||||
// it. Class unloading also walks the previous versions and might try to
|
||||
// delete it, so this class is used by class unloading also.
|
||||
MetadataOnStackMark::MetadataOnStackMark() {
|
||||
MetadataOnStackMark::MetadataOnStackMark(bool has_redefined_a_class) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
|
||||
NOT_PRODUCT(_is_active = true;)
|
||||
if (_marked_objects == NULL) {
|
||||
@ -49,7 +49,7 @@ MetadataOnStackMark::MetadataOnStackMark() {
|
||||
}
|
||||
|
||||
Threads::metadata_do(Metadata::mark_on_stack);
|
||||
if (JvmtiExport::has_redefined_a_class()) {
|
||||
if (has_redefined_a_class) {
|
||||
CodeCache::alive_nmethods_do(nmethod::mark_on_stack);
|
||||
}
|
||||
CompileBroker::mark_on_stack();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -37,7 +37,7 @@ class Metadata;
|
||||
class MetadataOnStackMark : public StackObj {
|
||||
NOT_PRODUCT(static bool _is_active;)
|
||||
public:
|
||||
MetadataOnStackMark();
|
||||
MetadataOnStackMark(bool has_redefined_a_class);
|
||||
~MetadataOnStackMark();
|
||||
static void record(Metadata* m);
|
||||
};
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "oops/typeArrayKlass.hpp"
|
||||
#include "prims/jvmtiEnvBase.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
#include "runtime/fieldType.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
@ -2274,7 +2275,11 @@ methodHandle SystemDictionary::find_method_handle_intrinsic(vmIntrinsics::ID iid
|
||||
m = Method::make_method_handle_intrinsic(iid, signature, CHECK_(empty));
|
||||
CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_highest_tier,
|
||||
methodHandle(), CompileThreshold, "MH", CHECK_(empty));
|
||||
|
||||
// Check if we need to have compiled code but we don't.
|
||||
if (!Arguments::is_interpreter_only() && !m->has_compiled_code()) {
|
||||
THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(),
|
||||
"out of space in CodeCache for method handle intrinsic", empty);
|
||||
}
|
||||
// Now grab the lock. We might have to throw away the new method,
|
||||
// if a racing thread has managed to install one at the same time.
|
||||
{
|
||||
@ -2288,6 +2293,9 @@ methodHandle SystemDictionary::find_method_handle_intrinsic(vmIntrinsics::ID iid
|
||||
}
|
||||
|
||||
assert(spe != NULL && spe->method() != NULL, "");
|
||||
assert(Arguments::is_interpreter_only() || (spe->method()->has_compiled_code() &&
|
||||
spe->method()->code()->entry_point() == spe->method()->from_compiled_entry()),
|
||||
"MH intrinsic invariant");
|
||||
return spe->method();
|
||||
}
|
||||
|
||||
|
@ -249,6 +249,7 @@ void CodeCache::commit(CodeBlob* cb) {
|
||||
#define FOR_ALL_BLOBS(var) for (CodeBlob *var = first() ; var != NULL; var = next(var) )
|
||||
#define FOR_ALL_ALIVE_BLOBS(var) for (CodeBlob *var = alive(first()); var != NULL; var = alive(next(var)))
|
||||
#define FOR_ALL_ALIVE_NMETHODS(var) for (nmethod *var = alive_nmethod(first()); var != NULL; var = alive_nmethod(next(var)))
|
||||
#define FOR_ALL_NMETHODS(var) for (nmethod *var = first_nmethod(); var != NULL; var = next_nmethod(var))
|
||||
|
||||
|
||||
bool CodeCache::contains(void *p) {
|
||||
@ -687,7 +688,9 @@ int CodeCache::mark_for_evol_deoptimization(instanceKlassHandle dependee) {
|
||||
void CodeCache::mark_all_nmethods_for_deoptimization() {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
FOR_ALL_ALIVE_NMETHODS(nm) {
|
||||
nm->mark_for_deoptimization();
|
||||
if (!nm->method()->is_method_handle_intrinsic()) {
|
||||
nm->mark_for_deoptimization();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -967,6 +970,25 @@ void CodeCache::print_summary(outputStream* st, bool detailed) {
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCache::print_codelist(outputStream* st) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
|
||||
FOR_ALL_NMETHODS(p) {
|
||||
ResourceMark rm;
|
||||
char *method_name = p->method()->name_and_sig_as_C_string();
|
||||
st->print_cr("%d %d %s ["INTPTR_FORMAT", "INTPTR_FORMAT" - "INTPTR_FORMAT"]",
|
||||
p->compile_id(), p->comp_level(), method_name, (intptr_t)p->header_begin(),
|
||||
(intptr_t)p->code_begin(), (intptr_t)p->code_end());
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCache::print_layout(outputStream* st) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
ResourceMark rm;
|
||||
|
||||
print_summary(st, true);
|
||||
}
|
||||
|
||||
void CodeCache::log_state(outputStream* st) {
|
||||
st->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'"
|
||||
" adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
|
||||
|
@ -152,6 +152,10 @@ class CodeCache : AllStatic {
|
||||
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
|
||||
static void log_state(outputStream* st);
|
||||
|
||||
// Dcmd (Diagnostic commands)
|
||||
static void print_codelist(outputStream* st);
|
||||
static void print_layout(outputStream* st);
|
||||
|
||||
// The full limits of the codeCache
|
||||
static address low_bound() { return (address) _heap->low_boundary(); }
|
||||
static address high_bound() { return (address) _heap->high_boundary(); }
|
||||
|
@ -595,6 +595,7 @@ void CompiledStaticCall::compute_entry(methodHandle m, StaticCallInfo& info) {
|
||||
} else {
|
||||
// Callee is interpreted code. In any case entering the interpreter
|
||||
// puts a converter-frame on the stack to save arguments.
|
||||
assert(!m->is_method_handle_intrinsic(), "Compiled code should never call interpreter MH intrinsics");
|
||||
info._to_interpreter = true;
|
||||
info._entry = m()->get_c2i_entry();
|
||||
}
|
||||
|
@ -2062,7 +2062,7 @@ void nmethod::metadata_do(void f(Metadata*)) {
|
||||
"metadata must be found in exactly one place");
|
||||
if (r->metadata_is_immediate() && r->metadata_value() != NULL) {
|
||||
Metadata* md = r->metadata_value();
|
||||
f(md);
|
||||
if (md != _method) f(md);
|
||||
}
|
||||
} else if (iter.type() == relocInfo::virtual_call_type) {
|
||||
// Check compiledIC holders associated with this nmethod
|
||||
|
@ -448,7 +448,10 @@ class nmethod : public CodeBlob {
|
||||
// alive. It is used when an uncommon trap happens. Returns true
|
||||
// if this thread changed the state of the nmethod or false if
|
||||
// another thread performed the transition.
|
||||
bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); }
|
||||
bool make_not_entrant() {
|
||||
assert(!method()->is_method_handle_intrinsic(), "Cannot make MH intrinsic not entrant");
|
||||
return make_not_entrant_or_zombie(not_entrant);
|
||||
}
|
||||
bool make_zombie() { return make_not_entrant_or_zombie(zombie); }
|
||||
|
||||
// used by jvmti to track if the unload event has been reported
|
||||
|
@ -166,7 +166,7 @@ class CompilationLog : public StringEventLog {
|
||||
StringLogMessage lm;
|
||||
stringStream sstr = lm.stream();
|
||||
// msg.time_stamp().update_to(tty->time_stamp().ticks());
|
||||
task->print_compilation(&sstr, NULL, true);
|
||||
task->print_compilation(&sstr, NULL, true, false);
|
||||
log(thread, "%s", (const char*)lm);
|
||||
}
|
||||
|
||||
@ -328,7 +328,6 @@ void CompileTask::set_code(nmethod* nm) {
|
||||
if (nm == NULL) _code_handle = NULL; // drop the handle also
|
||||
}
|
||||
|
||||
|
||||
void CompileTask::mark_on_stack() {
|
||||
// Mark these methods as something redefine classes cannot remove.
|
||||
_method->set_on_stack(true);
|
||||
@ -337,18 +336,6 @@ void CompileTask::mark_on_stack() {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print
|
||||
void CompileTask::print() {
|
||||
tty->print("<CompileTask compile_id=%d ", _compile_id);
|
||||
tty->print("method=");
|
||||
_method->print_name(tty);
|
||||
tty->print_cr(" osr_bci=%d is_blocking=%s is_complete=%s is_success=%s>",
|
||||
_osr_bci, bool_to_str(_is_blocking),
|
||||
bool_to_str(_is_complete), bool_to_str(_is_success));
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print_line_on_error
|
||||
//
|
||||
@ -367,19 +354,18 @@ void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) {
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print_line
|
||||
void CompileTask::print_line() {
|
||||
void CompileTask::print_tty() {
|
||||
ttyLocker ttyl; // keep the following output all in one block
|
||||
// print compiler name if requested
|
||||
if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level()));
|
||||
print_compilation();
|
||||
print_compilation(tty);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print_compilation_impl
|
||||
void CompileTask::print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
|
||||
bool is_osr_method, int osr_bci, bool is_blocking,
|
||||
const char* msg, bool short_form) {
|
||||
const char* msg, bool short_form, bool cr) {
|
||||
if (!short_form) {
|
||||
st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp
|
||||
}
|
||||
@ -428,7 +414,7 @@ void CompileTask::print_compilation_impl(outputStream* st, Method* method, int c
|
||||
if (msg != NULL) {
|
||||
st->print(" %s", msg);
|
||||
}
|
||||
if (!short_form) {
|
||||
if (cr) {
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
@ -494,9 +480,9 @@ void CompileTask::print_inline_indent(int inline_level, outputStream* st) {
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileTask::print_compilation
|
||||
void CompileTask::print_compilation(outputStream* st, const char* msg, bool short_form) {
|
||||
void CompileTask::print_compilation(outputStream* st, const char* msg, bool short_form, bool cr) {
|
||||
bool is_osr_method = osr_bci() != InvocationEntryBci;
|
||||
print_compilation_impl(st, method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form);
|
||||
print_compilation_impl(st, method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form, cr);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -621,7 +607,9 @@ void CompileQueue::add(CompileTask* task) {
|
||||
// Mark the method as being in the compile queue.
|
||||
task->method()->set_queued_for_compilation();
|
||||
|
||||
NOT_PRODUCT(print();)
|
||||
if (CIPrintCompileQueue) {
|
||||
print_tty();
|
||||
}
|
||||
|
||||
if (LogCompilation && xtty != NULL) {
|
||||
task->log_task_queued();
|
||||
@ -786,24 +774,40 @@ void CompileQueue::mark_on_stack() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
/**
|
||||
* Print entire compilation queue.
|
||||
*/
|
||||
void CompileQueue::print() {
|
||||
if (CIPrintCompileQueue) {
|
||||
ttyLocker ttyl;
|
||||
tty->print_cr("Contents of %s", name());
|
||||
tty->print_cr("----------------------");
|
||||
CompileTask* task = _first;
|
||||
|
||||
CompileQueue* CompileBroker::compile_queue(int comp_level) {
|
||||
if (is_c2_compile(comp_level)) return _c2_compile_queue;
|
||||
if (is_c1_compile(comp_level)) return _c1_compile_queue;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void CompileBroker::print_compile_queues(outputStream* st) {
|
||||
_c1_compile_queue->print(st);
|
||||
_c2_compile_queue->print(st);
|
||||
}
|
||||
|
||||
|
||||
void CompileQueue::print(outputStream* st) {
|
||||
assert_locked_or_safepoint(lock());
|
||||
st->print_cr("Contents of %s", name());
|
||||
st->print_cr("----------------------------");
|
||||
CompileTask* task = _first;
|
||||
if (task == NULL) {
|
||||
st->print_cr("Empty");;
|
||||
} else {
|
||||
while (task != NULL) {
|
||||
task->print_line();
|
||||
task->print_compilation(st, NULL, true, true);
|
||||
task = task->next();
|
||||
}
|
||||
tty->print_cr("----------------------");
|
||||
}
|
||||
st->print_cr("----------------------------");
|
||||
}
|
||||
|
||||
void CompileQueue::print_tty() {
|
||||
ttyLocker ttyl;
|
||||
print(tty);
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) {
|
||||
|
||||
@ -1068,11 +1072,11 @@ void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler
|
||||
#endif // !ZERO && !SHARK
|
||||
// Initialize the compilation queue
|
||||
if (c2_compiler_count > 0) {
|
||||
_c2_compile_queue = new CompileQueue("C2 CompileQueue", MethodCompileQueue_lock);
|
||||
_c2_compile_queue = new CompileQueue("C2 compile queue", MethodCompileQueue_lock);
|
||||
_compilers[1]->set_num_compiler_threads(c2_compiler_count);
|
||||
}
|
||||
if (c1_compiler_count > 0) {
|
||||
_c1_compile_queue = new CompileQueue("C1 CompileQueue", MethodCompileQueue_lock);
|
||||
_c1_compile_queue = new CompileQueue("C1 compile queue", MethodCompileQueue_lock);
|
||||
_compilers[0]->set_num_compiler_threads(c1_compiler_count);
|
||||
}
|
||||
|
||||
@ -1892,7 +1896,7 @@ static void codecache_print(bool detailed)
|
||||
void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
||||
if (PrintCompilation) {
|
||||
ResourceMark rm;
|
||||
task->print_line();
|
||||
task->print_tty();
|
||||
}
|
||||
elapsedTimer time;
|
||||
|
||||
|
@ -111,14 +111,14 @@ class CompileTask : public CHeapObj<mtCompiler> {
|
||||
private:
|
||||
static void print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
|
||||
bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false,
|
||||
const char* msg = NULL, bool short_form = false);
|
||||
const char* msg = NULL, bool short_form = false, bool cr = true);
|
||||
|
||||
public:
|
||||
void print_compilation(outputStream* st = tty, const char* msg = NULL, bool short_form = false);
|
||||
static void print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false) {
|
||||
void print_compilation(outputStream* st = tty, const char* msg = NULL, bool short_form = false, bool cr = true);
|
||||
static void print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false, bool cr = true) {
|
||||
print_compilation_impl(st, nm->method(), nm->compile_id(), nm->comp_level(),
|
||||
nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false,
|
||||
msg, short_form);
|
||||
msg, short_form, cr);
|
||||
}
|
||||
|
||||
static void print_inlining(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg = NULL);
|
||||
@ -131,8 +131,7 @@ public:
|
||||
|
||||
static void print_inline_indent(int inline_level, outputStream* st = tty);
|
||||
|
||||
void print();
|
||||
void print_line();
|
||||
void print_tty();
|
||||
void print_line_on_error(outputStream* st, char* buf, int buflen);
|
||||
|
||||
void log_task(xmlStream* log);
|
||||
@ -234,7 +233,8 @@ class CompileQueue : public CHeapObj<mtCompiler> {
|
||||
// Redefine Classes support
|
||||
void mark_on_stack();
|
||||
void free_all();
|
||||
NOT_PRODUCT (void print();)
|
||||
void print_tty();
|
||||
void print(outputStream* st = tty);
|
||||
|
||||
~CompileQueue() {
|
||||
assert (is_empty(), " Compile Queue must be empty");
|
||||
@ -341,7 +341,7 @@ class CompileBroker: AllStatic {
|
||||
static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count);
|
||||
static bool compilation_is_complete (methodHandle method, int osr_bci, int comp_level);
|
||||
static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level);
|
||||
static bool is_compile_blocking ();
|
||||
static bool is_compile_blocking();
|
||||
static void preload_classes (methodHandle method, TRAPS);
|
||||
|
||||
static CompileTask* create_compile_task(CompileQueue* queue,
|
||||
@ -369,11 +369,8 @@ class CompileBroker: AllStatic {
|
||||
int hot_count,
|
||||
const char* comment,
|
||||
Thread* thread);
|
||||
static CompileQueue* compile_queue(int comp_level) {
|
||||
if (is_c2_compile(comp_level)) return _c2_compile_queue;
|
||||
if (is_c1_compile(comp_level)) return _c1_compile_queue;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CompileQueue* compile_queue(int comp_level);
|
||||
static bool init_compiler_runtime();
|
||||
static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread);
|
||||
|
||||
@ -390,6 +387,7 @@ class CompileBroker: AllStatic {
|
||||
}
|
||||
|
||||
static bool compilation_is_in_queue(methodHandle method);
|
||||
static void print_compile_queues(outputStream* st);
|
||||
static int queue_size(int comp_level) {
|
||||
CompileQueue *q = compile_queue(comp_level);
|
||||
return q != NULL ? q->size() : 0;
|
||||
|
@ -369,33 +369,45 @@ void G1BlockOffsetArray::alloc_block_work2(HeapWord** threshold_, size_t* index_
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
G1BlockOffsetArray::verify_for_object(HeapWord* obj_start,
|
||||
size_t word_size) const {
|
||||
size_t first_card = _array->index_for(obj_start);
|
||||
size_t last_card = _array->index_for(obj_start + word_size - 1);
|
||||
if (!_array->is_card_boundary(obj_start)) {
|
||||
// If the object is not on a card boundary the BOT entry of the
|
||||
// first card should point to another object so we should not
|
||||
// check that one.
|
||||
first_card += 1;
|
||||
}
|
||||
for (size_t card = first_card; card <= last_card; card += 1) {
|
||||
HeapWord* card_addr = _array->address_for_index(card);
|
||||
HeapWord* block_start = block_start_const(card_addr);
|
||||
if (block_start != obj_start) {
|
||||
gclog_or_tty->print_cr("block start: "PTR_FORMAT" is incorrect - "
|
||||
"card index: "SIZE_FORMAT" "
|
||||
"card addr: "PTR_FORMAT" BOT entry: %u "
|
||||
"obj: "PTR_FORMAT" word size: "SIZE_FORMAT" "
|
||||
"cards: ["SIZE_FORMAT","SIZE_FORMAT"]",
|
||||
p2i(block_start), card, p2i(card_addr),
|
||||
_array->offset_array(card),
|
||||
p2i(obj_start), word_size, first_card, last_card);
|
||||
return false;
|
||||
void G1BlockOffsetArray::verify() const {
|
||||
assert(gsp()->bottom() < gsp()->top(), "Only non-empty regions should be verified.");
|
||||
size_t start_card = _array->index_for(gsp()->bottom());
|
||||
size_t end_card = _array->index_for(gsp()->top() - 1);
|
||||
|
||||
for (size_t current_card = start_card; current_card < end_card; current_card++) {
|
||||
u_char entry = _array->offset_array(current_card);
|
||||
if (entry < N_words) {
|
||||
// The entry should point to an object before the current card. Verify that
|
||||
// it is possible to walk from that object in to the current card by just
|
||||
// iterating over the objects following it.
|
||||
HeapWord* card_address = _array->address_for_index(current_card);
|
||||
HeapWord* obj_end = card_address - entry;
|
||||
while (obj_end < card_address) {
|
||||
HeapWord* obj = obj_end;
|
||||
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())));
|
||||
}
|
||||
} else {
|
||||
// Because we refine the BOT based on which cards are dirty there is not much we can verify here.
|
||||
// We need to make sure that we are going backwards and that we don't pass the start of the
|
||||
// corresponding heap region. But that is about all we can verify.
|
||||
size_t backskip = BlockOffsetArray::entry_to_cards_back(entry);
|
||||
guarantee(backskip >= 1, "Must be going back at least one card.");
|
||||
|
||||
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));
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
@ -304,14 +304,10 @@ public:
|
||||
virtual HeapWord* block_start_unsafe(const void* addr);
|
||||
virtual HeapWord* block_start_unsafe_const(const void* addr) const;
|
||||
|
||||
// Used by region verification. Checks that the contents of the
|
||||
// BOT reflect that there's a single object that spans the address
|
||||
// range [obj_start, obj_start + word_size); returns true if this is
|
||||
// the case, returns false if it's not.
|
||||
bool verify_for_object(HeapWord* obj_start, size_t word_size) const;
|
||||
|
||||
void check_all_cards(size_t left_card, size_t right_card) const;
|
||||
|
||||
void verify() const;
|
||||
|
||||
virtual void print_on(outputStream* out) PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
|
@ -48,6 +48,7 @@ class CodeRootSetTable : public Hashtable<nmethod*, mtGC> {
|
||||
return hash ^ (hash >> 7); // code heap blocks are 128byte aligned
|
||||
}
|
||||
|
||||
void remove_entry(Entry* e, Entry* previous);
|
||||
Entry* new_entry(nmethod* nm);
|
||||
|
||||
public:
|
||||
@ -67,7 +68,7 @@ class CodeRootSetTable : public Hashtable<nmethod*, mtGC> {
|
||||
void nmethods_do(CodeBlobClosure* blk);
|
||||
|
||||
template<typename CB>
|
||||
void remove_if(CB& should_remove);
|
||||
int remove_if(CB& should_remove);
|
||||
|
||||
static void purge_list_append(CodeRootSetTable* tbl);
|
||||
static void purge();
|
||||
@ -91,6 +92,18 @@ CodeRootSetTable::Entry* CodeRootSetTable::new_entry(nmethod* nm) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
void CodeRootSetTable::remove_entry(Entry* e, Entry* previous) {
|
||||
int index = hash_to_index(e->hash());
|
||||
assert((e == bucket(index)) == (previous == NULL), "if e is the first entry then previous should be null");
|
||||
|
||||
if (previous == NULL) {
|
||||
set_entry(index, e->next());
|
||||
} else {
|
||||
previous->set_next(e->next());
|
||||
}
|
||||
free_entry(e);
|
||||
}
|
||||
|
||||
CodeRootSetTable::~CodeRootSetTable() {
|
||||
for (int index = 0; index < table_size(); ++index) {
|
||||
for (Entry* e = bucket(index); e != NULL; ) {
|
||||
@ -133,12 +146,7 @@ bool CodeRootSetTable::remove(nmethod* nm) {
|
||||
Entry* previous = NULL;
|
||||
for (Entry* e = bucket(index); e != NULL; previous = e, e = e->next()) {
|
||||
if (e->literal() == nm) {
|
||||
if (previous != NULL) {
|
||||
previous->set_next(e->next());
|
||||
} else {
|
||||
set_entry(index, e->next());
|
||||
}
|
||||
free_entry(e);
|
||||
remove_entry(e, previous);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -163,25 +171,23 @@ void CodeRootSetTable::nmethods_do(CodeBlobClosure* blk) {
|
||||
}
|
||||
|
||||
template<typename CB>
|
||||
void CodeRootSetTable::remove_if(CB& should_remove) {
|
||||
int CodeRootSetTable::remove_if(CB& should_remove) {
|
||||
int num_removed = 0;
|
||||
for (int index = 0; index < table_size(); ++index) {
|
||||
Entry* previous = NULL;
|
||||
Entry* e = bucket(index);
|
||||
while (e != NULL) {
|
||||
Entry* next = e->next();
|
||||
if (should_remove(e->literal())) {
|
||||
if (previous != NULL) {
|
||||
previous->set_next(next);
|
||||
} else {
|
||||
set_entry(index, next);
|
||||
}
|
||||
free_entry(e);
|
||||
remove_entry(e, previous);
|
||||
++num_removed;
|
||||
} else {
|
||||
previous = e;
|
||||
}
|
||||
e = next;
|
||||
}
|
||||
}
|
||||
return num_removed;
|
||||
}
|
||||
|
||||
G1CodeRootSet::~G1CodeRootSet() {
|
||||
@ -320,14 +326,19 @@ class CleanCallback : public StackObj {
|
||||
bool operator() (nmethod* nm) {
|
||||
_detector._points_into = false;
|
||||
_blobs.do_code_blob(nm);
|
||||
return _detector._points_into;
|
||||
return !_detector._points_into;
|
||||
}
|
||||
};
|
||||
|
||||
void G1CodeRootSet::clean(HeapRegion* owner) {
|
||||
CleanCallback should_clean(owner);
|
||||
if (_table != NULL) {
|
||||
_table->remove_if(should_clean);
|
||||
int removed = _table->remove_if(should_clean);
|
||||
assert((size_t)removed <= _length, "impossible");
|
||||
_length -= removed;
|
||||
}
|
||||
if (_length == 0) {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -861,7 +861,6 @@ void HeapRegion::verify(VerifyOption vo,
|
||||
HeapWord* prev_p = NULL;
|
||||
VerifyLiveClosure vl_cl(g1, vo);
|
||||
bool is_humongous = isHumongous();
|
||||
bool do_bot_verify = !is_young();
|
||||
size_t object_num = 0;
|
||||
while (p < top()) {
|
||||
oop obj = oop(p);
|
||||
@ -878,15 +877,6 @@ void HeapRegion::verify(VerifyOption vo,
|
||||
return;
|
||||
}
|
||||
|
||||
// If it returns false, verify_for_object() will output the
|
||||
// appropriate message.
|
||||
if (do_bot_verify &&
|
||||
!g1->is_obj_dead(obj, this) &&
|
||||
!_offsets.verify_for_object(p, obj_size)) {
|
||||
*failures = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g1->is_obj_dead_cond(obj, this, vo)) {
|
||||
if (obj->is_oop()) {
|
||||
Klass* klass = obj->klass();
|
||||
@ -924,6 +914,10 @@ void HeapRegion::verify(VerifyOption vo,
|
||||
p += obj_size;
|
||||
}
|
||||
|
||||
if (!is_young() && !is_empty()) {
|
||||
_offsets.verify();
|
||||
}
|
||||
|
||||
if (p != top()) {
|
||||
gclog_or_tty->print_cr("end of last object "PTR_FORMAT" "
|
||||
"does not match top "PTR_FORMAT, p, top());
|
||||
|
@ -460,6 +460,8 @@ objArrayOop InstanceKlass::signers() const {
|
||||
oop InstanceKlass::init_lock() const {
|
||||
// return the init lock from the mirror
|
||||
oop lock = java_lang_Class::init_lock(java_mirror());
|
||||
// Prevent reordering with any access of initialization state
|
||||
OrderAccess::loadload();
|
||||
assert((oop)lock != NULL || !is_not_initialized(), // initialized or in_error state
|
||||
"only fully initialized state can have a null lock");
|
||||
return lock;
|
||||
@ -2437,16 +2439,6 @@ void InstanceKlass::release_C_heap_structures() {
|
||||
assert(breakpoints() == 0x0, "should have cleared breakpoints");
|
||||
}
|
||||
|
||||
// deallocate information about previous versions
|
||||
if (_previous_versions != NULL) {
|
||||
for (int i = _previous_versions->length() - 1; i >= 0; i--) {
|
||||
PreviousVersionNode * pv_node = _previous_versions->at(i);
|
||||
delete pv_node;
|
||||
}
|
||||
delete _previous_versions;
|
||||
_previous_versions = NULL;
|
||||
}
|
||||
|
||||
// deallocate the cached class file
|
||||
if (_cached_class_file != NULL) {
|
||||
os::free(_cached_class_file, mtClass);
|
||||
@ -3020,16 +3012,17 @@ void InstanceKlass::print_on(outputStream* st) const {
|
||||
st->print(BULLET"field type annotations: "); fields_type_annotations()->print_value_on(st); st->cr();
|
||||
{
|
||||
bool have_pv = false;
|
||||
PreviousVersionWalker pvw(Thread::current(), (InstanceKlass*)this);
|
||||
for (PreviousVersionNode * pv_node = pvw.next_previous_version();
|
||||
pv_node != NULL; pv_node = pvw.next_previous_version()) {
|
||||
// previous versions are linked together through the InstanceKlass
|
||||
for (InstanceKlass* pv_node = _previous_versions;
|
||||
pv_node != NULL;
|
||||
pv_node = pv_node->previous_versions()) {
|
||||
if (!have_pv)
|
||||
st->print(BULLET"previous version: ");
|
||||
have_pv = true;
|
||||
pv_node->prev_constant_pool()->print_value_on(st);
|
||||
pv_node->constants()->print_value_on(st);
|
||||
}
|
||||
if (have_pv) st->cr();
|
||||
} // pvw is cleaned up
|
||||
}
|
||||
|
||||
if (generic_signature() != NULL) {
|
||||
st->print(BULLET"generic signature: ");
|
||||
@ -3443,92 +3436,92 @@ void InstanceKlass::set_init_state(ClassState state) {
|
||||
// RedefineClasses() support for previous versions:
|
||||
|
||||
// Purge previous versions
|
||||
static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_count) {
|
||||
void InstanceKlass::purge_previous_versions(InstanceKlass* ik) {
|
||||
if (ik->previous_versions() != NULL) {
|
||||
// This klass has previous versions so see what we can cleanup
|
||||
// while it is safe to do so.
|
||||
|
||||
int deleted_count = 0; // leave debugging breadcrumbs
|
||||
int live_count = 0;
|
||||
ClassLoaderData* loader_data = ik->class_loader_data() == NULL ?
|
||||
ClassLoaderData::the_null_class_loader_data() :
|
||||
ik->class_loader_data();
|
||||
ClassLoaderData* loader_data = ik->class_loader_data();
|
||||
assert(loader_data != NULL, "should never be null");
|
||||
|
||||
// RC_TRACE macro has an embedded ResourceMark
|
||||
RC_TRACE(0x00000200, ("purge: %s: previous version length=%d",
|
||||
ik->external_name(), ik->previous_versions()->length()));
|
||||
RC_TRACE(0x00000200, ("purge: %s: previous versions", ik->external_name()));
|
||||
|
||||
for (int i = ik->previous_versions()->length() - 1; i >= 0; i--) {
|
||||
// check the previous versions array
|
||||
PreviousVersionNode * pv_node = ik->previous_versions()->at(i);
|
||||
ConstantPool* cp_ref = pv_node->prev_constant_pool();
|
||||
assert(cp_ref != NULL, "cp ref was unexpectedly cleared");
|
||||
// previous versions are linked together through the InstanceKlass
|
||||
InstanceKlass* pv_node = ik->previous_versions();
|
||||
InstanceKlass* last = ik;
|
||||
int version = 0;
|
||||
|
||||
// check the previous versions list
|
||||
for (; pv_node != NULL; ) {
|
||||
|
||||
ConstantPool* pvcp = pv_node->constants();
|
||||
assert(pvcp != NULL, "cp ref was unexpectedly cleared");
|
||||
|
||||
ConstantPool* pvcp = cp_ref;
|
||||
if (!pvcp->on_stack()) {
|
||||
// If the constant pool isn't on stack, none of the methods
|
||||
// are executing. Delete all the methods, the constant pool and
|
||||
// and this previous version node.
|
||||
GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
|
||||
if (method_refs != NULL) {
|
||||
for (int j = method_refs->length() - 1; j >= 0; j--) {
|
||||
Method* method = method_refs->at(j);
|
||||
assert(method != NULL, "method ref was unexpectedly cleared");
|
||||
method_refs->remove_at(j);
|
||||
// method will be freed with associated class.
|
||||
}
|
||||
}
|
||||
// Remove the constant pool
|
||||
delete pv_node;
|
||||
// Since we are traversing the array backwards, we don't have to
|
||||
// do anything special with the index.
|
||||
ik->previous_versions()->remove_at(i);
|
||||
// are executing. Unlink this previous_version.
|
||||
// The previous version InstanceKlass is on the ClassLoaderData deallocate list
|
||||
// so will be deallocated during the next phase of class unloading.
|
||||
pv_node = pv_node->previous_versions();
|
||||
last->link_previous_versions(pv_node);
|
||||
deleted_count++;
|
||||
version++;
|
||||
continue;
|
||||
} else {
|
||||
RC_TRACE(0x00000200, ("purge: previous version @%d is alive", i));
|
||||
RC_TRACE(0x00000200, ("purge: previous version " INTPTR_FORMAT " is alive",
|
||||
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++;
|
||||
}
|
||||
|
||||
// At least one method is live in this previous version, clean out
|
||||
// the others or mark them as obsolete.
|
||||
GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
|
||||
// At least one method is live in this previous version so clean its MethodData.
|
||||
// Reset dead EMCP methods not to get breakpoints.
|
||||
// All methods are deallocated when all of the methods for this class are no
|
||||
// longer running.
|
||||
Array<Method*>* method_refs = pv_node->methods();
|
||||
if (method_refs != NULL) {
|
||||
RC_TRACE(0x00000200, ("purge: previous methods length=%d",
|
||||
method_refs->length()));
|
||||
for (int j = method_refs->length() - 1; j >= 0; j--) {
|
||||
for (int j = 0; j < method_refs->length(); j++) {
|
||||
Method* method = method_refs->at(j);
|
||||
assert(method != NULL, "method ref was unexpectedly cleared");
|
||||
|
||||
// Remove the emcp method if it's not executing
|
||||
// If it's been made obsolete by a redefinition of a non-emcp
|
||||
// method, mark it as obsolete but leave it to clean up later.
|
||||
if (!method->on_stack()) {
|
||||
method_refs->remove_at(j);
|
||||
} else if (emcp_method_count == 0) {
|
||||
method->set_is_obsolete();
|
||||
// no breakpoints for non-running methods
|
||||
if (method->is_running_emcp()) {
|
||||
method->set_running_emcp(false);
|
||||
}
|
||||
} else {
|
||||
assert (method->is_obsolete() || method->is_running_emcp(),
|
||||
"emcp method cannot run after emcp bit is cleared");
|
||||
// RC_TRACE macro has an embedded ResourceMark
|
||||
RC_TRACE(0x00000200,
|
||||
("purge: %s(%s): prev method @%d in version @%d is alive",
|
||||
method->name()->as_C_string(),
|
||||
method->signature()->as_C_string(), j, i));
|
||||
method->signature()->as_C_string(), j, version));
|
||||
if (method->method_data() != NULL) {
|
||||
// Clean out any weak method links
|
||||
// Clean out any weak method links for running methods
|
||||
// (also should include not EMCP methods)
|
||||
method->method_data()->clean_weak_method_links();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// next previous version
|
||||
last = pv_node;
|
||||
pv_node = pv_node->previous_versions();
|
||||
version++;
|
||||
}
|
||||
assert(ik->previous_versions()->length() == live_count, "sanity check");
|
||||
RC_TRACE(0x00000200,
|
||||
("purge: previous version stats: live=%d, deleted=%d", live_count,
|
||||
deleted_count));
|
||||
}
|
||||
|
||||
// Clean MethodData of this class's methods so they don't refer to
|
||||
// old methods that are no longer running.
|
||||
Array<Method*>* methods = ik->methods();
|
||||
int num_methods = methods->length();
|
||||
for (int index2 = 0; index2 < num_methods; ++index2) {
|
||||
@ -3538,122 +3531,30 @@ static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_
|
||||
}
|
||||
}
|
||||
|
||||
// External interface for use during class unloading.
|
||||
void InstanceKlass::purge_previous_versions(InstanceKlass* ik) {
|
||||
// Call with >0 emcp methods since they are not currently being redefined.
|
||||
purge_previous_versions_internal(ik, 1);
|
||||
}
|
||||
|
||||
|
||||
// Potentially add an information node that contains pointers to the
|
||||
// interesting parts of the previous version of the_class.
|
||||
// This is also where we clean out any unused references.
|
||||
// Note that while we delete nodes from the _previous_versions
|
||||
// array, we never delete the array itself until the klass is
|
||||
// unloaded. The has_been_redefined() query depends on that fact.
|
||||
//
|
||||
void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
|
||||
BitMap* emcp_methods, int emcp_method_count) {
|
||||
assert(Thread::current()->is_VM_thread(),
|
||||
"only VMThread can add previous versions");
|
||||
|
||||
if (_previous_versions == NULL) {
|
||||
// This is the first previous version so make some space.
|
||||
// Start with 2 elements under the assumption that the class
|
||||
// won't be redefined much.
|
||||
_previous_versions = new (ResourceObj::C_HEAP, mtClass)
|
||||
GrowableArray<PreviousVersionNode *>(2, true);
|
||||
}
|
||||
|
||||
ConstantPool* cp_ref = ikh->constants();
|
||||
|
||||
// RC_TRACE macro has an embedded ResourceMark
|
||||
RC_TRACE(0x00000400, ("adding previous version ref for %s @%d, EMCP_cnt=%d "
|
||||
"on_stack=%d",
|
||||
ikh->external_name(), _previous_versions->length(), emcp_method_count,
|
||||
cp_ref->on_stack()));
|
||||
|
||||
// If the constant pool for this previous version of the class
|
||||
// is not marked as being on the stack, then none of the methods
|
||||
// in this previous version of the class are on the stack so
|
||||
// we don't need to create a new PreviousVersionNode. However,
|
||||
// we still need to examine older previous versions below.
|
||||
Array<Method*>* old_methods = ikh->methods();
|
||||
|
||||
if (cp_ref->on_stack()) {
|
||||
PreviousVersionNode * pv_node = NULL;
|
||||
if (emcp_method_count == 0) {
|
||||
// non-shared ConstantPool gets a reference
|
||||
pv_node = new PreviousVersionNode(cp_ref, NULL);
|
||||
RC_TRACE(0x00000400,
|
||||
("add: all methods are obsolete; flushing any EMCP refs"));
|
||||
} else {
|
||||
int local_count = 0;
|
||||
GrowableArray<Method*>* method_refs = new (ResourceObj::C_HEAP, mtClass)
|
||||
GrowableArray<Method*>(emcp_method_count, true);
|
||||
for (int i = 0; i < old_methods->length(); i++) {
|
||||
if (emcp_methods->at(i)) {
|
||||
// this old method is EMCP. Save it only if it's on the stack
|
||||
Method* old_method = old_methods->at(i);
|
||||
if (old_method->on_stack()) {
|
||||
method_refs->append(old_method);
|
||||
}
|
||||
if (++local_count >= emcp_method_count) {
|
||||
// no more EMCP methods so bail out now
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// non-shared ConstantPool gets a reference
|
||||
pv_node = new PreviousVersionNode(cp_ref, method_refs);
|
||||
}
|
||||
// append new previous version.
|
||||
_previous_versions->append(pv_node);
|
||||
}
|
||||
|
||||
// Since the caller is the VMThread and we are at a safepoint, this
|
||||
// is a good time to clear out unused references.
|
||||
|
||||
RC_TRACE(0x00000400, ("add: previous version length=%d",
|
||||
_previous_versions->length()));
|
||||
|
||||
// Purge previous versions not executing on the stack
|
||||
purge_previous_versions_internal(this, emcp_method_count);
|
||||
|
||||
void InstanceKlass::mark_newly_obsolete_methods(Array<Method*>* old_methods,
|
||||
int emcp_method_count) {
|
||||
int obsolete_method_count = old_methods->length() - emcp_method_count;
|
||||
|
||||
if (emcp_method_count != 0 && obsolete_method_count != 0 &&
|
||||
_previous_versions->length() > 0) {
|
||||
_previous_versions != NULL) {
|
||||
// We have a mix of obsolete and EMCP methods so we have to
|
||||
// clear out any matching EMCP method entries the hard way.
|
||||
int local_count = 0;
|
||||
for (int i = 0; i < old_methods->length(); i++) {
|
||||
if (!emcp_methods->at(i)) {
|
||||
Method* old_method = old_methods->at(i);
|
||||
if (old_method->is_obsolete()) {
|
||||
// only obsolete methods are interesting
|
||||
Method* old_method = old_methods->at(i);
|
||||
Symbol* m_name = old_method->name();
|
||||
Symbol* m_signature = old_method->signature();
|
||||
|
||||
// we might not have added the last entry
|
||||
for (int j = _previous_versions->length() - 1; j >= 0; j--) {
|
||||
// check the previous versions array for non executing obsolete methods
|
||||
PreviousVersionNode * pv_node = _previous_versions->at(j);
|
||||
// previous versions are linked together through the InstanceKlass
|
||||
int j = 0;
|
||||
for (InstanceKlass* prev_version = _previous_versions;
|
||||
prev_version != NULL;
|
||||
prev_version = prev_version->previous_versions(), j++) {
|
||||
|
||||
GrowableArray<Method*>* method_refs = pv_node->prev_EMCP_methods();
|
||||
if (method_refs == NULL) {
|
||||
// We have run into a PreviousVersion generation where
|
||||
// all methods were made obsolete during that generation's
|
||||
// RedefineClasses() operation. At the time of that
|
||||
// operation, all EMCP methods were flushed so we don't
|
||||
// have to go back any further.
|
||||
//
|
||||
// A NULL method_refs is different than an empty method_refs.
|
||||
// We cannot infer any optimizations about older generations
|
||||
// from an empty method_refs for the current generation.
|
||||
break;
|
||||
}
|
||||
|
||||
for (int k = method_refs->length() - 1; k >= 0; k--) {
|
||||
Array<Method*>* method_refs = prev_version->methods();
|
||||
for (int k = 0; k < method_refs->length(); k++) {
|
||||
Method* method = method_refs->at(k);
|
||||
|
||||
if (!method->is_obsolete() &&
|
||||
@ -3661,14 +3562,11 @@ void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
|
||||
method->signature() == m_signature) {
|
||||
// The current RedefineClasses() call has made all EMCP
|
||||
// versions of this method obsolete so mark it as obsolete
|
||||
// and remove the reference.
|
||||
RC_TRACE(0x00000400,
|
||||
("add: %s(%s): flush obsolete method @%d in version @%d",
|
||||
m_name->as_C_string(), m_signature->as_C_string(), k, j));
|
||||
|
||||
method->set_is_obsolete();
|
||||
// Leave obsolete methods on the previous version list to
|
||||
// clean up later.
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3676,9 +3574,9 @@ void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
|
||||
// The previous loop may not find a matching EMCP method, but
|
||||
// that doesn't mean that we can optimize and not go any
|
||||
// further back in the PreviousVersion generations. The EMCP
|
||||
// method for this generation could have already been deleted,
|
||||
// method for this generation could have already been made obsolete,
|
||||
// but there still may be an older EMCP method that has not
|
||||
// been deleted.
|
||||
// been made obsolete.
|
||||
}
|
||||
|
||||
if (++local_count >= obsolete_method_count) {
|
||||
@ -3688,15 +3586,69 @@ void InstanceKlass::add_previous_version(instanceKlassHandle ikh,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the scratch_class as the previous version if any of the methods are running.
|
||||
// The previous_versions are used to set breakpoints in EMCP methods and they are
|
||||
// also used to clean MethodData links to redefined methods that are no longer running.
|
||||
void InstanceKlass::add_previous_version(instanceKlassHandle scratch_class,
|
||||
int emcp_method_count) {
|
||||
assert(Thread::current()->is_VM_thread(),
|
||||
"only VMThread can add previous versions");
|
||||
|
||||
// RC_TRACE macro has an embedded ResourceMark
|
||||
RC_TRACE(0x00000400, ("adding previous version ref for %s, EMCP_cnt=%d",
|
||||
scratch_class->external_name(), emcp_method_count));
|
||||
|
||||
// Clean out old previous versions
|
||||
purge_previous_versions(this);
|
||||
|
||||
// Mark newly obsolete methods in remaining previous versions. An EMCP method from
|
||||
// a previous redefinition may be made obsolete by this redefinition.
|
||||
Array<Method*>* old_methods = scratch_class->methods();
|
||||
mark_newly_obsolete_methods(old_methods, emcp_method_count);
|
||||
|
||||
// If the constant pool for this previous version of the class
|
||||
// is not marked as being on the stack, then none of the methods
|
||||
// in this previous version of the class are on the stack so
|
||||
// we don't need to add this as a previous version.
|
||||
ConstantPool* cp_ref = scratch_class->constants();
|
||||
if (!cp_ref->on_stack()) {
|
||||
RC_TRACE(0x00000400, ("add: scratch class not added; no methods are running"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (emcp_method_count != 0) {
|
||||
// At least one method is still running, check for EMCP methods
|
||||
for (int i = 0; i < old_methods->length(); i++) {
|
||||
Method* old_method = old_methods->at(i);
|
||||
if (!old_method->is_obsolete() && old_method->on_stack()) {
|
||||
// if EMCP method (not obsolete) is on the stack, mark as EMCP so that
|
||||
// we can add breakpoints for it.
|
||||
|
||||
// We set the method->on_stack bit during safepoints for class redefinition and
|
||||
// class unloading and use this bit to set the is_running_emcp bit.
|
||||
// After the safepoint, the on_stack bit is cleared and the running emcp
|
||||
// method may exit. If so, we would set a breakpoint in a method that
|
||||
// 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));
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add previous version if any methods are still running.
|
||||
RC_TRACE(0x00000400, ("add: scratch class added; one of its methods is on_stack"));
|
||||
assert(scratch_class->previous_versions() == NULL, "shouldn't have a previous version");
|
||||
scratch_class->link_previous_versions(previous_versions());
|
||||
link_previous_versions(scratch_class());
|
||||
} // end add_previous_version()
|
||||
|
||||
|
||||
// Determine if InstanceKlass has a previous version.
|
||||
bool InstanceKlass::has_previous_version() const {
|
||||
return (_previous_versions != NULL && _previous_versions->length() > 0);
|
||||
} // end has_previous_version()
|
||||
|
||||
|
||||
Method* InstanceKlass::method_with_idnum(int idnum) {
|
||||
Method* m = NULL;
|
||||
if (idnum < methods()->length()) {
|
||||
@ -3722,61 +3674,3 @@ jint InstanceKlass::get_cached_class_file_len() {
|
||||
unsigned char * InstanceKlass::get_cached_class_file_bytes() {
|
||||
return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file);
|
||||
}
|
||||
|
||||
|
||||
// Construct a PreviousVersionNode entry for the array hung off
|
||||
// the InstanceKlass.
|
||||
PreviousVersionNode::PreviousVersionNode(ConstantPool* prev_constant_pool,
|
||||
GrowableArray<Method*>* prev_EMCP_methods) {
|
||||
|
||||
_prev_constant_pool = prev_constant_pool;
|
||||
_prev_EMCP_methods = prev_EMCP_methods;
|
||||
}
|
||||
|
||||
|
||||
// Destroy a PreviousVersionNode
|
||||
PreviousVersionNode::~PreviousVersionNode() {
|
||||
if (_prev_constant_pool != NULL) {
|
||||
_prev_constant_pool = NULL;
|
||||
}
|
||||
|
||||
if (_prev_EMCP_methods != NULL) {
|
||||
delete _prev_EMCP_methods;
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a helper for walking the previous versions array
|
||||
PreviousVersionWalker::PreviousVersionWalker(Thread* thread, InstanceKlass *ik) {
|
||||
_thread = thread;
|
||||
_previous_versions = ik->previous_versions();
|
||||
_current_index = 0;
|
||||
_current_p = NULL;
|
||||
_current_constant_pool_handle = constantPoolHandle(thread, ik->constants());
|
||||
}
|
||||
|
||||
|
||||
// Return the interesting information for the next previous version
|
||||
// of the klass. Returns NULL if there are no more previous versions.
|
||||
PreviousVersionNode* PreviousVersionWalker::next_previous_version() {
|
||||
if (_previous_versions == NULL) {
|
||||
// no previous versions so nothing to return
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_current_p = NULL; // reset to NULL
|
||||
_current_constant_pool_handle = NULL;
|
||||
|
||||
int length = _previous_versions->length();
|
||||
|
||||
while (_current_index < length) {
|
||||
PreviousVersionNode * pv_node = _previous_versions->at(_current_index++);
|
||||
|
||||
// Save a handle to the constant pool for this previous version,
|
||||
// which keeps all the methods from being deallocated.
|
||||
_current_constant_pool_handle = constantPoolHandle(_thread, pv_node->prev_constant_pool());
|
||||
_current_p = pv_node;
|
||||
return pv_node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} // end next_previous_version()
|
||||
|
@ -59,7 +59,6 @@ class BreakpointInfo;
|
||||
class fieldDescriptor;
|
||||
class DepChange;
|
||||
class nmethodBucket;
|
||||
class PreviousVersionNode;
|
||||
class JvmtiCachedClassFieldMap;
|
||||
class MemberNameTable;
|
||||
|
||||
@ -205,7 +204,8 @@ class InstanceKlass: public Klass {
|
||||
_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_has_default_methods = 1 << 5, // class/superclass/implemented interfaces has default methods
|
||||
_misc_has_been_redefined = 1 << 6 // class has been redefined
|
||||
};
|
||||
u2 _misc_flags;
|
||||
u2 _minor_version; // minor version number of class file
|
||||
@ -220,9 +220,8 @@ class InstanceKlass: public Klass {
|
||||
nmethodBucket* _dependencies; // list of dependent nmethods
|
||||
nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class
|
||||
BreakpointInfo* _breakpoints; // bpt lists, managed by Method*
|
||||
// Array of interesting part(s) of the previous version(s) of this
|
||||
// InstanceKlass. See PreviousVersionWalker below.
|
||||
GrowableArray<PreviousVersionNode *>* _previous_versions;
|
||||
// Linked instanceKlasses of previous versions
|
||||
InstanceKlass* _previous_versions;
|
||||
// JVMTI fields can be moved to their own structure - see 6315920
|
||||
// JVMTI: cached class file, before retransformable agent modified it in CFLH
|
||||
JvmtiCachedClassFileData* _cached_class_file;
|
||||
@ -608,19 +607,20 @@ class InstanceKlass: public Klass {
|
||||
}
|
||||
|
||||
// RedefineClasses() support for previous versions:
|
||||
void add_previous_version(instanceKlassHandle ikh, BitMap *emcp_methods,
|
||||
int emcp_method_count);
|
||||
// If the _previous_versions array is non-NULL, then this klass
|
||||
// has been redefined at least once even if we aren't currently
|
||||
// tracking a previous version.
|
||||
bool has_been_redefined() const { return _previous_versions != NULL; }
|
||||
bool has_previous_version() const;
|
||||
void add_previous_version(instanceKlassHandle ikh, int emcp_method_count);
|
||||
|
||||
InstanceKlass* previous_versions() const { return _previous_versions; }
|
||||
|
||||
bool has_been_redefined() const {
|
||||
return (_misc_flags & _misc_has_been_redefined) != 0;
|
||||
}
|
||||
void set_has_been_redefined() {
|
||||
_misc_flags |= _misc_has_been_redefined;
|
||||
}
|
||||
|
||||
void init_previous_versions() {
|
||||
_previous_versions = NULL;
|
||||
}
|
||||
GrowableArray<PreviousVersionNode *>* previous_versions() const {
|
||||
return _previous_versions;
|
||||
}
|
||||
|
||||
static void purge_previous_versions(InstanceKlass* ik);
|
||||
|
||||
@ -1042,6 +1042,10 @@ private:
|
||||
|
||||
// Free CHeap allocated fields.
|
||||
void release_C_heap_structures();
|
||||
|
||||
// RedefineClasses support
|
||||
void link_previous_versions(InstanceKlass* pv) { _previous_versions = pv; }
|
||||
void mark_newly_obsolete_methods(Array<Method*>* old_methods, int emcp_method_count);
|
||||
public:
|
||||
// CDS support - remove and restore oops from metadata. Oops are not shared.
|
||||
virtual void remove_unshareable_info();
|
||||
@ -1141,62 +1145,6 @@ class JNIid: public CHeapObj<mtClass> {
|
||||
};
|
||||
|
||||
|
||||
// If breakpoints are more numerous than just JVMTI breakpoints,
|
||||
// consider compressing this data structure.
|
||||
// It is currently a simple linked list defined in method.hpp.
|
||||
|
||||
class BreakpointInfo;
|
||||
|
||||
|
||||
// A collection point for interesting information about the previous
|
||||
// version(s) of an InstanceKlass. A GrowableArray of PreviousVersionNodes
|
||||
// is attached to the InstanceKlass as needed. See PreviousVersionWalker below.
|
||||
class PreviousVersionNode : public CHeapObj<mtClass> {
|
||||
private:
|
||||
ConstantPool* _prev_constant_pool;
|
||||
|
||||
// If the previous version of the InstanceKlass doesn't have any
|
||||
// EMCP methods, then _prev_EMCP_methods will be NULL. If all the
|
||||
// EMCP methods have been collected, then _prev_EMCP_methods can
|
||||
// have a length of zero.
|
||||
GrowableArray<Method*>* _prev_EMCP_methods;
|
||||
|
||||
public:
|
||||
PreviousVersionNode(ConstantPool* prev_constant_pool,
|
||||
GrowableArray<Method*>* prev_EMCP_methods);
|
||||
~PreviousVersionNode();
|
||||
ConstantPool* prev_constant_pool() const {
|
||||
return _prev_constant_pool;
|
||||
}
|
||||
GrowableArray<Method*>* prev_EMCP_methods() const {
|
||||
return _prev_EMCP_methods;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Helper object for walking previous versions.
|
||||
class PreviousVersionWalker : public StackObj {
|
||||
private:
|
||||
Thread* _thread;
|
||||
GrowableArray<PreviousVersionNode *>* _previous_versions;
|
||||
int _current_index;
|
||||
|
||||
// A pointer to the current node object so we can handle the deletes.
|
||||
PreviousVersionNode* _current_p;
|
||||
|
||||
// The constant pool handle keeps all the methods in this class from being
|
||||
// deallocated from the metaspace during class unloading.
|
||||
constantPoolHandle _current_constant_pool_handle;
|
||||
|
||||
public:
|
||||
PreviousVersionWalker(Thread* thread, InstanceKlass *ik);
|
||||
|
||||
// Return the interesting information for the next previous version
|
||||
// of the klass. Returns NULL if there are no more previous versions.
|
||||
PreviousVersionNode* next_previous_version();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// nmethodBucket is used to record dependent nmethods for
|
||||
// deoptimization. nmethod dependencies are actually <klass, method>
|
||||
|
@ -1635,34 +1635,34 @@ int Method::backedge_count() {
|
||||
}
|
||||
|
||||
int Method::highest_comp_level() const {
|
||||
const MethodData* mdo = method_data();
|
||||
if (mdo != NULL) {
|
||||
return mdo->highest_comp_level();
|
||||
const MethodCounters* mcs = method_counters();
|
||||
if (mcs != NULL) {
|
||||
return mcs->highest_comp_level();
|
||||
} else {
|
||||
return CompLevel_none;
|
||||
}
|
||||
}
|
||||
|
||||
int Method::highest_osr_comp_level() const {
|
||||
const MethodData* mdo = method_data();
|
||||
if (mdo != NULL) {
|
||||
return mdo->highest_osr_comp_level();
|
||||
const MethodCounters* mcs = method_counters();
|
||||
if (mcs != NULL) {
|
||||
return mcs->highest_osr_comp_level();
|
||||
} else {
|
||||
return CompLevel_none;
|
||||
}
|
||||
}
|
||||
|
||||
void Method::set_highest_comp_level(int level) {
|
||||
MethodData* mdo = method_data();
|
||||
if (mdo != NULL) {
|
||||
mdo->set_highest_comp_level(level);
|
||||
MethodCounters* mcs = method_counters();
|
||||
if (mcs != NULL) {
|
||||
mcs->set_highest_comp_level(level);
|
||||
}
|
||||
}
|
||||
|
||||
void Method::set_highest_osr_comp_level(int level) {
|
||||
MethodData* mdo = method_data();
|
||||
if (mdo != NULL) {
|
||||
mdo->set_highest_osr_comp_level(level);
|
||||
MethodCounters* mcs = method_counters();
|
||||
if (mcs != NULL) {
|
||||
mcs->set_highest_osr_comp_level(level);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,8 @@ class Method : public Metadata {
|
||||
_caller_sensitive = 1 << 1,
|
||||
_force_inline = 1 << 2,
|
||||
_dont_inline = 1 << 3,
|
||||
_hidden = 1 << 4
|
||||
_hidden = 1 << 4,
|
||||
_running_emcp = 1 << 5
|
||||
};
|
||||
u1 _flags;
|
||||
|
||||
@ -688,6 +689,21 @@ class Method : public Metadata {
|
||||
void set_is_obsolete() { _access_flags.set_is_obsolete(); }
|
||||
bool is_deleted() const { return access_flags().is_deleted(); }
|
||||
void set_is_deleted() { _access_flags.set_is_deleted(); }
|
||||
|
||||
bool is_running_emcp() const {
|
||||
// EMCP methods are old but not obsolete or deleted. Equivalent
|
||||
// Modulo Constant Pool means the method is equivalent except
|
||||
// the constant pool and instructions that access the constant
|
||||
// pool might be different.
|
||||
// If a breakpoint is set in a redefined method, its EMCP methods that are
|
||||
// still running must have a breakpoint also.
|
||||
return (_flags & _running_emcp) != 0;
|
||||
}
|
||||
|
||||
void set_running_emcp(bool x) {
|
||||
_flags = x ? (_flags | _running_emcp) : (_flags & ~_running_emcp);
|
||||
}
|
||||
|
||||
bool on_stack() const { return access_flags().on_stack(); }
|
||||
void set_on_stack(const bool value);
|
||||
|
||||
|
@ -35,4 +35,40 @@ void MethodCounters::clear_counters() {
|
||||
set_interpreter_throwout_count(0);
|
||||
set_interpreter_invocation_count(0);
|
||||
set_nmethod_age(INT_MAX);
|
||||
#ifdef TIERED
|
||||
set_prev_time(0);
|
||||
set_rate(0);
|
||||
set_highest_comp_level(0);
|
||||
set_highest_osr_comp_level(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int MethodCounters::highest_comp_level() const {
|
||||
#ifdef TIERED
|
||||
return _highest_comp_level;
|
||||
#else
|
||||
return CompLevel_none;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MethodCounters::set_highest_comp_level(int level) {
|
||||
#ifdef TIERED
|
||||
_highest_comp_level = level;
|
||||
#endif
|
||||
}
|
||||
|
||||
int MethodCounters::highest_osr_comp_level() const {
|
||||
#ifdef TIERED
|
||||
return _highest_osr_comp_level;
|
||||
#else
|
||||
return CompLevel_none;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MethodCounters::set_highest_osr_comp_level(int level) {
|
||||
#ifdef TIERED
|
||||
_highest_osr_comp_level = level;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,8 @@ class MethodCounters: public MetaspaceObj {
|
||||
#ifdef TIERED
|
||||
float _rate; // Events (invocation and backedge counter increments) per millisecond
|
||||
jlong _prev_time; // Previous time the rate was acquired
|
||||
u1 _highest_comp_level; // Highest compile level this method has ever seen.
|
||||
u1 _highest_osr_comp_level; // Same for OSR level
|
||||
#endif
|
||||
|
||||
MethodCounters() : _interpreter_invocation_count(0),
|
||||
@ -57,7 +59,9 @@ class MethodCounters: public MetaspaceObj {
|
||||
_nmethod_age(INT_MAX)
|
||||
#ifdef TIERED
|
||||
, _rate(0),
|
||||
_prev_time(0)
|
||||
_prev_time(0),
|
||||
_highest_comp_level(0),
|
||||
_highest_osr_comp_level(0)
|
||||
#endif
|
||||
{
|
||||
invocation_counter()->init();
|
||||
@ -114,6 +118,11 @@ class MethodCounters: public MetaspaceObj {
|
||||
void set_rate(float rate) { _rate = rate; }
|
||||
#endif
|
||||
|
||||
int highest_comp_level() const;
|
||||
void set_highest_comp_level(int level);
|
||||
int highest_osr_comp_level() const;
|
||||
void set_highest_osr_comp_level(int level);
|
||||
|
||||
// invocation counter
|
||||
InvocationCounter* invocation_counter() { return &_invocation_counter; }
|
||||
InvocationCounter* backedge_counter() { return &_backedge_counter; }
|
||||
|
@ -1134,8 +1134,6 @@ void MethodData::init() {
|
||||
_tenure_traps = 0;
|
||||
_num_loops = 0;
|
||||
_num_blocks = 0;
|
||||
_highest_comp_level = 0;
|
||||
_highest_osr_comp_level = 0;
|
||||
_would_profile = true;
|
||||
|
||||
#if INCLUDE_RTM_OPT
|
||||
|
@ -2095,10 +2095,6 @@ private:
|
||||
// time with C1. It is used to determine if method is trivial.
|
||||
short _num_loops;
|
||||
short _num_blocks;
|
||||
// Highest compile level this method has ever seen.
|
||||
u1 _highest_comp_level;
|
||||
// Same for OSR level
|
||||
u1 _highest_osr_comp_level;
|
||||
// Does this method contain anything worth profiling?
|
||||
bool _would_profile;
|
||||
|
||||
@ -2277,11 +2273,6 @@ public:
|
||||
void set_would_profile(bool p) { _would_profile = p; }
|
||||
bool would_profile() const { return _would_profile; }
|
||||
|
||||
int highest_comp_level() const { return _highest_comp_level; }
|
||||
void set_highest_comp_level(int level) { _highest_comp_level = level; }
|
||||
int highest_osr_comp_level() const { return _highest_osr_comp_level; }
|
||||
void set_highest_osr_comp_level(int level) { _highest_osr_comp_level = level; }
|
||||
|
||||
int num_loops() const { return _num_loops; }
|
||||
void set_num_loops(int n) { _num_loops = n; }
|
||||
int num_blocks() const { return _num_blocks; }
|
||||
|
@ -430,7 +430,7 @@ int Compile::frame_size_in_words() const {
|
||||
// removes the need to bang the stack in the deoptimization blob which
|
||||
// in turn simplifies stack overflow handling.
|
||||
int Compile::bang_size_in_bytes() const {
|
||||
return MAX2(_interpreter_frame_size, frame_size_in_bytes());
|
||||
return MAX2(frame_size_in_bytes() + os::extra_bang_size_in_bytes(), _interpreter_frame_size);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
@ -4968,7 +4968,8 @@ bool LibraryCallKit::inline_multiplyToLen() {
|
||||
|
||||
// Allocate the result array
|
||||
Node* zlen = _gvn.transform(new AddINode(xlen, ylen));
|
||||
Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_INT)));
|
||||
ciKlass* klass = ciTypeArrayKlass::make(T_INT);
|
||||
Node* klass_node = makecon(TypeKlassPtr::make(klass));
|
||||
|
||||
IdealKit ideal(this);
|
||||
|
||||
@ -5002,7 +5003,8 @@ bool LibraryCallKit::inline_multiplyToLen() {
|
||||
|
||||
sync_kit(ideal);
|
||||
z = __ value(z_alloc);
|
||||
_gvn.set_type(z, TypeAryPtr::INTS);
|
||||
// Can't use TypeAryPtr::INTS which uses Bottom offset.
|
||||
_gvn.set_type(z, TypeOopPtr::make_from_klass(klass));
|
||||
// Final sync IdealKit and GraphKit.
|
||||
final_sync(ideal);
|
||||
#undef __
|
||||
|
@ -282,39 +282,22 @@ address JvmtiBreakpoint::getBcp() {
|
||||
void JvmtiBreakpoint::each_method_version_do(method_action meth_act) {
|
||||
((Method*)_method->*meth_act)(_bci);
|
||||
|
||||
// add/remove breakpoint to/from versions of the method that
|
||||
// are EMCP. Directly or transitively obsolete methods are
|
||||
// not saved in the PreviousVersionNodes.
|
||||
// add/remove breakpoint to/from versions of the method that are EMCP.
|
||||
Thread *thread = Thread::current();
|
||||
instanceKlassHandle ikh = instanceKlassHandle(thread, _method->method_holder());
|
||||
Symbol* m_name = _method->name();
|
||||
Symbol* m_signature = _method->signature();
|
||||
|
||||
// search previous versions if they exist
|
||||
PreviousVersionWalker pvw(thread, (InstanceKlass *)ikh());
|
||||
for (PreviousVersionNode * pv_node = pvw.next_previous_version();
|
||||
pv_node != NULL; pv_node = pvw.next_previous_version()) {
|
||||
GrowableArray<Method*>* methods = pv_node->prev_EMCP_methods();
|
||||
|
||||
if (methods == NULL) {
|
||||
// We have run into a PreviousVersion generation where
|
||||
// all methods were made obsolete during that generation's
|
||||
// RedefineClasses() operation. At the time of that
|
||||
// operation, all EMCP methods were flushed so we don't
|
||||
// have to go back any further.
|
||||
//
|
||||
// A NULL methods array is different than an empty methods
|
||||
// array. We cannot infer any optimizations about older
|
||||
// generations from an empty methods array for the current
|
||||
// generation.
|
||||
break;
|
||||
}
|
||||
for (InstanceKlass* pv_node = ikh->previous_versions();
|
||||
pv_node != NULL;
|
||||
pv_node = pv_node->previous_versions()) {
|
||||
Array<Method*>* methods = pv_node->methods();
|
||||
|
||||
for (int i = methods->length() - 1; i >= 0; i--) {
|
||||
Method* method = methods->at(i);
|
||||
// obsolete methods that are running are not deleted from
|
||||
// previous version array, but they are skipped here.
|
||||
if (!method->is_obsolete() &&
|
||||
// Only set breakpoints in running EMCP methods.
|
||||
if (method->is_running_emcp() &&
|
||||
method->name() == m_name &&
|
||||
method->signature() == m_signature) {
|
||||
RC_TRACE(0x00000800, ("%sing breakpoint in %s(%s)",
|
||||
|
@ -135,7 +135,7 @@ void VM_RedefineClasses::doit() {
|
||||
|
||||
// Mark methods seen on stack and everywhere else so old methods are not
|
||||
// cleaned up if they're on the stack.
|
||||
MetadataOnStackMark md_on_stack;
|
||||
MetadataOnStackMark md_on_stack(true);
|
||||
HandleMark hm(thread); // make sure any handles created are deleted
|
||||
// before the stack walk again.
|
||||
|
||||
@ -2826,11 +2826,10 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
|
||||
}
|
||||
|
||||
// the previous versions' constant pool caches may need adjustment
|
||||
PreviousVersionWalker pvw(_thread, ik);
|
||||
for (PreviousVersionNode * pv_node = pvw.next_previous_version();
|
||||
pv_node != NULL; pv_node = pvw.next_previous_version()) {
|
||||
other_cp = pv_node->prev_constant_pool();
|
||||
cp_cache = other_cp->cache();
|
||||
for (InstanceKlass* pv_node = ik->previous_versions();
|
||||
pv_node != NULL;
|
||||
pv_node = pv_node->previous_versions()) {
|
||||
cp_cache = pv_node->constants()->cache();
|
||||
if (cp_cache != NULL) {
|
||||
cp_cache->adjust_method_entries(_matching_old_methods,
|
||||
_matching_new_methods,
|
||||
@ -2855,9 +2854,8 @@ void VM_RedefineClasses::update_jmethod_ids() {
|
||||
}
|
||||
}
|
||||
|
||||
void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
|
||||
BitMap *emcp_methods, int * emcp_method_count_p) {
|
||||
*emcp_method_count_p = 0;
|
||||
int VM_RedefineClasses::check_methods_and_mark_as_obsolete() {
|
||||
int emcp_method_count = 0;
|
||||
int obsolete_count = 0;
|
||||
int old_index = 0;
|
||||
for (int j = 0; j < _matching_methods_length; ++j, ++old_index) {
|
||||
@ -2931,9 +2929,9 @@ void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
|
||||
// that we get from effectively overwriting the old methods
|
||||
// when the new methods are attached to the_class.
|
||||
|
||||
// track which methods are EMCP for add_previous_version() call
|
||||
emcp_methods->set_bit(old_index);
|
||||
(*emcp_method_count_p)++;
|
||||
// Count number of methods that are EMCP. The method will be marked
|
||||
// old but not obsolete if it is EMCP.
|
||||
emcp_method_count++;
|
||||
|
||||
// An EMCP method is _not_ obsolete. An obsolete method has a
|
||||
// different jmethodID than the current method. An EMCP method
|
||||
@ -2982,10 +2980,11 @@ void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
|
||||
old_method->name()->as_C_string(),
|
||||
old_method->signature()->as_C_string()));
|
||||
}
|
||||
assert((*emcp_method_count_p + obsolete_count) == _old_methods->length(),
|
||||
assert((emcp_method_count + obsolete_count) == _old_methods->length(),
|
||||
"sanity check");
|
||||
RC_TRACE(0x00000100, ("EMCP_cnt=%d, obsolete_cnt=%d", *emcp_method_count_p,
|
||||
RC_TRACE(0x00000100, ("EMCP_cnt=%d, obsolete_cnt=%d", emcp_method_count,
|
||||
obsolete_count));
|
||||
return emcp_method_count;
|
||||
}
|
||||
|
||||
// This internal class transfers the native function registration from old methods
|
||||
@ -3379,11 +3378,8 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,
|
||||
old_constants->set_pool_holder(scratch_class());
|
||||
#endif
|
||||
|
||||
// track which methods are EMCP for add_previous_version() call below
|
||||
BitMap emcp_methods(_old_methods->length());
|
||||
int emcp_method_count = 0;
|
||||
emcp_methods.clear(); // clears 0..(length() - 1)
|
||||
check_methods_and_mark_as_obsolete(&emcp_methods, &emcp_method_count);
|
||||
// track number of methods that are EMCP for add_previous_version() call below
|
||||
int emcp_method_count = check_methods_and_mark_as_obsolete();
|
||||
transfer_old_native_function_registrations(the_class);
|
||||
|
||||
// The class file bytes from before any retransformable agents mucked
|
||||
@ -3471,9 +3467,10 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,
|
||||
scratch_class->enclosing_method_method_index());
|
||||
scratch_class->set_enclosing_method_indices(old_class_idx, old_method_idx);
|
||||
|
||||
the_class->set_has_been_redefined();
|
||||
|
||||
// keep track of previous versions of this class
|
||||
the_class->add_previous_version(scratch_class, &emcp_methods,
|
||||
emcp_method_count);
|
||||
the_class->add_previous_version(scratch_class, emcp_method_count);
|
||||
|
||||
RC_TIMER_STOP(_timer_rsc_phase1);
|
||||
RC_TIMER_START(_timer_rsc_phase2);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -403,14 +403,9 @@ class VM_RedefineClasses: public VM_Operation {
|
||||
// Change jmethodIDs to point to the new methods
|
||||
void update_jmethod_ids();
|
||||
|
||||
// In addition to marking methods as obsolete, this routine
|
||||
// records which methods are EMCP (Equivalent Module Constant
|
||||
// Pool) in the emcp_methods BitMap and returns the number of
|
||||
// EMCP methods via emcp_method_count_p. This information is
|
||||
// used when information about the previous version of the_class
|
||||
// is squirreled away.
|
||||
void check_methods_and_mark_as_obsolete(BitMap *emcp_methods,
|
||||
int * emcp_method_count_p);
|
||||
// In addition to marking methods as old and/or obsolete, this routine
|
||||
// counts the number of methods that are EMCP (Equivalent Module Constant Pool).
|
||||
int check_methods_and_mark_as_obsolete();
|
||||
void transfer_old_native_function_registrations(instanceKlassHandle the_class);
|
||||
|
||||
// Install the redefinition of a class
|
||||
|
@ -590,7 +590,9 @@ class Arguments : AllStatic {
|
||||
static void fix_appclasspath();
|
||||
|
||||
// Operation modi
|
||||
static Mode mode() { return _mode; }
|
||||
static Mode mode() { return _mode; }
|
||||
static bool is_interpreter_only() { return mode() == _int; }
|
||||
|
||||
|
||||
// Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid.
|
||||
static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen);
|
||||
|
@ -2473,7 +2473,7 @@ class CommandLineFlags {
|
||||
develop(bool, CIPrintCompilerName, false, \
|
||||
"when CIPrint is active, print the name of the active compiler") \
|
||||
\
|
||||
develop(bool, CIPrintCompileQueue, false, \
|
||||
diagnostic(bool, CIPrintCompileQueue, false, \
|
||||
"display the contents of the compile queue whenever a " \
|
||||
"compilation is enqueued") \
|
||||
\
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "services/attachListener.hpp"
|
||||
#include "services/nmtCommon.hpp"
|
||||
#include "services/mallocTracker.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "services/threadService.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
@ -570,6 +571,17 @@ void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
|
||||
NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
|
||||
NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
|
||||
|
||||
#if INCLUDE_NMT
|
||||
// NMT can not track malloc allocation size > MAX_MALLOC_SIZE, which is
|
||||
// (1GB - 1) on 32-bit system. It is not an issue on 64-bit system, where
|
||||
// MAX_MALLOC_SIZE = ((1 << 62) - 1).
|
||||
// VM code does not have such large malloc allocation. However, it can come
|
||||
// Unsafe call.
|
||||
if (MemTracker::tracking_level() >= NMT_summary && size > MAX_MALLOC_SIZE) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ASSERT
|
||||
// checking for the WatcherThread and crash_protection first
|
||||
// since os::malloc can be called when the libjvm.{dll,so} is
|
||||
@ -640,6 +652,13 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS flags) {
|
||||
}
|
||||
|
||||
void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
|
||||
#if INCLUDE_NMT
|
||||
// See comments in os::malloc() above
|
||||
if (MemTracker::tracking_level() >= NMT_summary && size > MAX_MALLOC_SIZE) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ASSERT
|
||||
NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
|
||||
NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
|
||||
|
@ -557,6 +557,16 @@ class os: AllStatic {
|
||||
// Unload library
|
||||
static void dll_unload(void *lib);
|
||||
|
||||
// Callback for loaded module information
|
||||
// Input parameters:
|
||||
// char* module_file_name,
|
||||
// address module_base_addr,
|
||||
// address module_top_addr,
|
||||
// void* param
|
||||
typedef int (*LoadedModulesCallbackFunc)(const char *, address, address, void *);
|
||||
|
||||
static int get_loaded_modules_info(LoadedModulesCallbackFunc callback, void *param);
|
||||
|
||||
// Return the handle of this process
|
||||
static void* get_default_process_handle();
|
||||
|
||||
@ -761,6 +771,9 @@ class os: AllStatic {
|
||||
// Hook for os specific jvm options that we don't want to abort on seeing
|
||||
static bool obsolete_option(const JavaVMOption *option);
|
||||
|
||||
// Amount beyond the callee frame size that we bang the stack.
|
||||
static int extra_bang_size_in_bytes();
|
||||
|
||||
// Extensions
|
||||
#include "runtime/os_ext.hpp"
|
||||
|
||||
|
@ -618,7 +618,7 @@ void NMethodSweeper::possibly_flush(nmethod* nm) {
|
||||
if (mc == NULL) {
|
||||
// Sometimes we can get here without MethodCounters. For example if we run with -Xcomp.
|
||||
// Try to allocate them.
|
||||
mc = Method::build_method_counters(nm->method(), Thread::current());
|
||||
mc = nm->method()->get_method_counters(Thread::current());
|
||||
}
|
||||
if (mc != NULL) {
|
||||
// Snapshot the value as it's changed concurrently
|
||||
|
@ -470,3 +470,15 @@ void VM_Exit::wait_if_vm_exited() {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
void VM_PrintCompileQueue::doit() {
|
||||
CompileBroker::print_compile_queues(_out);
|
||||
}
|
||||
|
||||
void VM_PrintCodeList::doit() {
|
||||
CodeCache::print_codelist(_out);
|
||||
}
|
||||
|
||||
void VM_PrintCodeCache::doit() {
|
||||
CodeCache::print_layout(_out);
|
||||
}
|
||||
|
@ -99,6 +99,9 @@
|
||||
template(RotateGCLog) \
|
||||
template(WhiteBoxOperation) \
|
||||
template(ClassLoaderStatsOperation) \
|
||||
template(PrintCompileQueue) \
|
||||
template(PrintCodeList) \
|
||||
template(PrintCodeCache) \
|
||||
|
||||
class VM_Operation: public CHeapObj<mtInternal> {
|
||||
public:
|
||||
@ -413,4 +416,35 @@ class VM_RotateGCLog: public VM_Operation {
|
||||
void doit() { gclog_or_tty->rotate_log(true, _out); }
|
||||
};
|
||||
|
||||
class VM_PrintCompileQueue: public VM_Operation {
|
||||
private:
|
||||
outputStream* _out;
|
||||
|
||||
public:
|
||||
VM_PrintCompileQueue(outputStream* st) : _out(st) {}
|
||||
VMOp_Type type() const { return VMOp_PrintCompileQueue; }
|
||||
void doit();
|
||||
};
|
||||
|
||||
class VM_PrintCodeList: public VM_Operation {
|
||||
private:
|
||||
outputStream* _out;
|
||||
|
||||
public:
|
||||
VM_PrintCodeList(outputStream* st) : _out(st) {}
|
||||
VMOp_Type type() const { return VMOp_PrintCodeList; }
|
||||
void doit();
|
||||
};
|
||||
|
||||
class VM_PrintCodeCache: public VM_Operation {
|
||||
private:
|
||||
outputStream* _out;
|
||||
|
||||
public:
|
||||
VM_PrintCodeCache(outputStream* st) : _out(st) {}
|
||||
VMOp_Type type() const { return VMOp_PrintCodeCache; }
|
||||
void doit();
|
||||
};
|
||||
|
||||
|
||||
#endif // SHARE_VM_RUNTIME_VM_OPERATIONS_HPP
|
||||
|
@ -60,6 +60,9 @@ void DCmdRegistrant::register_dcmds(){
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompileQueueDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false));
|
||||
|
||||
// Enhanced JMX Agent Support
|
||||
// These commands won't be exported via the DiagnosticCommandMBean until an
|
||||
@ -674,3 +677,18 @@ void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
void CompileQueueDCmd::execute(DCmdSource source, TRAPS) {
|
||||
VM_PrintCompileQueue printCompileQueueOp(output());
|
||||
VMThread::execute(&printCompileQueueOp);
|
||||
}
|
||||
|
||||
void CodeListDCmd::execute(DCmdSource source, TRAPS) {
|
||||
VM_PrintCodeList printCodeListOp(output());
|
||||
VMThread::execute(&printCodeListOp);
|
||||
}
|
||||
|
||||
void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
|
||||
VM_PrintCodeCache printCodeCacheOp(output());
|
||||
VMThread::execute(&printCodeCacheOp);
|
||||
}
|
||||
|
||||
|
@ -399,4 +399,68 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CompileQueueDCmd : public DCmd {
|
||||
public:
|
||||
CompileQueueDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
|
||||
static const char* name() {
|
||||
return "Compiler.queue";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Print methods queued for compilation.";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Low";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission",
|
||||
"monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments() { return 0; }
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
class CodeListDCmd : public DCmd {
|
||||
public:
|
||||
CodeListDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
|
||||
static const char* name() {
|
||||
return "Compiler.codelist";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Print all compiled methods in code cache.";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Medium";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission",
|
||||
"monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments() { return 0; }
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
|
||||
class CodeCacheDCmd : public DCmd {
|
||||
public:
|
||||
CodeCacheDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
|
||||
static const char* name() {
|
||||
return "Compiler.codecache";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Print code cache layout and bounds.";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Low";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission",
|
||||
"monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments() { return 0; }
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
|
||||
|
@ -80,6 +80,7 @@ needs_jdk = \
|
||||
runtime/NMT/MallocSiteHashOverflow.java \
|
||||
runtime/NMT/MallocStressTest.java \
|
||||
runtime/NMT/MallocTestType.java \
|
||||
runtime/NMT/MallocTrackingVerify.java \
|
||||
runtime/NMT/ReleaseCommittedMemory.java \
|
||||
runtime/NMT/ReleaseNoCommit.java \
|
||||
runtime/NMT/ShutdownTwice.java \
|
||||
@ -87,6 +88,7 @@ needs_jdk = \
|
||||
runtime/NMT/SummarySanityCheck.java \
|
||||
runtime/NMT/ThreadedMallocTestType.java \
|
||||
runtime/NMT/ThreadedVirtualAllocTestType.java \
|
||||
runtime/NMT/UnsafeMallocLimit.java \
|
||||
runtime/NMT/VirtualAllocCommitUncommitRecommit.java \
|
||||
runtime/NMT/VirtualAllocTestType.java \
|
||||
runtime/RedefineObject/TestRedefineObject.java \
|
||||
|
@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* @ignore 8027915
|
||||
* @ignore 8049864
|
||||
* @test TestParallelHeapSizeFlags
|
||||
* @key gc
|
||||
* @bug 8006088
|
||||
|
@ -22,7 +22,6 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* @ignore 8025645
|
||||
* @test TestUseCompressedOopsErgo
|
||||
* @key gc
|
||||
* @bug 8010722
|
||||
|
@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ignore 8042051
|
||||
* @ignore 8019361
|
||||
* @test TestDynShrinkHeap
|
||||
* @bug 8016479
|
||||
* @summary Verify that the heap shrinks after full GC according to the current values of the Min/MaxHeapFreeRatio flags
|
||||
|
105
hotspot/test/runtime/NMT/MallocTrackingVerify.java
Normal file
105
hotspot/test/runtime/NMT/MallocTrackingVerify.java
Normal file
@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8054836
|
||||
* @summary Test to verify correctness of malloc tracking
|
||||
* @key nmt jcmd
|
||||
* @library /testlibrary /testlibrary/whitebox
|
||||
* @build MallocTrackingVerify
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocTrackingVerify
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
import com.oracle.java.testlibrary.*;
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
public class MallocTrackingVerify {
|
||||
private static int MAX_ALLOC = 4 * 1024;
|
||||
|
||||
static ArrayList<MallocMemory> mallocd_memory = new ArrayList<MallocMemory>();
|
||||
static long mallocd_total = 0;
|
||||
public static WhiteBox wb = WhiteBox.getWhiteBox();
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
OutputAnalyzer output;
|
||||
|
||||
// Grab my own PID
|
||||
String pid = Integer.toString(ProcessTools.getProcessId());
|
||||
ProcessBuilder pb = new ProcessBuilder();
|
||||
|
||||
Random random = new Random();
|
||||
// Allocate small amounts of memory with random pseudo call stack
|
||||
while (mallocd_total < MAX_ALLOC) {
|
||||
int size = random.nextInt(31) + 1;
|
||||
long addr = wb.NMTMallocWithPseudoStack(size, random.nextInt());
|
||||
if (addr != 0) {
|
||||
MallocMemory mem = new MallocMemory(addr, size);
|
||||
mallocd_memory.add(mem);
|
||||
mallocd_total += size;
|
||||
} else {
|
||||
System.out.println("Out of malloc memory");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary" });
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=4KB, committed=4KB)");
|
||||
|
||||
// Free
|
||||
for (MallocMemory mem : mallocd_memory) {
|
||||
wb.NMTFree(mem.addr());
|
||||
}
|
||||
|
||||
// Run 'jcmd <pid> VM.native_memory summary', check for expected output
|
||||
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid,
|
||||
"VM.native_memory", "summary" });
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldNotContain("Test (reserved=");
|
||||
}
|
||||
|
||||
static class MallocMemory {
|
||||
private long addr;
|
||||
private int size;
|
||||
|
||||
MallocMemory(long addr, int size) {
|
||||
this.addr = addr;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
long addr() {
|
||||
return this.addr;
|
||||
}
|
||||
|
||||
int size() {
|
||||
return this.size;
|
||||
}
|
||||
}
|
||||
}
|
50
hotspot/test/runtime/NMT/UnsafeMallocLimit.java
Normal file
50
hotspot/test/runtime/NMT/UnsafeMallocLimit.java
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8055289
|
||||
* @library /testlibrary
|
||||
* @build UnsafeMallocLimit
|
||||
* @run main/othervm -Xmx32m -XX:NativeMemoryTracking=summary UnsafeMallocLimit
|
||||
*/
|
||||
|
||||
import com.oracle.java.testlibrary.*;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
public class UnsafeMallocLimit {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
if (Platform.is32bit()) {
|
||||
Unsafe unsafe = Utils.getUnsafe();
|
||||
try {
|
||||
unsafe.allocateMemory(1 << 30);
|
||||
throw new RuntimeException("Did not get expected OOME");
|
||||
} catch (OutOfMemoryError e) {
|
||||
// Expected exception
|
||||
}
|
||||
} else {
|
||||
System.out.println("Test only valid on 32-bit platforms");
|
||||
}
|
||||
}
|
||||
}
|
143
hotspot/test/runtime/RedefineTests/RedefineRunningMethods.java
Normal file
143
hotspot/test/runtime/RedefineTests/RedefineRunningMethods.java
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8055008
|
||||
* @summary Redefine EMCP and non-EMCP methods that are running in an infinite loop
|
||||
* @library /testlibrary
|
||||
* @build RedefineClassHelper
|
||||
* @run main RedefineClassHelper
|
||||
* @run main/othervm -javaagent:redefineagent.jar -XX:TraceRedefineClasses=0x600 RedefineRunningMethods
|
||||
*/
|
||||
public class RedefineRunningMethods {
|
||||
|
||||
public static String newB =
|
||||
"class RedefineRunningMethods$B {" +
|
||||
" static int count1 = 0;" +
|
||||
" static int count2 = 0;" +
|
||||
" public static volatile boolean stop = false;" +
|
||||
" static void localSleep() { " +
|
||||
" try{ " +
|
||||
" Thread.currentThread().sleep(10);" +
|
||||
" } catch(InterruptedException ie) { " +
|
||||
" } " +
|
||||
" } " +
|
||||
" public static void infinite() { " +
|
||||
" System.out.println(\"infinite called\");" +
|
||||
" }" +
|
||||
" public static void infinite_emcp() { " +
|
||||
" while (!stop) { count2++; localSleep(); }" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
public static String evenNewerB =
|
||||
"class RedefineRunningMethods$B {" +
|
||||
" static int count1 = 0;" +
|
||||
" static int count2 = 0;" +
|
||||
" public static volatile boolean stop = false;" +
|
||||
" static void localSleep() { " +
|
||||
" try{ " +
|
||||
" Thread.currentThread().sleep(1);" +
|
||||
" } catch(InterruptedException ie) { " +
|
||||
" } " +
|
||||
" } " +
|
||||
" public static void infinite() { }" +
|
||||
" public static void infinite_emcp() { " +
|
||||
" System.out.println(\"infinite_emcp now obsolete called\");" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
static class B {
|
||||
static int count1 = 0;
|
||||
static int count2 = 0;
|
||||
public static volatile boolean stop = false;
|
||||
static void localSleep() {
|
||||
try{
|
||||
Thread.currentThread().sleep(10);//sleep for 10 ms
|
||||
} catch(InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void infinite() {
|
||||
while (!stop) { count1++; localSleep(); }
|
||||
}
|
||||
public static void infinite_emcp() {
|
||||
while (!stop) { count2++; localSleep(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
new Thread() {
|
||||
public void run() {
|
||||
B.infinite();
|
||||
}
|
||||
}.start();
|
||||
|
||||
new Thread() {
|
||||
public void run() {
|
||||
B.infinite_emcp();
|
||||
}
|
||||
}.start();
|
||||
|
||||
RedefineClassHelper.redefineClass(B.class, newB);
|
||||
|
||||
System.gc();
|
||||
|
||||
B.infinite();
|
||||
|
||||
// Start a thread with the second version of infinite_emcp running
|
||||
new Thread() {
|
||||
public void run() {
|
||||
B.infinite_emcp();
|
||||
}
|
||||
}.start();
|
||||
|
||||
for (int i = 0; i < 20 ; i++) {
|
||||
String s = new String("some garbage");
|
||||
System.gc();
|
||||
}
|
||||
|
||||
RedefineClassHelper.redefineClass(B.class, evenNewerB);
|
||||
System.gc();
|
||||
|
||||
for (int i = 0; i < 20 ; i++) {
|
||||
B.infinite();
|
||||
String s = new String("some garbage");
|
||||
System.gc();
|
||||
}
|
||||
|
||||
B.infinite_emcp();
|
||||
|
||||
// purge should clean everything up.
|
||||
B.stop = true;
|
||||
|
||||
for (int i = 0; i < 20 ; i++) {
|
||||
B.infinite();
|
||||
String s = new String("some garbage");
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
}
|
@ -61,7 +61,7 @@ public class ArchiveDoesNotExist {
|
||||
"-version");
|
||||
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("java version");
|
||||
output.shouldMatch("(java|openjdk) version");
|
||||
output.shouldNotContain("sharing");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
139
hotspot/test/serviceability/dcmd/CodeCacheTest.java
Normal file
139
hotspot/test/serviceability/dcmd/CodeCacheTest.java
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test CodeCacheTest
|
||||
* @bug 8054889
|
||||
* @build DcmdUtil CodeCacheTest
|
||||
* @run main CodeCacheTest
|
||||
* @summary Test of diagnostic command Compiler.codecache
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class CodeCacheTest {
|
||||
|
||||
/**
|
||||
* This test calls Jcmd (diagnostic command tool) Compiler.codecache and then parses the output,
|
||||
* making sure that all number look ok
|
||||
*
|
||||
*
|
||||
* Expected output:
|
||||
*
|
||||
* CodeCache: size=245760Kb used=4680Kb max_used=4680Kb free=241079Kb
|
||||
* bounds [0x00007f5bd9000000, 0x00007f5bd94a0000, 0x00007f5be8000000]
|
||||
* total_blobs=575 nmethods=69 adapters=423
|
||||
* compilation: enabled
|
||||
*/
|
||||
|
||||
static Pattern line1 = Pattern.compile("CodeCache: size=(\\p{Digit}*)Kb used=(\\p{Digit}*)Kb max_used=(\\p{Digit}*)Kb free=(\\p{Digit}*)Kb");
|
||||
static Pattern line2 = Pattern.compile(" bounds \\[0x(\\p{XDigit}*), 0x(\\p{XDigit}*), 0x(\\p{XDigit}*)\\]");
|
||||
static Pattern line3 = Pattern.compile(" total_blobs=(\\p{Digit}*) nmethods=(\\p{Digit}*) adapters=(\\p{Digit}*)");
|
||||
static Pattern line4 = Pattern.compile(" compilation: (\\w*)");
|
||||
|
||||
public static void main(String arg[]) throws Exception {
|
||||
|
||||
// Get output from dcmd (diagnostic command)
|
||||
String result = DcmdUtil.executeDcmd("Compiler.codecache");
|
||||
BufferedReader r = new BufferedReader(new StringReader(result));
|
||||
|
||||
// Validate first line
|
||||
String line;
|
||||
line = r.readLine();
|
||||
Matcher m = line1.matcher(line);
|
||||
if (m.matches()) {
|
||||
for(int i = 1; i <= 4; i++) {
|
||||
int val = Integer.parseInt(m.group(i));
|
||||
if (val < 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Regexp 1 failed");
|
||||
}
|
||||
|
||||
// Validate second line
|
||||
line = r.readLine();
|
||||
m = line2.matcher(line);
|
||||
if (m.matches()) {
|
||||
long start = Long.parseLong(m.group(1), 16);
|
||||
if (start < 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
long mark = Long.parseLong(m.group(2), 16);
|
||||
if (mark < 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
long top = Long.parseLong(m.group(3), 16);
|
||||
if (top < 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
if (start > mark) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
if (mark > top) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Regexp 2 failed line: " + line);
|
||||
}
|
||||
|
||||
// Validate third line
|
||||
line = r.readLine();
|
||||
m = line3.matcher(line);
|
||||
if (m.matches()) {
|
||||
int blobs = Integer.parseInt(m.group(1));
|
||||
if (blobs <= 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
int nmethods = Integer.parseInt(m.group(2));
|
||||
if (nmethods <= 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
int adapters = Integer.parseInt(m.group(3));
|
||||
if (adapters <= 0) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
if (blobs < (nmethods + adapters)) {
|
||||
throw new Exception("Failed parsing dcmd codecache output");
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Regexp 3 failed");
|
||||
}
|
||||
|
||||
// Validate fourth line
|
||||
line = r.readLine();
|
||||
m = line4.matcher(line);
|
||||
if (m.matches()) {
|
||||
if (!m.group(1).equals("enabled")) {
|
||||
throw new Exception("Invalid message: '" + m.group(1) + "'");
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Regexp 4 failed");
|
||||
}
|
||||
}
|
||||
}
|
97
hotspot/test/serviceability/dcmd/CodelistTest.java
Normal file
97
hotspot/test/serviceability/dcmd/CodelistTest.java
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test CodelistTest
|
||||
* @bug 8054889
|
||||
* @build DcmdUtil MethodIdentifierParser CodelistTest
|
||||
* @run main CodelistTest
|
||||
* @summary Test of diagnostic command Compiler.codelist
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class CodelistTest {
|
||||
|
||||
/**
|
||||
* This test calls Jcmd (diagnostic command tool) Compiler.codelist and then parses the output,
|
||||
* making sure that the first methods in the list is valid by reflection.
|
||||
*
|
||||
* Output example:
|
||||
*
|
||||
* 6 0 java.lang.System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V [0x00007f7b49200910, 0x00007f7b49200aa0 - 0x00007f7b49200d30]
|
||||
* 2 3 java.lang.String.indexOf(II)I [0x00007f7b49200d90, 0x00007f7b49200f60 - 0x00007f7b49201490]
|
||||
* 7 3 java.lang.Math.min(II)I [0x00007f7b4922f010, 0x00007f7b4922f180 - 0x00007f7b4922f338]
|
||||
* 8 3 java.lang.String.equals(Ljava/lang/Object;)Z [0x00007f7b4922fb10, 0x00007f7b4922fd40 - 0x00007f7b49230698]
|
||||
* 9 3 java.lang.AbstractStringBuilder.ensureCapacityInternal(I)V [0x00007f7b49232010, 0x00007f7b492321a0 - 0x00007f7b49232510]
|
||||
* 10 1 java.lang.Object.<init>()V [0x00007f7b49233e90, 0x00007f7b49233fe0 - 0x00007f7b49234118]
|
||||
*
|
||||
*/
|
||||
|
||||
public static void main(String arg[]) throws Exception {
|
||||
int ok = 0;
|
||||
int fail = 0;
|
||||
|
||||
// Get output from dcmd (diagnostic command)
|
||||
String result = DcmdUtil.executeDcmd("Compiler.codelist");
|
||||
BufferedReader r = new BufferedReader(new StringReader(result));
|
||||
|
||||
// Grab a method name from the output
|
||||
String line;
|
||||
int count = 0;
|
||||
|
||||
while((line = r.readLine()) != null) {
|
||||
count++;
|
||||
|
||||
String[] parts = line.split(" ");
|
||||
// int compileID = Integer.parseInt(parts[0]);
|
||||
// int compileLevel = Integer.parseInt(parts[1]);
|
||||
String methodPrintedInLogFormat = parts[2];
|
||||
|
||||
// skip inits and clinits - they can not be reflected
|
||||
if (methodPrintedInLogFormat.contains("<init>")) {
|
||||
continue;
|
||||
}
|
||||
if (methodPrintedInLogFormat.contains("<clinit>")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodIdentifierParser mf = new MethodIdentifierParser(methodPrintedInLogFormat);
|
||||
Method m;
|
||||
try {
|
||||
m = mf.getMethod();
|
||||
} catch (NoSuchMethodException e) {
|
||||
m = null;
|
||||
}
|
||||
if (m == null) {
|
||||
throw new Exception("Test failed");
|
||||
}
|
||||
if (count > 10) {
|
||||
// Testing 10 entries is enough. Lets not waste time.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
108
hotspot/test/serviceability/dcmd/CompilerQueueTest.java
Normal file
108
hotspot/test/serviceability/dcmd/CompilerQueueTest.java
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test CompilerQueueTest
|
||||
* @bug 8054889
|
||||
* @build DcmdUtil CompilerQueueTest
|
||||
* @run main CompilerQueueTest
|
||||
* @summary Test of diagnostic command Compiler.queue
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.StringReader;
|
||||
|
||||
public class CompilerQueueTest {
|
||||
|
||||
/**
|
||||
* This test calls Jcmd (diagnostic command tool) Compiler.queue and
|
||||
* then parses the output, making sure that the output look ok.
|
||||
*
|
||||
*
|
||||
* Output example:
|
||||
*
|
||||
* Contents of C1 compile queue
|
||||
* ----------------------------
|
||||
* 73 3 java.lang.AbstractStringBuilder::append (50 bytes)
|
||||
* 74 1 java.util.TreeMap::size (5 bytes)
|
||||
* 75 3 java.lang.StringBuilder::append (8 bytes)
|
||||
* 83 3 java.util.TreeMap$ValueIterator::next (8 bytes)
|
||||
* 84 1 javax.management.MBeanFeatureInfo::getName (5 bytes)
|
||||
* ----------------------------
|
||||
* Contents of C2 compile queue
|
||||
* ----------------------------
|
||||
* Empty
|
||||
* ----------------------------
|
||||
*
|
||||
**/
|
||||
|
||||
public static void main(String arg[]) throws Exception {
|
||||
|
||||
// Get output from dcmd (diagnostic command)
|
||||
String result = DcmdUtil.executeDcmd("Compiler.queue");
|
||||
BufferedReader r = new BufferedReader(new StringReader(result));
|
||||
|
||||
String line;
|
||||
match(r.readLine(), "Contents of C1 compile queue");
|
||||
match(r.readLine(), "----------------------------");
|
||||
String str = r.readLine();
|
||||
if (!str.equals("Empty")) {
|
||||
while (str.charAt(0) != '-') {
|
||||
validateMethodLine(str);
|
||||
str = r.readLine();
|
||||
}
|
||||
} else {
|
||||
str = r.readLine();
|
||||
}
|
||||
|
||||
match(str, "----------------------------");
|
||||
match(r.readLine(), "Contents of C2 compile queue");
|
||||
match(r.readLine(), "----------------------------");
|
||||
str = r.readLine();
|
||||
if (!str.equals("Empty")) {
|
||||
while (str.charAt(0) != '-') {
|
||||
validateMethodLine(str);
|
||||
str = r.readLine();
|
||||
}
|
||||
} else {
|
||||
str = r.readLine();
|
||||
}
|
||||
match(str, "----------------------------");
|
||||
}
|
||||
|
||||
private static void validateMethodLine(String str) throws Exception {
|
||||
String name = str.substring(19);
|
||||
int sep = name.indexOf("::");
|
||||
try {
|
||||
Class.forName(name.substring(0, sep));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new Exception("Failed parsing dcmd queue");
|
||||
}
|
||||
}
|
||||
|
||||
public static void match(String line, String str) throws Exception {
|
||||
if (!line.equals(str)) {
|
||||
throw new Exception("String equals: " + line + ", " + str);
|
||||
}
|
||||
}
|
||||
}
|
196
hotspot/test/serviceability/dcmd/MethodIdentifierParser.java
Normal file
196
hotspot/test/serviceability/dcmd/MethodIdentifierParser.java
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MethodIdentifierParser {
|
||||
|
||||
private String logString;
|
||||
private String className;
|
||||
private String methodName;
|
||||
private String methodDescriptor;
|
||||
|
||||
/**
|
||||
* This is a utility class for parsing the log entries for a method. It supplies
|
||||
* a few select methods for reflecting the class and method from that information.
|
||||
*
|
||||
* Example log entries:
|
||||
* "java.util.TreeMap.successor(Ljava/util/TreeMap$Entry;)Ljava/util/TreeMap$Entry;"
|
||||
*/
|
||||
|
||||
public MethodIdentifierParser(String logString) {
|
||||
this.logString = logString;
|
||||
|
||||
int i = logString.lastIndexOf("."); // find start of method name
|
||||
className = logString.substring(0, i); // classname is everything before
|
||||
int i2 = logString.indexOf("("); // Signature starts with an '('
|
||||
methodName = logString.substring(i+1, i2);
|
||||
methodDescriptor = logString.substring(i2, logString.length());
|
||||
|
||||
// Add sanity check for extracted fields
|
||||
}
|
||||
|
||||
public Method getMethod() throws NoSuchMethodException, SecurityException, ClassNotFoundException, Exception {
|
||||
try {
|
||||
return Class.forName(className).getDeclaredMethod(methodName, getParamenterDescriptorArray());
|
||||
} catch (UnexpectedTokenException e) {
|
||||
throw new Exception("Parse failed");
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?>[] getParamenterDescriptorArray() throws ClassNotFoundException, UnexpectedTokenException {
|
||||
ParameterDecriptorIterator s = new ParameterDecriptorIterator(methodDescriptor);
|
||||
Class<?> paramType;
|
||||
ArrayList<Class<?>> list = new ArrayList<Class<?>>();
|
||||
while ((paramType = s.nextParamType()) != null) {
|
||||
list.add(paramType);
|
||||
}
|
||||
if (list.size() > 0) {
|
||||
return list.toArray(new Class<?>[list.size()]);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class ParameterDecriptorIterator {
|
||||
|
||||
// This class uses charAt() indexing for startMark and i
|
||||
// That is when i points to the last char it can be retrieved with
|
||||
// charAt(i). Including the last char for a subString requires
|
||||
// substring(startMark, i+1);
|
||||
|
||||
private String methodDescriptor;
|
||||
private int startMark;
|
||||
|
||||
public ParameterDecriptorIterator(String signature) {
|
||||
this.methodDescriptor = signature;
|
||||
this.startMark = 0;
|
||||
if (signature.charAt(0) == '(') {
|
||||
this.startMark = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> nextParamType() throws UnexpectedTokenException {
|
||||
int i = startMark;
|
||||
while (methodDescriptor.length() > i) {
|
||||
switch (methodDescriptor.charAt(i)) {
|
||||
case 'C':
|
||||
case 'B':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'Z':
|
||||
case 'F':
|
||||
case 'D':
|
||||
case 'S':
|
||||
// Primitive class case, but we may have gotten here with [ as first token
|
||||
break;
|
||||
case 'L':
|
||||
// Internal class name suffixed by ';'
|
||||
while (methodDescriptor.charAt(i) != ';') {
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
case '[':
|
||||
i++; // arrays -> do another pass
|
||||
continue;
|
||||
case ')':
|
||||
return null; // end found
|
||||
case 'V':
|
||||
case ';':
|
||||
default:
|
||||
throw new UnexpectedTokenException(methodDescriptor, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i == startMark) {
|
||||
// Single char -> primitive class case
|
||||
startMark++; // Update for next iteration
|
||||
switch (methodDescriptor.charAt(i)) {
|
||||
case 'C':
|
||||
return char.class;
|
||||
case 'B':
|
||||
return byte.class;
|
||||
case 'I':
|
||||
return int.class;
|
||||
case 'J':
|
||||
return long.class;
|
||||
case 'F':
|
||||
return float.class;
|
||||
case 'D':
|
||||
return double.class;
|
||||
case 'S':
|
||||
return short.class;
|
||||
case 'Z':
|
||||
return boolean.class;
|
||||
default:
|
||||
throw new UnexpectedTokenException(methodDescriptor, i);
|
||||
}
|
||||
} else {
|
||||
// Multi char case
|
||||
String nextParam;
|
||||
if (methodDescriptor.charAt(startMark) == 'L') {
|
||||
// When reflecting a class the leading 'L' and trailing';' must be removed.
|
||||
// (When reflecting an array of classes, they must remain...)
|
||||
nextParam = methodDescriptor.substring(startMark+1, i);
|
||||
} else {
|
||||
// Any kind of array - simple case, use whole descriptor when reflecting.
|
||||
nextParam = methodDescriptor.substring(startMark, i+1);
|
||||
}
|
||||
startMark = ++i; // Update for next iteration
|
||||
try {
|
||||
// The parameter descriptor uses JVM internal class identifier with '/' as
|
||||
// package separator, but Class.forName expects '.'.
|
||||
nextParam = nextParam.replace('/', '.');
|
||||
return Class.forName(nextParam);
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.out.println("Class not Found: " + nextParam);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnexpectedTokenException extends Exception {
|
||||
String descriptor;
|
||||
int i;
|
||||
public UnexpectedTokenException(String descriptor, int i) {
|
||||
this.descriptor = descriptor;
|
||||
this.i = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Unexpected token at: " + i + " in signature: " + descriptor;
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
|
||||
public void debugPrint() {
|
||||
System.out.println("mlf in: " + logString);
|
||||
System.out.println("mlf class: " + className);
|
||||
System.out.println("mlf method: " + methodName);
|
||||
System.out.println("mlf methodDescriptor: " + methodDescriptor);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user