diff --git a/.hgtags b/.hgtags index a9f3d0f406a..3fe829ce922 100644 --- a/.hgtags +++ b/.hgtags @@ -79,3 +79,6 @@ c4c8a5bc54f66abc68cd185d9294042121922154 jdk7-b99 88db80c8e49cea352c2900f689600dc410761c1f jdk7-b102 64770970865839b0443066370e7d476ef47e90cd jdk7-b103 10bc903a228d3a8efdf46fb8c3fcf82a59b88bc5 jdk7-b104 +1ce7938efb03224ccc8b3cdd7803eb39e889539c jdk7-b105 +6bdae472f77205046703b685eff2ac4f7a0ecf4e jdk7-b106 +439de530aac531a360beedba6e2fe51e17292cc0 jdk7-b107 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 9bf4e58dcf0..c533bdc1115 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -79,3 +79,6 @@ b218a53ec7d3d42be61d31d6917a6c5c037b6f56 jdk7-b100 a136a51f5113da4dad3853b74a8536ab583ab112 jdk7-b102 be2aedc4e3b1751c1310f334242ba69e90867f38 jdk7-b103 f8be576feefce0c6695f188ef97ec16b73ad9cfd jdk7-b104 +9f96a4269d7727dad68864eaab795eafce270311 jdk7-b105 +43096cccf1cee749c2f4e7714ee71f4e9e0f4d7f jdk7-b106 +7d396ad455c3b2f68b0d7094891c5aba7c757a6e jdk7-b107 diff --git a/corba/.hgtags b/corba/.hgtags index ffebb61ccdc..6eac1b642e0 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -79,3 +79,6 @@ a56d734a1e970e1a21a8f4feb13053e9a33674c7 jdk7-b100 78561a95779090b5106c8d0f1a75360a027ef087 jdk7-b102 11e7678c3eb169b77d9a9892fe5e3dfa1d1a0d51 jdk7-b103 9607213481d400ac477183191cc080e1bef6f475 jdk7-b104 +6f21b030092fb61244cc8a0aedf8058f7c022b81 jdk7-b105 +519daea48888196af76a975a3b31258efa860bad jdk7-b106 +232adb83eae8375439ccff65b6e205ca0da0510d jdk7-b107 diff --git a/hotspot/.hgtags b/hotspot/.hgtags index e28f5ca8355..8fc773e9e0a 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -110,3 +110,8 @@ c5cadf1a07717955cf60dbaec16e35b529fd2cb0 jdk7-b102 cb4250ef73b21de6c487ea14e2b0b99eed67b4b6 jdk7-b103 e55900b5c1b865cac17e18abc639c7dc50de7fd8 hs19-b04 b4acf10eb134fe930802c97e36db65e7ccb544b5 jdk7-b104 +6709c14587c2cc6faca208767335afeb01e33de5 jdk7-b105 +1b81ca701fa5fc30adc4cfdaa4bdd153df5e6c86 jdk7-b106 +cc3fdfeb54b049f18edcf3463e6ab051d0b7b609 hs19-b05 +688a538aa65412178286ae2a6b0c00b6711e121b hs19-b06 +bf496cbe9b74dda5975a1559da7ecfdd313e509e jdk7-b107 diff --git a/hotspot/agent/src/os/linux/ps_proc.c b/hotspot/agent/src/os/linux/ps_proc.c index ef3ab89e6b6..5ad3ff7f367 100644 --- a/hotspot/agent/src/os/linux/ps_proc.c +++ b/hotspot/agent/src/os/linux/ps_proc.c @@ -253,7 +253,11 @@ static bool read_lib_info(struct ps_prochandle* ph) { if (nwords > 5 && find_lib(ph, word[5]) == false) { intptr_t base; lib_info* lib; +#ifdef _LP64 sscanf(word[0], "%lx", &base); +#else + sscanf(word[0], "%x", &base); +#endif if ((lib = add_lib_info(ph, word[5], (uintptr_t)base)) == NULL) continue; // ignore, add_lib_info prints error diff --git a/hotspot/make/Makefile b/hotspot/make/Makefile index 130a73cdb2c..e55408cc484 100644 --- a/hotspot/make/Makefile +++ b/hotspot/make/Makefile @@ -85,14 +85,21 @@ C1_VM_TARGETS=product1 fastdebug1 optimized1 jvmg1 C2_VM_TARGETS=product fastdebug optimized jvmg KERNEL_VM_TARGETS=productkernel fastdebugkernel optimizedkernel jvmgkernel ZERO_VM_TARGETS=productzero fastdebugzero optimizedzero jvmgzero +SHARK_VM_TARGETS=productshark fastdebugshark optimizedshark jvmgshark # JDK directory list JDK_DIRS=bin include jre lib demo all: all_product all_fastdebug +ifndef BUILD_CLIENT_ONLY all_product: product product1 productkernel docs export_product all_fastdebug: fastdebug fastdebug1 fastdebugkernel docs export_fastdebug all_debug: jvmg jvmg1 jvmgkernel docs export_debug +else +all_product: product1 docs export_product +all_fastdebug: fastdebug1 docs export_fastdebug +all_debug: jvmg1 docs export_debug +endif all_optimized: optimized optimized1 optimizedkernel docs export_optimized allzero: all_productzero all_fastdebugzero @@ -101,6 +108,12 @@ all_fastdebugzero: fastdebugzero docs export_fastdebug all_debugzero: jvmgzero docs export_debug all_optimizedzero: optimizedzero docs export_optimized +allshark: all_productshark all_fastdebugshark +all_productshark: productshark docs export_product +all_fastdebugshark: fastdebugshark docs export_fastdebug +all_debugshark: jvmgshark docs export_debug +all_optimizedshark: optimizedshark docs export_optimized + # Do everything world: all create_jdk @@ -131,6 +144,10 @@ $(ZERO_VM_TARGETS): $(CD) $(GAMMADIR)/make; \ $(MAKE) VM_TARGET=$@ generic_buildzero $(ALT_OUT) +$(SHARK_VM_TARGETS): + $(CD) $(GAMMADIR)/make; \ + $(MAKE) VM_TARGET=$@ generic_buildshark $(ALT_OUT) + # Build compiler1 (client) rule, different for platforms generic_build1: $(MKDIR) -p $(OUTPUTDIR) @@ -197,6 +214,12 @@ generic_buildzero: $(MAKE) -f $(ABS_OS_MAKEFILE) \ $(MAKE_ARGS) $(VM_TARGET) +generic_buildshark: + $(MKDIR) -p $(OUTPUTDIR) + $(CD) $(OUTPUTDIR); \ + $(MAKE) -f $(ABS_OS_MAKEFILE) \ + $(MAKE_ARGS) $(VM_TARGET) + # Export file rule generic_export: $(EXPORT_LIST) export_product: @@ -228,15 +251,22 @@ C1_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_compiler1 C2_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_compiler2 KERNEL_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_kernel ZERO_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_zero +SHARK_BASE_DIR=$(OUTPUTDIR)/$(VM_PLATFORM)_shark C1_DIR=$(C1_BASE_DIR)/$(VM_SUBDIR) C2_DIR=$(C2_BASE_DIR)/$(VM_SUBDIR) KERNEL_DIR=$(KERNEL_BASE_DIR)/$(VM_SUBDIR) ZERO_DIR=$(ZERO_BASE_DIR)/$(VM_SUBDIR) +SHARK_DIR=$(SHARK_BASE_DIR)/$(VM_SUBDIR) # Misc files and generated files need to come from C1 or C2 area ifeq ($(ZERO_BUILD), true) +ifeq ($(SHARK_BUILD), true) + MISC_DIR=$(SHARK_DIR) + GEN_DIR=$(SHARK_BASE_DIR)/generated +else MISC_DIR=$(ZERO_DIR) GEN_DIR=$(ZERO_BASE_DIR)/generated +endif else ifeq ($(ARCH_DATA_MODEL), 32) MISC_DIR=$(C1_DIR) @@ -290,11 +320,20 @@ endif # Shared Library ifneq ($(OSNAME),windows) ifeq ($(ZERO_BUILD), true) + ifeq ($(SHARK_BUILD), true) +$(EXPORT_JRE_LIB_ARCH_DIR)/%.so: $(SHARK_DIR)/%.so + $(install-file) +$(EXPORT_SERVER_DIR)/%.so: $(SHARK_DIR)/%.so + $(install-file) + else $(EXPORT_JRE_LIB_ARCH_DIR)/%.so: $(ZERO_DIR)/%.so $(install-file) $(EXPORT_SERVER_DIR)/%.so: $(ZERO_DIR)/%.so $(install-file) + endif else +$(EXPORT_JRE_LIB_ARCH_DIR)/%.so: $(C1_DIR)/%.so + $(install-file) $(EXPORT_JRE_LIB_ARCH_DIR)/%.so: $(C2_DIR)/%.so $(install-file) $(EXPORT_CLIENT_DIR)/%.so: $(C1_DIR)/%.so @@ -348,6 +387,7 @@ clean_build: $(RM) -r $(C2_DIR) $(RM) -r $(KERNEL_DIR) $(RM) -r $(ZERO_DIR) + $(RM) -r $(SHARK_DIR) clean_export: $(RM) -r $(EXPORT_PATH) clean_jdk: diff --git a/hotspot/make/defs.make b/hotspot/make/defs.make index be4eda0f1c5..528d9405bf8 100644 --- a/hotspot/make/defs.make +++ b/hotspot/make/defs.make @@ -192,13 +192,16 @@ ifneq ($(OSNAME),windows) # Use uname output for SRCARCH, but deal with platform differences. If ARCH # is not explicitly listed below, it is treated as x86. - SRCARCH = $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 zero,$(ARCH))) + SRCARCH = $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 arm ppc zero,$(ARCH))) ARCH/ = x86 ARCH/sparc = sparc ARCH/sparc64= sparc ARCH/ia64 = ia64 ARCH/amd64 = x86 ARCH/x86_64 = x86 + ARCH/ppc64 = ppc + ARCH/ppc = ppc + ARCH/arm = arm ARCH/zero = zero # BUILDARCH is usually the same as SRCARCH, except for sparcv9 @@ -223,6 +226,9 @@ ifneq ($(OSNAME),windows) LIBARCH/sparc = sparc LIBARCH/sparcv9 = sparcv9 LIBARCH/ia64 = ia64 + LIBARCH/ppc64 = ppc + LIBARCH/ppc = ppc + LIBARCH/arm = arm LIBARCH/zero = $(ZERO_LIBARCH) LP64_ARCH = sparcv9 amd64 ia64 zero diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index e2f63f0f86c..dae71d920fb 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2010 HS_MAJOR_VER=19 HS_MINOR_VER=0 -HS_BUILD_NUMBER=05 +HS_BUILD_NUMBER=06 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index 6d6a1cf4e50..e671c4bf94a 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -168,6 +168,13 @@ VARIANTARCH = $(subst i386,i486,$(ZERO_LIBARCH)) # profiledzero zero __zero/profiled # productzero zero __zero/product # +# debugshark shark __shark/debug +# fastdebugshark shark __shark/fastdebug +# jvmgshark shark __shark/jvmg +# optimizedshark shark __shark/optimized +# profiledshark shark __shark/profiled +# productshark shark __shark/product +# # What you get with each target: # # debug* - "thin" libjvm_g - debug info linked into the gamma_g launcher @@ -191,12 +198,14 @@ SUBDIRS_C2 = $(addprefix $(OSNAME)_$(BUILDARCH)_compiler2/,$(TARGETS)) SUBDIRS_TIERED = $(addprefix $(OSNAME)_$(BUILDARCH)_tiered/,$(TARGETS)) SUBDIRS_CORE = $(addprefix $(OSNAME)_$(BUILDARCH)_core/,$(TARGETS)) SUBDIRS_ZERO = $(addprefix $(OSNAME)_$(VARIANTARCH)_zero/,$(TARGETS)) +SUBDIRS_SHARK = $(addprefix $(OSNAME)_$(VARIANTARCH)_shark/,$(TARGETS)) TARGETS_C2 = $(TARGETS) TARGETS_C1 = $(addsuffix 1,$(TARGETS)) TARGETS_TIERED = $(addsuffix tiered,$(TARGETS)) TARGETS_CORE = $(addsuffix core,$(TARGETS)) TARGETS_ZERO = $(addsuffix zero,$(TARGETS)) +TARGETS_SHARK = $(addsuffix shark,$(TARGETS)) BUILDTREE_MAKE = $(GAMMADIR)/make/$(OSNAME)/makefiles/buildtree.make BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OSNAME) ARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) @@ -213,6 +222,7 @@ all: @echo " $(TARGETS_C1)" @echo " $(TARGETS_CORE)" @echo " $(TARGETS_ZERO)" + @echo " $(TARGETS_SHARK)" checks: check_os_version check_j2se_version @@ -266,6 +276,10 @@ $(SUBDIRS_ZERO): $(BUILDTREE_MAKE) platform_zero $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks $(BUILDTREE) VARIANT=zero VARIANTARCH=$(VARIANTARCH) +$(SUBDIRS_SHARK): $(BUILDTREE_MAKE) platform_zero + $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks + $(BUILDTREE) VARIANT=shark VARIANTARCH=$(VARIANTARCH) + platform_zero: $(GAMMADIR)/make/$(OSNAME)/platform_zero.in $(SED) 's/@ZERO_ARCHDEF@/$(ZERO_ARCHDEF)/g;s/@ZERO_LIBARCH@/$(ZERO_LIBARCH)/g;' < $< > $@ @@ -306,11 +320,19 @@ ifdef INSTALL cd $(OSNAME)_$(VARIANTARCH)_zero/$(patsubst %zero,%,$@) && $(MAKE) $(MFLAGS) install endif +$(TARGETS_SHARK): $(SUBDIRS_SHARK) + cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) + cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && ./test_gamma +ifdef INSTALL + cd $(OSNAME)_$(VARIANTARCH)_shark/$(patsubst %shark,%,$@) && $(MAKE) $(MFLAGS) install +endif + # Just build the tree, and nothing else: tree: $(SUBDIRS_C2) tree1: $(SUBDIRS_C1) treecore: $(SUBDIRS_CORE) treezero: $(SUBDIRS_ZERO) +treeshark: $(SUBDIRS_SHARK) # Doc target. This is the same for all build options. # Hence create a docs directory beside ...$(ARCH)_[...] @@ -327,20 +349,22 @@ core: jvmgcore productcore zero: jvmgzero productzero +shark: jvmgshark productshark + clean_docs: rm -rf $(SUBDIR_DOCS) -clean_compiler1 clean_compiler2 clean_core clean_zero: +clean_compiler1 clean_compiler2 clean_core clean_zero clean_shark: rm -rf $(OSNAME)_$(BUILDARCH)_$(subst clean_,,$@) -clean: clean_compiler2 clean_compiler1 clean_core clean_zero clean_docs +clean: clean_compiler2 clean_compiler1 clean_core clean_zero clean_shark clean_docs include $(GAMMADIR)/make/$(OSNAME)/makefiles/cscope.make #------------------------------------------------------------------------------- -.PHONY: $(TARGETS_C2) $(TARGETS_C1) $(TARGETS_CORE) $(TARGETS_ZERO) -.PHONY: tree tree1 treecore treezero -.PHONY: all compiler1 compiler2 core zero -.PHONY: clean clean_compiler1 clean_compiler2 clean_core clean_zero docs clean_docs +.PHONY: $(TARGETS_C2) $(TARGETS_C1) $(TARGETS_CORE) $(TARGETS_ZERO) $(TARGETS_SHARK) +.PHONY: tree tree1 treecore treezero treeshark +.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 diff --git a/hotspot/make/linux/makefiles/build_vm_def.sh b/hotspot/make/linux/makefiles/build_vm_def.sh index 51a07b9bfa2..2b6f906eee8 100644 --- a/hotspot/make/linux/makefiles/build_vm_def.sh +++ b/hotspot/make/linux/makefiles/build_vm_def.sh @@ -1,5 +1,12 @@ #!/bin/sh -nm --defined-only $* | awk ' +# If we're cross compiling use that path for nm +if [ "$ALT_COMPILER_PATH" != "" ]; then +NM=$ALT_COMPILER_PATH/nm +else +NM=nm +fi + +$NM --defined-only $* | awk ' { if ($3 ~ /^_ZTV/ || $3 ~ /^gHotSpotVM/) print "\t" $3 ";" } ' diff --git a/hotspot/make/linux/makefiles/buildtree.make b/hotspot/make/linux/makefiles/buildtree.make index b7ce6513c98..af34617f46c 100644 --- a/hotspot/make/linux/makefiles/buildtree.make +++ b/hotspot/make/linux/makefiles/buildtree.make @@ -339,12 +339,16 @@ JAVA_FLAG/64 = -d64 WRONG_DATA_MODE_MSG = \ echo "JAVA_HOME must point to $(DATA_MODE)bit JDK." +CROSS_COMPILING_MSG = \ + echo "Cross compiling for ARCH $(CROSS_COMPILE_ARCH), skipping gamma run." + test_gamma: $(BUILDTREE_MAKE) $(GAMMADIR)/make/test/Queens.java @echo Creating $@ ... $(QUIETLY) ( \ echo '#!/bin/sh'; \ $(BUILDTREE_COMMENT); \ echo '. ./env.sh'; \ + echo "if [ \"$(CROSS_COMPILE_ARCH)\" != \"\" ]; then { $(CROSS_COMPILING_MSG); exit 0; }; fi"; \ echo "if [ -z \$$JAVA_HOME ]; then { $(NO_JAVA_HOME_MSG); exit 0; }; fi"; \ echo "if ! \$${JAVA_HOME}/bin/java $(JAVA_FLAG) -fullversion 2>&1 > /dev/null"; \ echo "then"; \ diff --git a/hotspot/make/linux/makefiles/defs.make b/hotspot/make/linux/makefiles/defs.make index 29ef407adb1..561f7f58107 100644 --- a/hotspot/make/linux/makefiles/defs.make +++ b/hotspot/make/linux/makefiles/defs.make @@ -98,6 +98,22 @@ ifeq ($(ARCH), i686) HS_ARCH = x86 endif +# ARM +ifeq ($(ARCH), arm) + ARCH_DATA_MODEL = 32 + PLATFORM = linux-arm + VM_PLATFORM = linux_arm + HS_ARCH = arm +endif + +# PPC +ifeq ($(ARCH), ppc) + ARCH_DATA_MODEL = 32 + PLATFORM = linux-ppc + VM_PLATFORM = linux_ppc + HS_ARCH = ppc +endif + JDK_INCLUDE_SUBDIR=linux # FIXUP: The subdirectory for a debug build is NOT the same on all platforms @@ -107,22 +123,32 @@ EXPORT_LIST += $(EXPORT_DOCS_DIR)/platform/jvmti/jvmti.html # client and server subdirectories have symbolic links to ../libjsig.so EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.so - EXPORT_SERVER_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/server + +ifndef BUILD_CLIENT_ONLY EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.so +endif + ifneq ($(ZERO_BUILD), true) ifeq ($(ARCH_DATA_MODEL), 32) EXPORT_CLIENT_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/client EXPORT_LIST += $(EXPORT_CLIENT_DIR)/Xusage.txt EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm.so - EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.so - EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar - else - ifeq ($(ARCH),ia64) - else - EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.so - EXPORT_LIST += $(EXPORT_LIB_DIR)/sa-jdi.jar - endif endif endif + +# Serviceability Binaries +# No SA Support for PPC, IA64, ARM or zero +ADD_SA_BINARIES/x86 = $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.so \ + $(EXPORT_LIB_DIR)/sa-jdi.jar +ADD_SA_BINARIES/sparc = $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.so \ + $(EXPORT_LIB_DIR)/sa-jdi.jar +ADD_SA_BINARIES/ppc = +ADD_SA_BINARIES/ia64 = +ADD_SA_BINARIES/arm = +ADD_SA_BINARIES/zero = + +EXPORT_LIST += $(ADD_SA_BINARIES/$(HS_ARCH)) + + diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index e7ed00e9137..7107858f7d9 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,14 @@ #------------------------------------------------------------------------ # CC, CPP & AS +ifdef ALT_COMPILER_PATH +CPP = $(ALT_COMPILER_PATH)/g++ +CC = $(ALT_COMPILER_PATH)/gcc +else CPP = g++ CC = gcc +endif + AS = $(CC) -c # -dumpversion in gcc-2.91 shows "egcs-2.91.66". In later version, it only @@ -55,6 +61,9 @@ VM_PICFLAG = $(VM_PICFLAG/$(LINK_INTO)) ifeq ($(ZERO_BUILD), true) CFLAGS += $(LIBFFI_CFLAGS) endif +ifeq ($(SHARK_BUILD), true) +CFLAGS += $(LLVM_CFLAGS) +endif CFLAGS += $(VM_PICFLAG) CFLAGS += -fno-rtti CFLAGS += -fno-exceptions @@ -67,18 +76,31 @@ ARCHFLAG/amd64 = -m64 ARCHFLAG/ia64 = ARCHFLAG/sparc = -m32 -mcpu=v9 ARCHFLAG/sparcv9 = -m64 -mcpu=v9 +ARCHFLAG/arm = -fsigned-char ARCHFLAG/zero = $(ZERO_ARCHFLAG) +ifndef E500V2 +ARCHFLAG/ppc = -mcpu=powerpc +endif CFLAGS += $(ARCHFLAG) AOUT_FLAGS += $(ARCHFLAG) LFLAGS += $(ARCHFLAG) ASFLAGS += $(ARCHFLAG) +ifdef E500V2 +CFLAGS += -DE500V2 +endif + # Use C++ Interpreter ifdef CC_INTERP CFLAGS += -DCC_INTERP endif +# Build for embedded targets +ifdef JAVASE_EMBEDDED + CFLAGS += -DJAVASE_EMBEDDED +endif + # Keep temporary files (.ii, .s) ifdef NEED_ASM CFLAGS += -save-temps @@ -171,6 +193,8 @@ AOUT_FLAGS += -export-dynamic # Note: The Itanium gcc compiler crashes when using -gstabs. DEBUG_CFLAGS/ia64 = -g DEBUG_CFLAGS/amd64 = -g +DEBUG_CFLAGS/arm = -g +DEBUG_CFLAGS/ppc = -g DEBUG_CFLAGS += $(DEBUG_CFLAGS/$(BUILDARCH)) ifeq ($(DEBUG_CFLAGS/$(BUILDARCH)),) DEBUG_CFLAGS += -gstabs @@ -181,3 +205,15 @@ ifeq ($(DEBUG_BINARIES), true) DEBUG_CFLAGS = -g CFLAGS += $(DEBUG_CFLAGS) endif + +# If we are building HEADLESS, pass on to VM +# so it can set the java.awt.headless property +ifdef HEADLESS +CFLAGS += -DHEADLESS +endif + +# We are building Embedded for a small device +# favor code space over speed +ifdef MINIMIZE_RAM_USAGE +CFLAGS += -DMINIMIZE_RAM_USAGE +endif diff --git a/hotspot/make/linux/makefiles/product.make b/hotspot/make/linux/makefiles/product.make index 82ed58a1fcd..ff768b6a6bd 100644 --- a/hotspot/make/linux/makefiles/product.make +++ b/hotspot/make/linux/makefiles/product.make @@ -46,7 +46,11 @@ VERSION = optimized # use -g to strip library as -x will discard its symbol table; -x is fine for # executables. -STRIP = strip +ifdef CROSS_COMPILE_ARCH + STRIP = $(ALT_COMPILER_PATH)/strip +else + STRIP = strip +endif STRIP_LIBJVM = $(STRIP) -g $@ || exit 1; STRIP_AOUT = $(STRIP) -x $@ || exit 1; diff --git a/hotspot/make/linux/makefiles/sa.make b/hotspot/make/linux/makefiles/sa.make index f7a1a208ba7..19d68083ede 100644 --- a/hotspot/make/linux/makefiles/sa.make +++ b/hotspot/make/linux/makefiles/sa.make @@ -55,10 +55,13 @@ SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VE SA_PROPERTIES = $(SA_CLASSDIR)/sa.properties # if $(AGENT_DIR) does not exist, we don't build SA -# also, we don't build SA on Itanium or zero. +# also, we don't build SA on Itanium, PowerPC, ARM or zero. all: - if [ -d $(AGENT_DIR) -a "$(SRCARCH)" != "ia64" -a "$(SRCARCH)" != "zero" ] ; then \ + if [ -d $(AGENT_DIR) -a "$(SRCARCH)" != "ia64" \ + -a "$(SRCARCH)" != "arm" \ + -a "$(SRCARCH)" != "ppc" \ + -a "$(SRCARCH)" != "zero" ] ; then \ $(MAKE) -f sa.make $(GENERATED)/sa-jdi.jar; \ fi diff --git a/hotspot/make/linux/makefiles/saproc.make b/hotspot/make/linux/makefiles/saproc.make index 1da5c217d07..bc4fc66c5fa 100644 --- a/hotspot/make/linux/makefiles/saproc.make +++ b/hotspot/make/linux/makefiles/saproc.make @@ -53,10 +53,10 @@ ifeq ($(DEBUG_BINARIES), true) endif # if $(AGENT_DIR) does not exist, we don't build SA -# also, we don't build SA on Itanium or zero. +# also, we don't build SA on Itanium, PPC, ARM or zero. checkAndBuildSA: - $(QUIETLY) if [ -d $(AGENT_DIR) -a "$(SRCARCH)" != "ia64" -a "$(SRCARCH)" != "zero" ] ; then \ + $(QUIETLY) if [ -d $(AGENT_DIR) -a "$(SRCARCH)" != "ia64" -a "$(SRCARCH)" != "arm" -a "$(SRCARCH)" != "ppc" -a "$(SRCARCH)" != "zero" ] ; then \ $(MAKE) -f vm.make $(LIBSAPROC); \ fi diff --git a/hotspot/make/linux/makefiles/shark.make b/hotspot/make/linux/makefiles/shark.make new file mode 100644 index 00000000000..f767a805039 --- /dev/null +++ b/hotspot/make/linux/makefiles/shark.make @@ -0,0 +1,32 @@ +# +# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright 2008, 2010 Red Hat, Inc. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# + +# Sets make macros for making Shark version of VM + +TYPE = SHARK + +VM_SUBDIR = server + +CFLAGS += -DSHARK diff --git a/hotspot/make/linux/makefiles/top.make b/hotspot/make/linux/makefiles/top.make index 393040d7e0d..c9988f6aba7 100644 --- a/hotspot/make/linux/makefiles/top.make +++ b/hotspot/make/linux/makefiles/top.make @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -75,6 +75,7 @@ Include_DBs/COMPILER1 = $(Include_DBs/CORE) $(VM)/includeDB_compiler1 Include_DBs/COMPILER2 = $(Include_DBs/CORE) $(VM)/includeDB_compiler2 Include_DBs/TIERED = $(Include_DBs/CORE) $(VM)/includeDB_compiler1 $(VM)/includeDB_compiler2 Include_DBs/ZERO = $(Include_DBs/CORE) $(VM)/includeDB_zero +Include_DBs/SHARK = $(Include_DBs/ZERO) $(VM)/includeDB_shark Include_DBs = $(Include_DBs/$(TYPE)) Cached_plat = $(GENERATED)/platform.current diff --git a/hotspot/make/linux/makefiles/vm.make b/hotspot/make/linux/makefiles/vm.make index 0f8bccd2a16..92add561f09 100644 --- a/hotspot/make/linux/makefiles/vm.make +++ b/hotspot/make/linux/makefiles/vm.make @@ -1,5 +1,5 @@ # -# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -98,6 +98,7 @@ CFLAGS += $(CFLAGS/NOEX) # Extra flags from gnumake's invocation or environment CFLAGS += $(EXTRA_CFLAGS) +LFLAGS += $(EXTRA_CFLAGS) LIBS += -lm -ldl -lpthread @@ -136,10 +137,14 @@ mapfile_reorder : mapfile $(REORDERFILE) vm.def: $(Res_Files) $(Obj_Files) sh $(GAMMADIR)/make/linux/makefiles/build_vm_def.sh *.o > $@ -ifeq ($(ZERO_LIBARCH), ppc64) +ifeq ($(SHARK_BUILD), true) STATIC_CXX = false else - STATIC_CXX = true + ifeq ($(ZERO_LIBARCH), ppc64) + STATIC_CXX = false + else + STATIC_CXX = true + endif endif ifeq ($(LINK_INTO),AOUT) @@ -167,6 +172,10 @@ endif ifeq ($(ZERO_BUILD), true) LIBS_VM += $(LIBFFI_LIBS) endif +ifeq ($(SHARK_BUILD), true) + LFLAGS_VM += $(LLVM_LDFLAGS) + LIBS_VM += $(LLVM_LIBS) +endif LINK_VM = $(LINK_LIB.c) @@ -210,15 +219,17 @@ $(LIBJVM): $(LIBJVM.o) $(LIBJVM_MAPFILE) $(LD_SCRIPT) $(LINK_LIB.CC/POST_HOOK) \ rm -f $@.1; ln -s $@ $@.1; \ [ -f $(LIBJVM_G) ] || { ln -s $@ $(LIBJVM_G); ln -s $@.1 $(LIBJVM_G).1; }; \ - if [ -x /usr/sbin/selinuxenabled ] ; then \ - /usr/sbin/selinuxenabled; \ - if [ $$? = 0 ] ; then \ - /usr/bin/chcon -t textrel_shlib_t $@; \ - if [ $$? != 0 ]; then \ - echo "ERROR: Cannot chcon $@"; \ - fi \ - fi \ - fi \ + if [ \"$(CROSS_COMPILE_ARCH)\" = \"\" ] ; then \ + if [ -x /usr/sbin/selinuxenabled ] ; then \ + /usr/sbin/selinuxenabled; \ + if [ $$? = 0 ] ; then \ + /usr/bin/chcon -t textrel_shlib_t $@; \ + if [ $$? != 0 ]; then \ + echo "ERROR: Cannot chcon $@"; \ + fi \ + fi \ + fi \ + fi \ } DEST_JVM = $(JDK_LIBDIR)/$(VM_SUBDIR)/$(LIBJVM) diff --git a/hotspot/make/solaris/makefiles/defs.make b/hotspot/make/solaris/makefiles/defs.make index 9e1d981cee0..637b3b49c54 100644 --- a/hotspot/make/solaris/makefiles/defs.make +++ b/hotspot/make/solaris/makefiles/defs.make @@ -70,20 +70,24 @@ EXPORT_LIST += $(EXPORT_DOCS_DIR)/platform/jvmti/jvmti.html EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libjsig.so EXPORT_SERVER_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/server +ifneq ($(BUILD_CLIENT_ONLY),true) EXPORT_LIST += $(EXPORT_SERVER_DIR)/Xusage.txt EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.so EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_db.so EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_dtrace.so +endif ifeq ($(ARCH_DATA_MODEL), 32) EXPORT_CLIENT_DIR = $(EXPORT_JRE_LIB_ARCH_DIR)/client EXPORT_LIST += $(EXPORT_CLIENT_DIR)/Xusage.txt EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm.so EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm_db.so - EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm_dtrace.so - EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_db.so + EXPORT_LIST += $(EXPORT_CLIENT_DIR)/libjvm_dtrace.so EXPORT_LIST += $(EXPORT_CLIENT_DIR)/64/libjvm_db.so - EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_dtrace.so EXPORT_LIST += $(EXPORT_CLIENT_DIR)/64/libjvm_dtrace.so + ifneq ($(BUILD_CLIENT_ONLY), true) + EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_db.so + EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_dtrace.so + endif endif EXPORT_LIST += $(EXPORT_JRE_LIB_ARCH_DIR)/libsaproc.so diff --git a/hotspot/make/solaris/makefiles/sparcWorks.make b/hotspot/make/solaris/makefiles/sparcWorks.make index a8beca11226..34b279b7266 100644 --- a/hotspot/make/solaris/makefiles/sparcWorks.make +++ b/hotspot/make/solaris/makefiles/sparcWorks.make @@ -145,11 +145,20 @@ OPT_CFLAGS/SLOWER=-xO3 OPT_CFLAGS/O2=-xO2 OPT_CFLAGS/NOOPT=-xO1 +################################################# +# Begin current (>=5.9) Forte compiler options # +################################################# + ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 509), 1) ifeq ($(Platform_arch), x86) OPT_CFLAGS/NO_TAIL_CALL_OPT = -Wu,-O~yz OPT_CCFLAGS/NO_TAIL_CALL_OPT = -Qoption ube -O~yz +OPT_CFLAGS/stubGenerator_x86_32.o = $(OPT_CFLAGS) -xspace +OPT_CFLAGS/stubGenerator_x86_64.o = $(OPT_CFLAGS) -xspace endif # Platform_arch == x86 +ifeq ("${Platform_arch}", "sparc") +OPT_CFLAGS/stubGenerator_sparc.o = $(OPT_CFLAGS) -xspace +endif endif # COMPILER_REV_NUMERIC >= 509 ################################################# diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp index e9e55062627..1239483966c 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp @@ -626,7 +626,7 @@ void MacroAssembler::jmp(Register r1, int offset, const char* file, int line ) { } // This code sequence is relocatable to any address, even on LP64. -void MacroAssembler::jumpl(AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line) { +void MacroAssembler::jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line) { assert_not_delayed(); // Force fixed length sethi because NativeJump and NativeFarCall don't handle // variable length instruction streams. @@ -672,7 +672,7 @@ void MacroAssembler::jumpl(AddressLiteral& addrlit, Register temp, Register d, i } } -void MacroAssembler::jump(AddressLiteral& addrlit, Register temp, int offset, const char* file, int line) { +void MacroAssembler::jump(const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line) { jumpl(addrlit, temp, G0, offset, file, line); } diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp index 2f95cb9e8bd..4592ed81fea 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp @@ -1974,12 +1974,12 @@ public: // address pseudos: make these names unlike instruction names to avoid confusion inline intptr_t load_pc_address( Register reg, int bytes_to_skip ); - inline void load_contents(AddressLiteral& addrlit, Register d, int offset = 0); - inline void load_ptr_contents(AddressLiteral& addrlit, Register d, int offset = 0); - inline void store_contents(Register s, AddressLiteral& addrlit, Register temp, int offset = 0); - inline void store_ptr_contents(Register s, AddressLiteral& addrlit, Register temp, int offset = 0); - inline void jumpl_to(AddressLiteral& addrlit, Register temp, Register d, int offset = 0); - inline void jump_to(AddressLiteral& addrlit, Register temp, int offset = 0); + inline void load_contents(const AddressLiteral& addrlit, Register d, int offset = 0); + inline void load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset = 0); + inline void store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0); + inline void store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0); + inline void jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset = 0); + inline void jump_to(const AddressLiteral& addrlit, Register temp, int offset = 0); inline void jump_indirect_to(Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0); // ring buffer traceable jumps @@ -1987,8 +1987,8 @@ public: void jmp2( Register r1, Register r2, const char* file, int line ); void jmp ( Register r1, int offset, const char* file, int line ); - void jumpl(AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line); - void jump (AddressLiteral& addrlit, Register temp, int offset, const char* file, int line); + void jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line); + void jump (const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line); // argument pseudos: diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp index 3ebf9c1c091..88cf8f5eee0 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp @@ -650,28 +650,28 @@ inline intptr_t MacroAssembler::load_pc_address( Register reg, int bytes_to_skip } -inline void MacroAssembler::load_contents(AddressLiteral& addrlit, Register d, int offset) { +inline void MacroAssembler::load_contents(const AddressLiteral& addrlit, Register d, int offset) { assert_not_delayed(); sethi(addrlit, d); ld(d, addrlit.low10() + offset, d); } -inline void MacroAssembler::load_ptr_contents(AddressLiteral& addrlit, Register d, int offset) { +inline void MacroAssembler::load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset) { assert_not_delayed(); sethi(addrlit, d); ld_ptr(d, addrlit.low10() + offset, d); } -inline void MacroAssembler::store_contents(Register s, AddressLiteral& addrlit, Register temp, int offset) { +inline void MacroAssembler::store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) { assert_not_delayed(); sethi(addrlit, temp); st(s, temp, addrlit.low10() + offset); } -inline void MacroAssembler::store_ptr_contents(Register s, AddressLiteral& addrlit, Register temp, int offset) { +inline void MacroAssembler::store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) { assert_not_delayed(); sethi(addrlit, temp); st_ptr(s, temp, addrlit.low10() + offset); @@ -679,7 +679,7 @@ inline void MacroAssembler::store_ptr_contents(Register s, AddressLiteral& addrl // This code sequence is relocatable to any address, even on LP64. -inline void MacroAssembler::jumpl_to(AddressLiteral& addrlit, Register temp, Register d, int offset) { +inline void MacroAssembler::jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset) { assert_not_delayed(); // Force fixed length sethi because NativeJump and NativeFarCall don't handle // variable length instruction streams. @@ -688,7 +688,7 @@ inline void MacroAssembler::jumpl_to(AddressLiteral& addrlit, Register temp, Reg } -inline void MacroAssembler::jump_to(AddressLiteral& addrlit, Register temp, int offset) { +inline void MacroAssembler::jump_to(const AddressLiteral& addrlit, Register temp, int offset) { jumpl_to(addrlit, temp, G0, offset); } diff --git a/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.inline.hpp index c143939d401..6bd42a8ec84 100644 --- a/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/bytecodeInterpreter_sparc.inline.hpp @@ -236,19 +236,19 @@ inline jint BytecodeInterpreter::VMintRem(jint op1, jint op2) { } inline jint BytecodeInterpreter::VMintShl(jint op1, jint op2) { - return op1 << op2; + return op1 << (op2 & 0x1f); } inline jint BytecodeInterpreter::VMintShr(jint op1, jint op2) { - return op1 >> op2; // QQ op2 & 0x1f?? + return op1 >> (op2 & 0x1f); } inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { return op1 - op2; } -inline jint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { - return ((juint) op1) >> op2; // QQ op2 & 0x1f?? +inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { + return ((juint) op1) >> (op2 & 0x1f); } inline jint BytecodeInterpreter::VMintXor(jint op1, jint op2) { diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp index a8b7b08154d..04a8be9c431 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp @@ -409,7 +409,7 @@ void LIRGenerator::do_MonitorExit(MonitorExit* x) { LIR_Opr lock = FrameMap::G1_opr; LIR_Opr hdr = FrameMap::G3_opr; LIR_Opr obj_temp = FrameMap::G4_opr; - monitor_exit(obj_temp, lock, hdr, x->monitor_no()); + monitor_exit(obj_temp, lock, hdr, LIR_OprFact::illegalOpr, x->monitor_no()); } diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index e1e4c3ac17e..3a4ebb94e58 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -1031,3 +1031,7 @@ void Runtime1::generate_handle_exception(StubAssembler* sasm, OopMapSet* oop_map #undef __ #define __ masm-> + +const char *Runtime1::pd_name_for_address(address entry) { + return ""; +} diff --git a/hotspot/src/cpu/sparc/vm/interpreterRT_sparc.cpp b/hotspot/src/cpu/sparc/vm/interpreterRT_sparc.cpp index 9bd6e0b0732..fb95f8ad4a3 100644 --- a/hotspot/src/cpu/sparc/vm/interpreterRT_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/interpreterRT_sparc.cpp @@ -56,14 +56,18 @@ void InterpreterRuntime::SignatureHandlerGenerator::pass_long() { } -#ifdef _LP64 void InterpreterRuntime::SignatureHandlerGenerator::pass_float() { Argument jni_arg(jni_offset(), false); +#ifdef _LP64 FloatRegister Rtmp = F0; __ ldf(FloatRegisterImpl::S, Llocals, Interpreter::local_offset_in_bytes(offset()), Rtmp); __ store_float_argument(Rtmp, jni_arg); -} +#else + Register Rtmp = O0; + __ ld(Llocals, Interpreter::local_offset_in_bytes(offset()), Rtmp); + __ store_argument(Rtmp, jni_arg); #endif +} void InterpreterRuntime::SignatureHandlerGenerator::pass_double() { @@ -185,6 +189,13 @@ class SlowSignatureHandler: public NativeSignatureIterator { _from -= 2*Interpreter::stackElementSize; add_signature( non_float ); } + + virtual void pass_float() { + *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); + _from -= Interpreter::stackElementSize; + add_signature( non_float ); + } + #endif // _LP64 virtual void add_signature( intptr_t sig_type ) { diff --git a/hotspot/src/cpu/sparc/vm/javaFrameAnchor_sparc.hpp b/hotspot/src/cpu/sparc/vm/javaFrameAnchor_sparc.hpp index 783f099f834..f9607f8fede 100644 --- a/hotspot/src/cpu/sparc/vm/javaFrameAnchor_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/javaFrameAnchor_sparc.hpp @@ -76,6 +76,8 @@ public: void set_last_Java_sp(intptr_t* sp) { _last_Java_sp = sp; } + address last_Java_pc(void) { return _last_Java_pc; } + // These are only used by friends private: diff --git a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp index fbb4d0b557e..7a45489be40 100644 --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp @@ -3236,12 +3236,14 @@ void TemplateTable::_new() { __ get_2_byte_integer_at_bcp(1, Rscratch, Roffset, InterpreterMacroAssembler::Unsigned); __ get_cpool_and_tags(Rscratch, G3_scratch); // make sure the class we're about to instantiate has been resolved + // This is done before loading instanceKlass to be consistent with the order + // how Constant Pool is updated (see constantPoolOopDesc::klass_at_put) __ add(G3_scratch, typeArrayOopDesc::header_size(T_BYTE) * wordSize, G3_scratch); __ ldub(G3_scratch, Roffset, G3_scratch); __ cmp(G3_scratch, JVM_CONSTANT_Class); __ br(Assembler::notEqual, false, Assembler::pn, slow_case); __ delayed()->sll(Roffset, LogBytesPerWord, Roffset); - + // get instanceKlass //__ sll(Roffset, LogBytesPerWord, Roffset); // executed in delay slot __ add(Roffset, sizeof(constantPoolOopDesc), Roffset); __ ld_ptr(Rscratch, Roffset, RinstanceKlass); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index ab758216c57..bb7517f533d 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -7151,7 +7151,7 @@ void MacroAssembler::tlab_refill(Label& retry, subptr(t1, typeArrayOopDesc::header_size(T_INT)); addptr(t1, (int32_t)ThreadLocalAllocBuffer::alignment_reserve()); shlptr(t1, log2_intptr(HeapWordSize/sizeof(jint))); - movptr(Address(top, arrayOopDesc::length_offset_in_bytes()), t1); + movl(Address(top, arrayOopDesc::length_offset_in_bytes()), t1); // set klass to intArrayKlass // dubious reloc why not an oop reloc? movptr(t1, ExternalAddress((address) Universe::intArrayKlassObj_addr())); @@ -7568,21 +7568,27 @@ void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, // Scan RCX words at [RDI] for an occurrence of RAX. // Set NZ/Z based on last compare. + // Z flag value will not be set by 'repne' if RCX == 0 since 'repne' does + // not change flags (only scas instruction which is repeated sets flags). + // Set Z = 0 (not equal) before 'repne' to indicate that class was not found. #ifdef _LP64 // This part is tricky, as values in supers array could be 32 or 64 bit wide // and we store values in objArrays always encoded, thus we need to encode // the value of rax before repne. Note that rax is dead after the repne. if (UseCompressedOops) { - encode_heap_oop_not_null(rax); + encode_heap_oop_not_null(rax); // Changes flags. // The superclass is never null; it would be a basic system error if a null // pointer were to sneak in here. Note that we have already loaded the // Klass::super_check_offset from the super_klass in the fast path, // so if there is a null in that register, we are already in the afterlife. + testl(rax,rax); // Set Z = 0 repne_scanl(); } else #endif // _LP64 + { + testptr(rax,rax); // Set Z = 0 repne_scan(); - + } // Unspill the temp. registers: if (pushed_rdi) pop(rdi); if (pushed_rcx) pop(rcx); @@ -8257,30 +8263,35 @@ void MacroAssembler::store_heap_oop_null(Address dst) { } } -// Algorithm must match oop.inline.hpp encode_heap_oop. -void MacroAssembler::encode_heap_oop(Register r) { +#ifdef ASSERT +void MacroAssembler::verify_heapbase(const char* msg) { assert (UseCompressedOops, "should be compressed"); assert (Universe::heap() != NULL, "java heap should be initialized"); + if (CheckCompressedOops) { + Label ok; + push(rscratch1); // cmpptr trashes rscratch1 + cmpptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); + jcc(Assembler::equal, ok); + stop(msg); + bind(ok); + pop(rscratch1); + } +} +#endif + +// Algorithm must match oop.inline.hpp encode_heap_oop. +void MacroAssembler::encode_heap_oop(Register r) { +#ifdef ASSERT + verify_heapbase("MacroAssembler::encode_heap_oop: heap base corrupted?"); +#endif + verify_oop(r, "broken oop in encode_heap_oop"); if (Universe::narrow_oop_base() == NULL) { - verify_oop(r, "broken oop in encode_heap_oop"); if (Universe::narrow_oop_shift() != 0) { assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); shrq(r, LogMinObjAlignmentInBytes); } return; } -#ifdef ASSERT - if (CheckCompressedOops) { - Label ok; - push(rscratch1); // cmpptr trashes rscratch1 - cmpptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); - jcc(Assembler::equal, ok); - stop("MacroAssembler::encode_heap_oop: heap base corrupted?"); - bind(ok); - pop(rscratch1); - } -#endif - verify_oop(r, "broken oop in encode_heap_oop"); testq(r, r); cmovq(Assembler::equal, r, r12_heapbase); subq(r, r12_heapbase); @@ -8288,9 +8299,8 @@ void MacroAssembler::encode_heap_oop(Register r) { } void MacroAssembler::encode_heap_oop_not_null(Register r) { - assert (UseCompressedOops, "should be compressed"); - assert (Universe::heap() != NULL, "java heap should be initialized"); #ifdef ASSERT + verify_heapbase("MacroAssembler::encode_heap_oop_not_null: heap base corrupted?"); if (CheckCompressedOops) { Label ok; testq(r, r); @@ -8310,9 +8320,8 @@ void MacroAssembler::encode_heap_oop_not_null(Register r) { } void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { - assert (UseCompressedOops, "should be compressed"); - assert (Universe::heap() != NULL, "java heap should be initialized"); #ifdef ASSERT + verify_heapbase("MacroAssembler::encode_heap_oop_not_null2: heap base corrupted?"); if (CheckCompressedOops) { Label ok; testq(src, src); @@ -8335,40 +8344,21 @@ void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) { } void MacroAssembler::decode_heap_oop(Register r) { - assert (UseCompressedOops, "should be compressed"); - assert (Universe::heap() != NULL, "java heap should be initialized"); +#ifdef ASSERT + verify_heapbase("MacroAssembler::decode_heap_oop: heap base corrupted?"); +#endif if (Universe::narrow_oop_base() == NULL) { if (Universe::narrow_oop_shift() != 0) { assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong"); shlq(r, LogMinObjAlignmentInBytes); } - verify_oop(r, "broken oop in decode_heap_oop"); - return; + } else { + Label done; + shlq(r, LogMinObjAlignmentInBytes); + jccb(Assembler::equal, done); + addq(r, r12_heapbase); + bind(done); } -#ifdef ASSERT - if (CheckCompressedOops) { - Label ok; - push(rscratch1); - cmpptr(r12_heapbase, - ExternalAddress((address)Universe::narrow_oop_base_addr())); - jcc(Assembler::equal, ok); - stop("MacroAssembler::decode_heap_oop: heap base corrupted?"); - bind(ok); - pop(rscratch1); - } -#endif - - Label done; - shlq(r, LogMinObjAlignmentInBytes); - jccb(Assembler::equal, done); - addq(r, r12_heapbase); -#if 0 - // alternate decoding probably a wash. - testq(r, r); - jccb(Assembler::equal, done); - leaq(r, Address(r12_heapbase, r, Address::times_8, 0)); -#endif - bind(done); verify_oop(r, "broken oop in decode_heap_oop"); } @@ -8410,9 +8400,11 @@ void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) { addq(dst, r12_heapbase); } } - } else if (dst != src) { + } else { assert (Universe::narrow_oop_base() == NULL, "sanity"); - movq(dst, src); + if (dst != src) { + movq(dst, src); + } } } diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index 5384f6bf46b..2ee35280959 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -1714,6 +1714,9 @@ class MacroAssembler: public Assembler { // if heap base register is used - reinit it with the correct value void reinit_heapbase(); + + DEBUG_ONLY(void verify_heapbase(const char* msg);) + #endif // _LP64 // Int division/remainder for Java diff --git a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp index a8e600db946..1c5616aa352 100644 --- a/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/bytecodeInterpreter_x86.inline.hpp @@ -236,11 +236,11 @@ inline jint BytecodeInterpreter::VMintRem(jint op1, jint op2) { } inline jint BytecodeInterpreter::VMintShl(jint op1, jint op2) { - return op1 << op2; + return op1 << op2; } inline jint BytecodeInterpreter::VMintShr(jint op1, jint op2) { - return op1 >> op2; // QQ op2 & 0x1f?? + return op1 >> (op2 & 0x1f); } inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { @@ -248,7 +248,7 @@ inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) { } inline jint BytecodeInterpreter::VMintUshr(jint op1, jint op2) { - return ((juint) op1) >> op2; // QQ op2 & 0x1f?? + return ((juint) op1) >> (op2 & 0x1f); } inline jint BytecodeInterpreter::VMintXor(jint op1, jint op2) { diff --git a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index a37aab25aa6..df92163cca4 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -349,7 +349,7 @@ void LIRGenerator::do_MonitorExit(MonitorExit* x) { LIR_Opr lock = new_register(T_INT); LIR_Opr obj_temp = new_register(T_INT); set_no_result(x); - monitor_exit(obj_temp, lock, syncTempOpr(), x->monitor_no()); + monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no()); } diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index 4bfcdb84f33..230c4b28ea3 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1779,3 +1779,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { } #undef __ + +const char *Runtime1::pd_name_for_address(address entry) { + return ""; +} diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index 95a69f3d724..cfc20539783 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -575,8 +575,8 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) { #ifdef CC_INTERP - // Needed for JVMTI. The result should always be in the interpreterState object - assert(false, "NYI"); + // Needed for JVMTI. The result should always be in the + // interpreterState object interpreterState istate = get_interpreterState(); #endif // CC_INTERP assert(is_interpreted_frame(), "interpreted frame expected"); diff --git a/hotspot/src/cpu/x86/vm/interpreterRT_x86_32.cpp b/hotspot/src/cpu/x86/vm/interpreterRT_x86_32.cpp index bfa03b1cef2..ab70515a69f 100644 --- a/hotspot/src/cpu/x86/vm/interpreterRT_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/interpreterRT_x86_32.cpp @@ -34,6 +34,10 @@ void InterpreterRuntime::SignatureHandlerGenerator::pass_int() { move(offset(), jni_offset() + 1); } +void InterpreterRuntime::SignatureHandlerGenerator::pass_float() { + move(offset(), jni_offset() + 1); +} + void InterpreterRuntime::SignatureHandlerGenerator::pass_long() { move(offset(), jni_offset() + 2); move(offset() + 1, jni_offset() + 1); @@ -91,6 +95,11 @@ class SlowSignatureHandler: public NativeSignatureIterator { _from -= Interpreter::stackElementSize; } + virtual void pass_float() { + *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); + _from -= Interpreter::stackElementSize; + } + virtual void pass_long() { _to[0] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); _to[1] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(0)); diff --git a/hotspot/src/cpu/x86/vm/javaFrameAnchor_x86.hpp b/hotspot/src/cpu/x86/vm/javaFrameAnchor_x86.hpp index 9f4a9aae56d..d78bead14cb 100644 --- a/hotspot/src/cpu/x86/vm/javaFrameAnchor_x86.hpp +++ b/hotspot/src/cpu/x86/vm/javaFrameAnchor_x86.hpp @@ -66,6 +66,8 @@ public: intptr_t* last_Java_sp(void) const { return _last_Java_sp; } + address last_Java_pc(void) { return _last_Java_pc; } + private: static ByteSize last_Java_fp_offset() { return byte_offset_of(JavaFrameAnchor, _last_Java_fp); } diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp index d21646c1628..b41c646c755 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp @@ -3112,22 +3112,25 @@ void TemplateTable::_new() { transition(vtos, atos); __ get_unsigned_2_byte_index_at_bcp(rdx, 1); Label slow_case; + Label slow_case_no_pop; Label done; Label initialize_header; Label initialize_object; // including clearing the fields Label allocate_shared; __ get_cpool_and_tags(rcx, rax); + + // Make sure the class we're about to instantiate has been resolved. + // This is done before loading instanceKlass to be consistent with the order + // how Constant Pool is updated (see constantPoolOopDesc::klass_at_put) + const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; + __ cmpb(Address(rax, rdx, Address::times_1, tags_offset), JVM_CONSTANT_Class); + __ jcc(Assembler::notEqual, slow_case_no_pop); + // get instanceKlass __ movptr(rcx, Address(rcx, rdx, Address::times_ptr, sizeof(constantPoolOopDesc))); __ push(rcx); // save the contexts of klass for initializing the header - // make sure the class we're about to instantiate has been resolved. - // Note: slow_case does a pop of stack, which is why we loaded class/pushed above - const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; - __ cmpb(Address(rax, rdx, Address::times_1, tags_offset), JVM_CONSTANT_Class); - __ jcc(Assembler::notEqual, slow_case); - // make sure klass is initialized & doesn't have finalizer // make sure klass is fully initialized __ cmpl(Address(rcx, instanceKlass::init_state_offset_in_bytes() + sizeof(oopDesc)), instanceKlass::fully_initialized); @@ -3255,6 +3258,7 @@ void TemplateTable::_new() { // slow case __ bind(slow_case); __ pop(rcx); // restore stack pointer to what it was when we came in. + __ bind(slow_case_no_pop); __ get_constant_pool(rax); __ get_unsigned_2_byte_index_at_bcp(rdx, 1); call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), rax, rdx); diff --git a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp index 8c623d33e3b..832e96bd458 100644 --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp @@ -3126,18 +3126,18 @@ void TemplateTable::_new() { Label allocate_shared; __ get_cpool_and_tags(rsi, rax); - // get instanceKlass - __ movptr(rsi, Address(rsi, rdx, - Address::times_8, sizeof(constantPoolOopDesc))); - - // make sure the class we're about to instantiate has been - // resolved. Note: slow_case does a pop of stack, which is why we - // loaded class/pushed above + // Make sure the class we're about to instantiate has been resolved. + // This is done before loading instanceKlass to be consistent with the order + // how Constant Pool is updated (see constantPoolOopDesc::klass_at_put) const int tags_offset = typeArrayOopDesc::header_size(T_BYTE) * wordSize; __ cmpb(Address(rax, rdx, Address::times_1, tags_offset), JVM_CONSTANT_Class); __ jcc(Assembler::notEqual, slow_case); + // get instanceKlass + __ movptr(rsi, Address(rsi, rdx, + Address::times_8, sizeof(constantPoolOopDesc))); + // make sure klass is initialized & doesn't have finalizer // make sure klass is fully initialized __ cmpl(Address(rsi, diff --git a/hotspot/src/cpu/zero/vm/disassembler_zero.hpp b/hotspot/src/cpu/zero/vm/disassembler_zero.hpp index 76eea60aa65..c488cf8e765 100644 --- a/hotspot/src/cpu/zero/vm/disassembler_zero.hpp +++ b/hotspot/src/cpu/zero/vm/disassembler_zero.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * Copyright 2007 Red Hat, Inc. + * Copyright 2007, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,10 @@ * */ -// The disassembler prints out zero code annotated -// with Java specific information. - static int pd_instruction_alignment() { - ShouldNotCallThis(); + return 1; } static const char* pd_cpu_opts() { - ShouldNotCallThis(); + return ""; } diff --git a/hotspot/src/cpu/zero/vm/shark_globals_zero.hpp b/hotspot/src/cpu/zero/vm/shark_globals_zero.hpp new file mode 100644 index 00000000000..30151973840 --- /dev/null +++ b/hotspot/src/cpu/zero/vm/shark_globals_zero.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// Set the default values for platform dependent flags used by the +// Shark compiler. See globals.hpp for details of what they do. + +define_pd_global(bool, BackgroundCompilation, true ); +define_pd_global(bool, UseTLAB, true ); +define_pd_global(bool, ResizeTLAB, true ); +define_pd_global(bool, InlineIntrinsics, false); +define_pd_global(bool, PreferInterpreterNativeStubs, false); +define_pd_global(bool, ProfileTraps, false); +define_pd_global(bool, UseOnStackReplacement, true ); +define_pd_global(bool, TieredCompilation, false); + +define_pd_global(intx, CompileThreshold, 1500); +define_pd_global(intx, Tier2CompileThreshold, 1500); +define_pd_global(intx, Tier3CompileThreshold, 2500); +define_pd_global(intx, Tier4CompileThreshold, 4500); + +define_pd_global(intx, BackEdgeThreshold, 100000); +define_pd_global(intx, Tier2BackEdgeThreshold, 100000); +define_pd_global(intx, Tier3BackEdgeThreshold, 100000); +define_pd_global(intx, Tier4BackEdgeThreshold, 100000); + +define_pd_global(intx, OnStackReplacePercentage, 933 ); +define_pd_global(intx, FreqInlineSize, 325 ); +define_pd_global(intx, InlineSmallCode, 1000 ); +define_pd_global(intx, NewRatio, 12 ); +define_pd_global(intx, NewSizeThreadIncrease, 4*K ); +define_pd_global(intx, InitialCodeCacheSize, 160*K); +define_pd_global(intx, ReservedCodeCacheSize, 32*M ); +define_pd_global(bool, ProfileInterpreter, false); +define_pd_global(intx, CodeCacheExpansionSize, 32*K ); +define_pd_global(uintx, CodeCacheMinBlockLength, 1 ); +define_pd_global(uintx, PermSize, 12*M ); +define_pd_global(uintx, MaxPermSize, 64*M ); +define_pd_global(bool, NeverActAsServerClassMachine, true ); +define_pd_global(uint64_t, MaxRAM, 1ULL*G); +define_pd_global(bool, CICompileOSR, true ); diff --git a/hotspot/src/os/linux/launcher/java_md.c b/hotspot/src/os/linux/launcher/java_md.c index baa328523eb..3308ff62df3 100644 --- a/hotspot/src/os/linux/launcher/java_md.c +++ b/hotspot/src/os/linux/launcher/java_md.c @@ -79,6 +79,10 @@ # define ARCH "i386" # elif defined(__sparc) # define ARCH "sparc" +# elif defined(arm) +# define ARCH "arm" +# elif defined(PPC) +# define ARCH "ppc" # endif #endif /* _LP64 */ diff --git a/hotspot/src/os/linux/vm/attachListener_linux.cpp b/hotspot/src/os/linux/vm/attachListener_linux.cpp index 222ffa5acb2..837410ab3bd 100644 --- a/hotspot/src/os/linux/vm/attachListener_linux.cpp +++ b/hotspot/src/os/linux/vm/attachListener_linux.cpp @@ -32,11 +32,15 @@ #include #include +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path) +#endif + // The attach mechanism on Linux uses a UNIX domain socket. An attach listener // thread is created at startup or is created on-demand via a signal from // the client tool. The attach listener creates a socket and binds it to a file // in the filesystem. The attach listener then acts as a simple (single- -// threaded) server - tt waits for a client to connect, reads the request, +// threaded) server - it waits for a client to connect, reads the request, // executes it, and returns the response to the client via the socket // connection. // @@ -54,7 +58,7 @@ class LinuxAttachOperation; class LinuxAttachListener: AllStatic { private: // the path to which we bind the UNIX domain socket - static char _path[PATH_MAX+1]; + static char _path[UNIX_PATH_MAX]; static bool _has_path; // the file descriptor for the listening socket @@ -64,8 +68,8 @@ class LinuxAttachListener: AllStatic { if (path == NULL) { _has_path = false; } else { - strncpy(_path, path, PATH_MAX); - _path[PATH_MAX] = '\0'; + strncpy(_path, path, UNIX_PATH_MAX); + _path[UNIX_PATH_MAX-1] = '\0'; _has_path = true; } } @@ -113,7 +117,7 @@ class LinuxAttachOperation: public AttachOperation { }; // statics -char LinuxAttachListener::_path[PATH_MAX+1]; +char LinuxAttachListener::_path[UNIX_PATH_MAX]; bool LinuxAttachListener::_has_path; int LinuxAttachListener::_listener = -1; @@ -163,54 +167,53 @@ extern "C" { // Initialization - create a listener socket and bind it to a file int LinuxAttachListener::init() { - char path[PATH_MAX+1]; // socket file - int listener; // listener socket (file descriptor) + char path[UNIX_PATH_MAX]; // socket file + char initial_path[UNIX_PATH_MAX]; // socket file during setup + int listener; // listener socket (file descriptor) // register function to cleanup ::atexit(listener_cleanup); + int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", + os::get_temp_directory(), os::current_process_id()); + if (n <= (int)UNIX_PATH_MAX) { + n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); + } + if (n > (int)UNIX_PATH_MAX) { + return -1; + } + // create the listener socket listener = ::socket(PF_UNIX, SOCK_STREAM, 0); if (listener == -1) { return -1; } - int res = -1; + // bind socket struct sockaddr_un addr; addr.sun_family = AF_UNIX; - - // FIXME: Prior to b39 the tool-side API expected to find the well - // known file in the working directory. To allow this libjvm.so work with - // a pre-b39 SDK we create it in the working directory if - // +StartAttachListener is used is used. All unit tests for this feature - // currently used this flag. Once b39 SDK has been promoted we can remove - // this code. - if (StartAttachListener) { - sprintf(path, ".java_pid%d", os::current_process_id()); - strcpy(addr.sun_path, path); - ::unlink(path); - res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); - } + strcpy(addr.sun_path, initial_path); + ::unlink(initial_path); + int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); if (res == -1) { - snprintf(path, PATH_MAX+1, "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); - strcpy(addr.sun_path, path); - ::unlink(path); - res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); + RESTARTABLE(::close(listener), res); + return -1; + } + + // put in listen mode, set permissions, and rename into place + res = ::listen(listener, 5); + if (res == 0) { + RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res); + if (res == 0) { + res = ::rename(initial_path, path); + } } if (res == -1) { RESTARTABLE(::close(listener), res); + ::unlink(initial_path); return -1; } set_path(path); - - // put in listen mode and set permission - if ((::listen(listener, 5) == -1) || (::chmod(path, S_IREAD|S_IWRITE) == -1)) { - RESTARTABLE(::close(listener), res); - ::unlink(path); - set_path(NULL); - return -1; - } set_listener(listener); return 0; diff --git a/hotspot/src/os/linux/vm/globals_linux.hpp b/hotspot/src/os/linux/vm/globals_linux.hpp index 14b22bf7ce8..75b31373703 100644 --- a/hotspot/src/os/linux/vm/globals_linux.hpp +++ b/hotspot/src/os/linux/vm/globals_linux.hpp @@ -29,9 +29,10 @@ product(bool, UseOprofile, false, \ "enable support for Oprofile profiler") \ \ - product(bool, UseLinuxPosixThreadCPUClocks, false, \ - "enable fast Linux Posix clocks where available") \ - + product(bool, UseLinuxPosixThreadCPUClocks, true, \ + "enable fast Linux Posix clocks where available") +// NB: The default value of UseLinuxPosixThreadCPUClocks may be +// overridden in Arguments::parse_each_vm_init_arg. // // Defines Linux-specific default values. The flags are available on all diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 9648b72500a..8635a3d411f 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -30,6 +30,8 @@ // put OS-includes here # include # include +# include +# include # include # include # include @@ -188,6 +190,10 @@ static char cpu_arch[] = "ia64"; static char cpu_arch[] = "i386"; #elif defined(AMD64) static char cpu_arch[] = "amd64"; +#elif defined(ARM) +static char cpu_arch[] = "arm"; +#elif defined(PPC) +static char cpu_arch[] = "ppc"; #elif defined(SPARC) # ifdef _LP64 static char cpu_arch[] = "sparcv9"; @@ -1137,8 +1143,8 @@ void os::Linux::capture_initial_stack(size_t max_size) { long it_real; uintptr_t start; uintptr_t vsize; - uintptr_t rss; - unsigned long rsslim; + intptr_t rss; + uintptr_t rsslim; uintptr_t scodes; uintptr_t ecode; int i; @@ -1168,12 +1174,12 @@ void os::Linux::capture_initial_stack(size_t max_size) { // Skip blank chars do s++; while (isspace(*s)); - /* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 */ - /* 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 */ - i = sscanf(s, "%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld " - UINTX_FORMAT UINTX_FORMAT UINTX_FORMAT - " %lu " - UINTX_FORMAT UINTX_FORMAT UINTX_FORMAT, +#define _UFM UINTX_FORMAT +#define _DFM INTX_FORMAT + + /* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 */ + /* 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 */ + i = sscanf(s, "%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld " _UFM _UFM _DFM _UFM _UFM _UFM _UFM, &state, /* 3 %c */ &ppid, /* 4 %d */ &pgrp, /* 5 %d */ @@ -1193,15 +1199,18 @@ void os::Linux::capture_initial_stack(size_t max_size) { &nice, /* 19 %ld */ &junk, /* 20 %ld */ &it_real, /* 21 %ld */ - &start, /* 22 UINTX_FORMAT */ - &vsize, /* 23 UINTX_FORMAT */ - &rss, /* 24 UINTX_FORMAT */ - &rsslim, /* 25 %lu */ - &scodes, /* 26 UINTX_FORMAT */ - &ecode, /* 27 UINTX_FORMAT */ - &stack_start); /* 28 UINTX_FORMAT */ + &start, /* 22 UINTX_FORMAT */ + &vsize, /* 23 UINTX_FORMAT */ + &rss, /* 24 INTX_FORMAT */ + &rsslim, /* 25 UINTX_FORMAT */ + &scodes, /* 26 UINTX_FORMAT */ + &ecode, /* 27 UINTX_FORMAT */ + &stack_start); /* 28 UINTX_FORMAT */ } +#undef _UFM +#undef _DFM + if (i != 28 - 2) { assert(false, "Bad conversion from /proc/self/stat"); // product mode - assume we are the initial thread, good luck in the @@ -1336,13 +1345,15 @@ void os::Linux::clock_init() { #if defined(IA32) || defined(AMD64) #define SYS_clock_getres IA32_ONLY(266) AMD64_ONLY(229) -#else -#error Value of SYS_clock_getres not known on this platform -#endif - -#endif - #define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y) +#else +#warning "SYS_clock_getres not defined for this platform, disabling fast_thread_cpu_time" +#define sys_clock_getres(x,y) -1 +#endif + +#else +#define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y) +#endif void os::Linux::fast_thread_clock_init() { if (!UseLinuxPosixThreadCPUClocks) { @@ -1905,7 +1916,9 @@ void os::print_os_info(outputStream* st) { !_print_ascii_file("/etc/SuSE-release", st) && !_print_ascii_file("/etc/turbolinux-release", st) && !_print_ascii_file("/etc/gentoo-release", st) && - !_print_ascii_file("/etc/debian_version", st)) { + !_print_ascii_file("/etc/debian_version", st) && + !_print_ascii_file("/etc/ltib-release", st) && + !_print_ascii_file("/etc/angstrom-version", st)) { st->print("Linux"); } st->cr(); @@ -1971,6 +1984,11 @@ void os::print_os_info(outputStream* st) { os::loadavg(loadavg, 3); st->print("%0.02f %0.02f %0.02f", loadavg[0], loadavg[1], loadavg[2]); st->cr(); + + // meminfo + st->print("\n/proc/meminfo:\n"); + _print_ascii_file("/proc/meminfo", st); + st->cr(); } void os::print_memory_info(outputStream* st) { @@ -2097,7 +2115,8 @@ void os::jvm_path(char *buf, jint buflen) { CAST_FROM_FN_PTR(address, os::jvm_path), dli_fname, sizeof(dli_fname), NULL); assert(ret != 0, "cannot locate libjvm"); - if (realpath(dli_fname, buf) == NULL) + char *rp = realpath(dli_fname, buf); + if (rp == NULL) return; if (strcmp(Arguments::sun_java_launcher(), "gamma") == 0) { @@ -2125,7 +2144,8 @@ void os::jvm_path(char *buf, jint buflen) { assert(strstr(p, "/libjvm") == p, "invalid library name"); p = strstr(p, "_g") ? "_g" : ""; - if (realpath(java_home_var, buf) == NULL) + rp = realpath(java_home_var, buf); + if (rp == NULL) return; // determine if this is a legacy image or modules image @@ -2147,7 +2167,8 @@ void os::jvm_path(char *buf, jint buflen) { snprintf(buf + len, buflen-len, "/hotspot/libjvm%s.so", p); } else { // Go back to path of .so - if (realpath(dli_fname, buf) == NULL) + rp = realpath(dli_fname, buf); + if (rp == NULL) return; } } @@ -2508,9 +2529,9 @@ os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory; unsigned long* os::Linux::_numa_all_nodes; bool os::uncommit_memory(char* addr, size_t size) { - return ::mmap(addr, size, PROT_NONE, - MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0) - != MAP_FAILED; + uintptr_t res = (uintptr_t) ::mmap(addr, size, PROT_NONE, + MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE|MAP_ANONYMOUS, -1, 0); + return res != (uintptr_t) MAP_FAILED; } // Linux uses a growable mapping for the stack, and if the mapping for @@ -2718,7 +2739,8 @@ bool os::large_page_init() { // the processor. #ifndef ZERO - _large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M); + _large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M) + ARM_ONLY(2 * M) PPC_ONLY(4 * M); #endif // ZERO FILE *fp = fopen("/proc/meminfo", "r"); @@ -3981,6 +4003,9 @@ jint os::init_2(void) return JNI_OK; } +// this is called at the end of vm_initialization +void os::init_3(void) { } + // Mark the polling page as unreadable void os::make_polling_page_unreadable(void) { if( !guard_memory((char*)_polling_page, Linux::page_size()) ) @@ -4061,7 +4086,6 @@ int os::Linux::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mute //////////////////////////////////////////////////////////////////////////////// // debug support -#ifndef PRODUCT static address same_page(address x, address y) { int page_bits = -os::vm_page_size(); if ((intptr_t(x) & page_bits) == (intptr_t(y) & page_bits)) @@ -4072,26 +4096,26 @@ static address same_page(address x, address y) { return (address)(intptr_t(y) & page_bits); } -bool os::find(address addr) { +bool os::find(address addr, outputStream* st) { Dl_info dlinfo; memset(&dlinfo, 0, sizeof(dlinfo)); if (dladdr(addr, &dlinfo)) { - tty->print(PTR_FORMAT ": ", addr); + st->print(PTR_FORMAT ": ", addr); if (dlinfo.dli_sname != NULL) { - tty->print("%s+%#x", dlinfo.dli_sname, + st->print("%s+%#x", dlinfo.dli_sname, addr - (intptr_t)dlinfo.dli_saddr); } else if (dlinfo.dli_fname) { - tty->print("", addr - (intptr_t)dlinfo.dli_fbase); + st->print("", addr - (intptr_t)dlinfo.dli_fbase); } else { - tty->print(""); + st->print(""); } if (dlinfo.dli_fname) { - tty->print(" in %s", dlinfo.dli_fname); + st->print(" in %s", dlinfo.dli_fname); } if (dlinfo.dli_fbase) { - tty->print(" at " PTR_FORMAT, dlinfo.dli_fbase); + st->print(" at " PTR_FORMAT, dlinfo.dli_fbase); } - tty->cr(); + st->cr(); if (Verbose) { // decode some bytes around the PC @@ -4104,15 +4128,13 @@ bool os::find(address addr) { if (dladdr(end, &dlinfo2) && dlinfo2.dli_saddr != dlinfo.dli_saddr && end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin) end = (address) dlinfo2.dli_saddr; - Disassembler::decode(begin, end); + Disassembler::decode(begin, end, st); } return true; } return false; } -#endif - //////////////////////////////////////////////////////////////////////////////// // misc @@ -4321,6 +4343,7 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { int count; long sys_time, user_time; char string[64]; + char cdummy; int idummy; long ldummy; FILE *fp; @@ -4381,11 +4404,11 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { // Skip blank chars do s++; while (isspace(*s)); - count = sscanf(s,"%*c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu", - &idummy, &idummy, &idummy, &idummy, &idummy, + count = sscanf(s,"%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu", + &cdummy, &idummy, &idummy, &idummy, &idummy, &idummy, &ldummy, &ldummy, &ldummy, &ldummy, &ldummy, &user_time, &sys_time); - if ( count != 12 ) return -1; + if ( count != 13 ) return -1; if (user_sys_cpu_time) { return ((jlong)sys_time + (jlong)user_time) * (1000000000 / clock_tics_per_sec); } else { @@ -4980,3 +5003,43 @@ int os::fork_and_exec(char* cmd) { } } } + +// is_headless_jre() +// +// Test for the existence of libmawt in motif21 or xawt directories +// in order to report if we are running in a headless jre +// +bool os::is_headless_jre() { + struct stat statbuf; + char buf[MAXPATHLEN]; + char libmawtpath[MAXPATHLEN]; + const char *xawtstr = "/xawt/libmawt.so"; + const char *motifstr = "/motif21/libmawt.so"; + char *p; + + // Get path to libjvm.so + os::jvm_path(buf, sizeof(buf)); + + // Get rid of libjvm.so + p = strrchr(buf, '/'); + if (p == NULL) return false; + else *p = '\0'; + + // Get rid of client or server + p = strrchr(buf, '/'); + if (p == NULL) return false; + else *p = '\0'; + + // check xawt/libmawt.so + strcpy(libmawtpath, buf); + strcat(libmawtpath, xawtstr); + if (::stat(libmawtpath, &statbuf) == 0) return false; + + // check motif21/libmawt.so + strcpy(libmawtpath, buf); + strcat(libmawtpath, motifstr); + if (::stat(libmawtpath, &statbuf) == 0) return false; + + return true; +} + diff --git a/hotspot/src/os/solaris/vm/attachListener_solaris.cpp b/hotspot/src/os/solaris/vm/attachListener_solaris.cpp index a88f8861fbd..9ae81cb53d5 100644 --- a/hotspot/src/os/solaris/vm/attachListener_solaris.cpp +++ b/hotspot/src/os/solaris/vm/attachListener_solaris.cpp @@ -364,6 +364,7 @@ extern "C" { // Create the door int SolarisAttachListener::create_door() { char door_path[PATH_MAX+1]; + char initial_path[PATH_MAX+1]; int fd, res; // register exit function @@ -375,36 +376,46 @@ int SolarisAttachListener::create_door() { return -1; } + // create initial file to attach door descriptor snprintf(door_path, sizeof(door_path), "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id()); - RESTARTABLE(::creat(door_path, S_IRUSR | S_IWUSR), fd); - + snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path); + RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd); if (fd == -1) { - debug_only(warning("attempt to create %s failed", door_path)); + debug_only(warning("attempt to create %s failed", initial_path)); + ::door_revoke(dd); return -1; } assert(fd >= 0, "bad file descriptor"); - set_door_path(door_path); RESTARTABLE(::close(fd), res); // attach the door descriptor to the file - if ((res = ::fattach(dd, door_path)) == -1) { + if ((res = ::fattach(dd, initial_path)) == -1) { // if busy then detach and try again if (errno == EBUSY) { - ::fdetach(door_path); - res = ::fattach(dd, door_path); + ::fdetach(initial_path); + res = ::fattach(dd, initial_path); } if (res == -1) { ::door_revoke(dd); dd = -1; } } + + // rename file so that clients can attach + if (dd >= 0) { + if (::rename(initial_path, door_path) == -1) { + RESTARTABLE(::close(dd), res); + ::fdetach(initial_path); + dd = -1; + } + } if (dd >= 0) { set_door_descriptor(dd); + set_door_path(door_path); } else { - // unable to create door or attach it to the file - ::unlink(door_path); - set_door_path(NULL); + // unable to create door, attach it to file, or rename file into place + ::unlink(initial_path); return -1; } diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 9a51d167a38..0245d6f609d 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1839,8 +1839,8 @@ void os::dll_build_name(char* buffer, size_t buflen, // Quietly truncate on buffer overflow. Should be an error. if (pnamelen + strlen(fname) + 10 > (size_t) buflen) { - *buffer = '\0'; - return; + *buffer = '\0'; + return; } if (pnamelen == 0) { @@ -2051,7 +2051,8 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, - {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"} + {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, + {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM 32"} }; #if (defined IA32) @@ -2068,9 +2069,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) static Elf32_Half running_arch_code=EM_PPC64; #elif (defined __powerpc__) static Elf32_Half running_arch_code=EM_PPC; + #elif (defined ARM) + static Elf32_Half running_arch_code=EM_ARM; #else #error Method os::dll_load requires that one of following is defined:\ - IA32, AMD64, IA64, __sparc, __powerpc__ + IA32, AMD64, IA64, __sparc, __powerpc__, ARM, ARM #endif // Identify compatability class for VM's architecture and library's architecture @@ -3149,7 +3152,8 @@ bool os::Solaris::ism_sanity_check(bool warn, size_t * page_size) { // ISM is only recommended on old Solaris where there is no MPSS support. // Simply choose a conservative value as default. *page_size = LargePageSizeInBytes ? LargePageSizeInBytes : - SPARC_ONLY(4 * M) IA32_ONLY(4 * M) AMD64_ONLY(2 * M); + SPARC_ONLY(4 * M) IA32_ONLY(4 * M) AMD64_ONLY(2 * M) + ARM_ONLY(2 * M); // ISM is available on all supported Solaris versions return true; @@ -5007,6 +5011,9 @@ jint os::init_2(void) { return JNI_OK; } +void os::init_3(void) { + return; +} // Mark the polling page as unreadable void os::make_polling_page_unreadable(void) { @@ -5412,7 +5419,6 @@ int os::loadavg(double loadavg[], int nelem) { } //--------------------------------------------------------------------------------- -#ifndef PRODUCT static address same_page(address x, address y) { intptr_t page_bits = -os::vm_page_size(); @@ -5424,28 +5430,28 @@ static address same_page(address x, address y) { return (address)(intptr_t(y) & page_bits); } -bool os::find(address addr) { +bool os::find(address addr, outputStream* st) { Dl_info dlinfo; memset(&dlinfo, 0, sizeof(dlinfo)); if (dladdr(addr, &dlinfo)) { #ifdef _LP64 - tty->print("0x%016lx: ", addr); + st->print("0x%016lx: ", addr); #else - tty->print("0x%08x: ", addr); + st->print("0x%08x: ", addr); #endif if (dlinfo.dli_sname != NULL) - tty->print("%s+%#lx", dlinfo.dli_sname, addr-(intptr_t)dlinfo.dli_saddr); + st->print("%s+%#lx", dlinfo.dli_sname, addr-(intptr_t)dlinfo.dli_saddr); else if (dlinfo.dli_fname) - tty->print("", addr-(intptr_t)dlinfo.dli_fbase); + st->print("", addr-(intptr_t)dlinfo.dli_fbase); else - tty->print(""); - if (dlinfo.dli_fname) tty->print(" in %s", dlinfo.dli_fname); + st->print(""); + if (dlinfo.dli_fname) st->print(" in %s", dlinfo.dli_fname); #ifdef _LP64 - if (dlinfo.dli_fbase) tty->print(" at 0x%016lx", dlinfo.dli_fbase); + if (dlinfo.dli_fbase) st->print(" at 0x%016lx", dlinfo.dli_fbase); #else - if (dlinfo.dli_fbase) tty->print(" at 0x%08x", dlinfo.dli_fbase); + if (dlinfo.dli_fbase) st->print(" at 0x%08x", dlinfo.dli_fbase); #endif - tty->cr(); + st->cr(); if (Verbose) { // decode some bytes around the PC @@ -5458,16 +5464,13 @@ bool os::find(address addr) { if (dladdr(end, &dlinfo2) && dlinfo2.dli_saddr != dlinfo.dli_saddr && end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin) end = (address) dlinfo2.dli_saddr; - Disassembler::decode(begin, end); + Disassembler::decode(begin, end, st); } return true; } return false; } -#endif - - // Following function has been added to support HotSparc's libjvm.so running // under Solaris production JDK 1.2.2 / 1.3.0. These came from // src/solaris/hpi/native_threads in the EVM codebase. @@ -5910,7 +5913,6 @@ void Parker::park(bool isAbsolute, jlong time) { if (jt->handle_special_suspend_equivalent_condition()) { jt->java_suspend_self(); } - OrderAccess::fence(); } @@ -5997,3 +5999,44 @@ int os::fork_and_exec(char* cmd) { } } } + +// is_headless_jre() +// +// Test for the existence of libmawt in motif21 or xawt directories +// in order to report if we are running in a headless jre +// +bool os::is_headless_jre() { + struct stat statbuf; + char buf[MAXPATHLEN]; + char libmawtpath[MAXPATHLEN]; + const char *xawtstr = "/xawt/libmawt.so"; + const char *motifstr = "/motif21/libmawt.so"; + char *p; + + // Get path to libjvm.so + os::jvm_path(buf, sizeof(buf)); + + // Get rid of libjvm.so + p = strrchr(buf, '/'); + if (p == NULL) return false; + else *p = '\0'; + + // Get rid of client or server + p = strrchr(buf, '/'); + if (p == NULL) return false; + else *p = '\0'; + + // check xawt/libmawt.so + strcpy(libmawtpath, buf); + strcat(libmawtpath, xawtstr); + if (::stat(libmawtpath, &statbuf) == 0) return false; + + // check motif21/libmawt.so + strcpy(libmawtpath, buf); + strcat(libmawtpath, motifstr); + if (::stat(libmawtpath, &statbuf) == 0) return false; + + return true; +} + + diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 2e5cee6c5f4..f2b7eedcb5e 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -3444,6 +3444,9 @@ jint os::init_2(void) { return JNI_OK; } +void os::init_3(void) { + return; +} // Mark the polling page as unreadable void os::make_polling_page_unreadable(void) { @@ -4105,12 +4108,10 @@ bool os::check_heap(bool force) { } -#ifndef PRODUCT -bool os::find(address addr) { +bool os::find(address addr, outputStream* st) { // Nothing yet return false; } -#endif LONG WINAPI os::win32::serialize_fault_filter(struct _EXCEPTION_POINTERS* e) { DWORD exception_code = e->ExceptionRecord->ExceptionCode; @@ -4164,3 +4165,8 @@ static int getLastErrorString(char *buf, size_t len) } return 0; } + + +// We don't build a headless jre for Windows +bool os::is_headless_jre() { return false; } + diff --git a/hotspot/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp index 5d1bdac4a1d..7b44e39eee7 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp @@ -105,3 +105,6 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, // nothing else to try return false; } + +void JavaThread::cache_global_variables() { } + diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp index 6877c5ad00d..29b93ec6dd4 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp @@ -718,6 +718,11 @@ void os::print_context(outputStream *st, void *context) { ucontext_t *uc = (ucontext_t*)context; st->print_cr("Registers:"); + + // this is horrendously verbose but the layout of the registers in the + // context does not match how we defined our abstract Register set, so + // we can't just iterate through the gregs area + #ifdef AMD64 st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); @@ -745,6 +750,63 @@ void os::print_context(outputStream *st, void *context) { st->print(", ERR=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ERR]); st->cr(); st->print(" TRAPNO=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_TRAPNO]); + + st->cr(); + st->cr(); + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + + st->print_cr("RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); + print_location(st, uc->uc_mcontext.gregs[REG_RAX]); + st->cr(); + st->print_cr("RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); + print_location(st, uc->uc_mcontext.gregs[REG_RBX]); + st->cr(); + st->print_cr("RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]); + print_location(st, uc->uc_mcontext.gregs[REG_RCX]); + st->cr(); + st->print_cr("RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]); + print_location(st, uc->uc_mcontext.gregs[REG_RDX]); + st->cr(); + st->print_cr("RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]); + print_location(st, uc->uc_mcontext.gregs[REG_RSP]); + st->cr(); + st->print_cr("RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]); + print_location(st, uc->uc_mcontext.gregs[REG_RBP]); + st->cr(); + st->print_cr("RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); + print_location(st, uc->uc_mcontext.gregs[REG_RSI]); + st->cr(); + st->print_cr("RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); + print_location(st, uc->uc_mcontext.gregs[REG_RDI]); + st->cr(); + st->print_cr("R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); + print_location(st, uc->uc_mcontext.gregs[REG_R8]); + st->cr(); + st->print_cr("R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); + print_location(st, uc->uc_mcontext.gregs[REG_R9]); + st->cr(); + st->print_cr("R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); + print_location(st, uc->uc_mcontext.gregs[REG_R10]); + st->cr(); + st->print_cr("R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); + print_location(st, uc->uc_mcontext.gregs[REG_R11]); + st->cr(); + st->print_cr("R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]); + print_location(st, uc->uc_mcontext.gregs[REG_R12]); + st->cr(); + st->print_cr("R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]); + print_location(st, uc->uc_mcontext.gregs[REG_R13]); + st->cr(); + st->print_cr("R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]); + print_location(st, uc->uc_mcontext.gregs[REG_R14]); + st->cr(); + st->print_cr("R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); + print_location(st, uc->uc_mcontext.gregs[REG_R15]); + #else st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]); st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]); @@ -759,6 +821,39 @@ void os::print_context(outputStream *st, void *context) { st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]); st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2); st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); + + st->cr(); + st->cr(); + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + + st->print_cr("EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]); + print_location(st, uc->uc_mcontext.gregs[REG_EAX]); + st->cr(); + st->print_cr("EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]); + print_location(st, uc->uc_mcontext.gregs[REG_EBX]); + st->cr(); + st->print_cr("ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ECX]); + print_location(st, uc->uc_mcontext.gregs[REG_ECX]); + st->cr(); + st->print_cr("EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDX]); + print_location(st, uc->uc_mcontext.gregs[REG_EDX]); + st->cr(); + st->print_cr("ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ESP]); + print_location(st, uc->uc_mcontext.gregs[REG_ESP]); + st->cr(); + st->print_cr("EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBP]); + print_location(st, uc->uc_mcontext.gregs[REG_EBP]); + st->cr(); + st->print_cr("ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ESI]); + print_location(st, uc->uc_mcontext.gregs[REG_ESI]); + st->cr(); + st->print_cr("EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]); + print_location(st, uc->uc_mcontext.gregs[REG_EDI]); + #endif // AMD64 st->cr(); st->cr(); diff --git a/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp index 8347bcccd9a..b3089810813 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp +++ b/hotspot/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp @@ -79,3 +79,6 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, // nothing else to try return false; } + +void JavaThread::cache_global_variables() { } + diff --git a/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp b/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp index 1e7f6703a71..15dba5fff97 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp +++ b/hotspot/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp @@ -24,3 +24,5 @@ */ // This file is intentionally empty + +void JavaThread::cache_global_variables() { } diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp index 8ca2aeb425c..91ae05ace11 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp @@ -587,6 +587,61 @@ void os::print_context(outputStream *st, void *context) { st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_PC], uc->uc_mcontext.gregs[REG_nPC]); + + st->cr(); + st->cr(); + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + + st->print_cr("O0=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O0]); + print_location(st, uc->uc_mcontext.gregs[REG_O0]); + st->cr(); + st->print_cr("O1=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O1]); + print_location(st, uc->uc_mcontext.gregs[REG_O1]); + st->cr(); + st->print_cr("O2=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O2]); + print_location(st, uc->uc_mcontext.gregs[REG_O2]); + st->cr(); + st->print_cr("O3=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O3]); + print_location(st, uc->uc_mcontext.gregs[REG_O3]); + st->cr(); + st->print_cr("O4=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O4]); + print_location(st, uc->uc_mcontext.gregs[REG_O4]); + st->cr(); + st->print_cr("O5=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O5]); + print_location(st, uc->uc_mcontext.gregs[REG_O5]); + st->cr(); + st->print_cr("O6=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O6]); + print_location(st, uc->uc_mcontext.gregs[REG_O6]); + st->cr(); + st->print_cr("O7=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O7]); + print_location(st, uc->uc_mcontext.gregs[REG_O7]); + st->cr(); + + st->print_cr("G1=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G1]); + print_location(st, uc->uc_mcontext.gregs[REG_G1]); + st->cr(); + st->print_cr("G2=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G2]); + print_location(st, uc->uc_mcontext.gregs[REG_G2]); + st->cr(); + st->print_cr("G3=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G3]); + print_location(st, uc->uc_mcontext.gregs[REG_G3]); + st->cr(); + st->print_cr("G4=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G4]); + print_location(st, uc->uc_mcontext.gregs[REG_G4]); + st->cr(); + st->print_cr("G5=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G5]); + print_location(st, uc->uc_mcontext.gregs[REG_G5]); + st->cr(); + st->print_cr("G6=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G6]); + print_location(st, uc->uc_mcontext.gregs[REG_G6]); + st->cr(); + st->print_cr("G7=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G7]); + print_location(st, uc->uc_mcontext.gregs[REG_G7]); + st->cr(); st->cr(); diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp index 6b8bc2a3656..84efd5e76d1 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp @@ -140,3 +140,6 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, *fr_addr = ret_frame; return true; } + +void JavaThread::cache_global_variables() { } + diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index 96c95448ab2..a80374a0095 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -719,6 +719,11 @@ void os::print_context(outputStream *st, void *context) { ucontext_t *uc = (ucontext_t*)context; st->print_cr("Registers:"); + + // this is horrendously verbose but the layout of the registers in the + // context does not match how we defined our abstract Register set, so + // we can't just iterate through the gregs area + #ifdef AMD64 st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); @@ -742,6 +747,63 @@ void os::print_context(outputStream *st, void *context) { st->cr(); st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); st->print(", RFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RFL]); + + st->cr(); + st->cr(); + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + + st->print_cr("RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); + print_location(st, uc->uc_mcontext.gregs[REG_RAX]); + st->cr(); + st->print_cr("RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); + print_location(st, uc->uc_mcontext.gregs[REG_RBX]); + st->cr(); + st->print_cr("RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]); + print_location(st, uc->uc_mcontext.gregs[REG_RCX]); + st->cr(); + st->print_cr("RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]); + print_location(st, uc->uc_mcontext.gregs[REG_RDX]); + st->cr(); + st->print_cr("RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]); + print_location(st, uc->uc_mcontext.gregs[REG_RSP]); + st->cr(); + st->print_cr("RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]); + print_location(st, uc->uc_mcontext.gregs[REG_RSP]); + st->cr(); + st->print_cr("RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); + print_location(st, uc->uc_mcontext.gregs[REG_RSI]); + st->cr(); + st->print_cr("RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); + print_location(st, uc->uc_mcontext.gregs[REG_RDI]); + st->cr(); + st->print_cr("R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); + print_location(st, uc->uc_mcontext.gregs[REG_R8]); + st->cr(); + st->print_cr("R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); + print_location(st, uc->uc_mcontext.gregs[REG_R9]); + st->cr(); + st->print_cr("R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); + print_location(st, uc->uc_mcontext.gregs[REG_R10]); + st->cr(); + st->print_cr("R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); + print_location(st, uc->uc_mcontext.gregs[REG_R11]); + st->cr(); + st->print_cr("R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]); + print_location(st, uc->uc_mcontext.gregs[REG_R12]); + st->cr(); + st->print_cr("R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]); + print_location(st, uc->uc_mcontext.gregs[REG_R13]); + st->cr(); + st->print_cr("R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]); + print_location(st, uc->uc_mcontext.gregs[REG_R14]); + st->cr(); + st->print_cr("R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); + print_location(st, uc->uc_mcontext.gregs[REG_R15]); + #else st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]); st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]); @@ -755,6 +817,39 @@ void os::print_context(outputStream *st, void *context) { st->cr(); st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EIP]); st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EFL]); + + st->cr(); + st->cr(); + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + + st->print_cr("EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]); + print_location(st, uc->uc_mcontext.gregs[EAX]); + st->cr(); + st->print_cr("EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]); + print_location(st, uc->uc_mcontext.gregs[EBX]); + st->cr(); + st->print_cr("ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ECX]); + print_location(st, uc->uc_mcontext.gregs[ECX]); + st->cr(); + st->print_cr("EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDX]); + print_location(st, uc->uc_mcontext.gregs[EDX]); + st->cr(); + st->print_cr("ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[UESP]); + print_location(st, uc->uc_mcontext.gregs[UESP]); + st->cr(); + st->print_cr("EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBP]); + print_location(st, uc->uc_mcontext.gregs[EBP]); + st->cr(); + st->print_cr("ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ESI]); + print_location(st, uc->uc_mcontext.gregs[ESI]); + st->cr(); + st->print_cr("EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDI]); + print_location(st, uc->uc_mcontext.gregs[EDI]); + #endif // AMD64 st->cr(); st->cr(); @@ -773,6 +868,7 @@ void os::print_context(outputStream *st, void *context) { print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); } + #ifdef AMD64 void os::Solaris::init_thread_fpu_state(void) { // Nothing to do diff --git a/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp index 115f27fa013..fa308d54630 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp @@ -82,3 +82,6 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, return true; } + +void JavaThread::cache_global_variables() { } + diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp index f22821311e8..8cc55b78c3d 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp @@ -377,18 +377,84 @@ void os::print_context(outputStream *st, void *context) { st->print_cr("Registers:"); #ifdef AMD64 - st->print( "EAX=" INTPTR_FORMAT, uc->Rax); - st->print(", EBX=" INTPTR_FORMAT, uc->Rbx); - st->print(", ECX=" INTPTR_FORMAT, uc->Rcx); - st->print(", EDX=" INTPTR_FORMAT, uc->Rdx); + st->print( "RAX=" INTPTR_FORMAT, uc->Rax); + st->print(", RBX=" INTPTR_FORMAT, uc->Rbx); + st->print(", RCX=" INTPTR_FORMAT, uc->Rcx); + st->print(", RDX=" INTPTR_FORMAT, uc->Rdx); st->cr(); - st->print( "ESP=" INTPTR_FORMAT, uc->Rsp); - st->print(", EBP=" INTPTR_FORMAT, uc->Rbp); - st->print(", ESI=" INTPTR_FORMAT, uc->Rsi); - st->print(", EDI=" INTPTR_FORMAT, uc->Rdi); + st->print( "RSP=" INTPTR_FORMAT, uc->Rsp); + st->print(", RBP=" INTPTR_FORMAT, uc->Rbp); + st->print(", RSI=" INTPTR_FORMAT, uc->Rsi); + st->print(", RDI=" INTPTR_FORMAT, uc->Rdi); st->cr(); - st->print( "EIP=" INTPTR_FORMAT, uc->Rip); + st->print( "R8=" INTPTR_FORMAT, uc->R8); + st->print(", R9=" INTPTR_FORMAT, uc->R9); + st->print(", R10=" INTPTR_FORMAT, uc->R10); + st->print(", R11=" INTPTR_FORMAT, uc->R11); + st->cr(); + st->print( "R12=" INTPTR_FORMAT, uc->R12); + st->print(", R13=" INTPTR_FORMAT, uc->R13); + st->print(", R14=" INTPTR_FORMAT, uc->R14); + st->print(", R15=" INTPTR_FORMAT, uc->R15); + st->cr(); + st->print( "RIP=" INTPTR_FORMAT, uc->Rip); st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags); + + st->cr(); + st->cr(); + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + + st->print_cr("RAX=" INTPTR_FORMAT, uc->Rax); + print_location(st, uc->Rax); + st->cr(); + st->print_cr("RBX=" INTPTR_FORMAT, uc->Rbx); + print_location(st, uc->Rbx); + st->cr(); + st->print_cr("RCX=" INTPTR_FORMAT, uc->Rcx); + print_location(st, uc->Rcx); + st->cr(); + st->print_cr("RDX=" INTPTR_FORMAT, uc->Rdx); + print_location(st, uc->Rdx); + st->cr(); + st->print_cr("RSP=" INTPTR_FORMAT, uc->Rsp); + print_location(st, uc->Rsp); + st->cr(); + st->print_cr("RBP=" INTPTR_FORMAT, uc->Rbp); + print_location(st, uc->Rbp); + st->cr(); + st->print_cr("RSI=" INTPTR_FORMAT, uc->Rsi); + print_location(st, uc->Rsi); + st->cr(); + st->print_cr("RDI=" INTPTR_FORMAT, uc->Rdi); + print_location(st, uc->Rdi); + st->cr(); + st->print_cr("R8 =" INTPTR_FORMAT, uc->R8); + print_location(st, uc->R8); + st->cr(); + st->print_cr("R9 =" INTPTR_FORMAT, uc->R9); + print_location(st, uc->R9); + st->cr(); + st->print_cr("R10=" INTPTR_FORMAT, uc->R10); + print_location(st, uc->R10); + st->cr(); + st->print_cr("R11=" INTPTR_FORMAT, uc->R11); + print_location(st, uc->R11); + st->cr(); + st->print_cr("R12=" INTPTR_FORMAT, uc->R12); + print_location(st, uc->R12); + st->cr(); + st->print_cr("R13=" INTPTR_FORMAT, uc->R13); + print_location(st, uc->R13); + st->cr(); + st->print_cr("R14=" INTPTR_FORMAT, uc->R14); + print_location(st, uc->R14); + st->cr(); + st->print_cr("R15=" INTPTR_FORMAT, uc->R15); + print_location(st, uc->R15); #else st->print( "EAX=" INTPTR_FORMAT, uc->Eax); st->print(", EBX=" INTPTR_FORMAT, uc->Ebx); @@ -402,6 +468,38 @@ void os::print_context(outputStream *st, void *context) { st->cr(); st->print( "EIP=" INTPTR_FORMAT, uc->Eip); st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags); + + st->cr(); + st->cr(); + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + + st->print_cr("EAX=" INTPTR_FORMAT, uc->Eax); + print_location(st, uc->Eax); + st->cr(); + st->print_cr("EBX=" INTPTR_FORMAT, uc->Ebx); + print_location(st, uc->Ebx); + st->cr(); + st->print_cr("ECX=" INTPTR_FORMAT, uc->Ecx); + print_location(st, uc->Ecx); + st->cr(); + st->print_cr("EDX=" INTPTR_FORMAT, uc->Edx); + print_location(st, uc->Edx); + st->cr(); + st->print_cr("ESP=" INTPTR_FORMAT, uc->Esp); + print_location(st, uc->Esp); + st->cr(); + st->print_cr("EBP=" INTPTR_FORMAT, uc->Ebp); + print_location(st, uc->Ebp); + st->cr(); + st->print_cr("ESI=" INTPTR_FORMAT, uc->Esi); + print_location(st, uc->Esi); + st->cr(); + st->print_cr("EDI=" INTPTR_FORMAT, uc->Edi); + print_location(st, uc->Edi); #endif // AMD64 st->cr(); st->cr(); diff --git a/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp index 43716368f56..7334845c3d9 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp @@ -84,3 +84,6 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, // nothing else to try return false; } + +void JavaThread::cache_global_variables() { } + diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index 4c7aab94d58..77e7cdb8727 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -128,7 +128,11 @@ CodeBuffer::~CodeBuffer() { delete _overflow_arena; #ifdef ASSERT + // Save allocation type to execute assert in ~ResourceObj() + // which is called after this destructor. + ResourceObj::allocation_type at = _default_oop_recorder.get_allocation_type(); Copy::fill_to_bytes(this, sizeof(*this), badResourceValue); + ResourceObj::set_allocation_type((address)(&_default_oop_recorder), at); #endif } diff --git a/hotspot/src/share/vm/asm/codeBuffer.hpp b/hotspot/src/share/vm/asm/codeBuffer.hpp index 2f1a8d3c8fe..8e4a4ea323c 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.hpp +++ b/hotspot/src/share/vm/asm/codeBuffer.hpp @@ -102,7 +102,7 @@ class CodeSection VALUE_OBJ_CLASS_SPEC { _locs_point = NULL; _locs_own = false; _frozen = false; - debug_only(_index = -1); + debug_only(_index = (char)-1); debug_only(_outer = (CodeBuffer*)badAddress); } @@ -278,7 +278,7 @@ class CodeBuffer: public StackObj { // special case during expansion which is handled internally. This // is done to guarantee proper cleanup of resources. void* operator new(size_t size) { return ResourceObj::operator new(size); } - void operator delete(void* p) { ResourceObj::operator delete(p); } + void operator delete(void* p) { ShouldNotCallThis(); } public: typedef int csize_t; // code size type; would be size_t except for history diff --git a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp index 547e2d70a82..07ed4302dd9 100644 --- a/hotspot/src/share/vm/c1/c1_CodeStubs.hpp +++ b/hotspot/src/share/vm/c1/c1_CodeStubs.hpp @@ -448,6 +448,10 @@ class SimpleExceptionStub: public CodeStub { _obj(obj), _info(info), _stub(stub) { } + void set_obj(LIR_Opr obj) { + _obj = obj; + } + virtual void emit_code(LIR_Assembler* e); virtual CodeEmitInfo* info() const { return _info; } virtual bool is_exception_throw_stub() const { return true; } diff --git a/hotspot/src/share/vm/c1/c1_Compilation.cpp b/hotspot/src/share/vm/c1/c1_Compilation.cpp index ac47342f45a..d9156c1b307 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.cpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp @@ -220,11 +220,13 @@ void Compilation::emit_code_epilog(LIR_Assembler* assembler) { code_offsets->set_value(CodeOffsets::Deopt, assembler->emit_deopt_handler()); CHECK_BAILOUT(); - // Generate code for MethodHandle deopt handler. We can use the - // same code as for the normal deopt handler, we just need a - // different entry point address. - code_offsets->set_value(CodeOffsets::DeoptMH, assembler->emit_deopt_handler()); - CHECK_BAILOUT(); + // Emit the MethodHandle deopt handler code (if required). + if (has_method_handle_invokes()) { + // We can use the same code as for the normal deopt handler, we + // just need a different entry point address. + code_offsets->set_value(CodeOffsets::DeoptMH, assembler->emit_deopt_handler()); + CHECK_BAILOUT(); + } // Emit the handler to remove the activation from the stack and // dispatch to the caller. @@ -446,6 +448,7 @@ Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* metho , _has_exception_handlers(false) , _has_fpu_code(true) // pessimistic assumption , _has_unsafe_access(false) +, _has_method_handle_invokes(false) , _bailout_msg(NULL) , _exception_info_list(NULL) , _allocator(NULL) diff --git a/hotspot/src/share/vm/c1/c1_Compilation.hpp b/hotspot/src/share/vm/c1/c1_Compilation.hpp index 86d6cbf7a05..82c1699ea91 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.hpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp @@ -69,6 +69,7 @@ class Compilation: public StackObj { bool _has_exception_handlers; bool _has_fpu_code; bool _has_unsafe_access; + bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. const char* _bailout_msg; ExceptionInfoList* _exception_info_list; ExceptionHandlerTable _exception_handler_table; @@ -147,6 +148,10 @@ class Compilation: public StackObj { // Statistics gathering void notice_inlined_method(ciMethod* method); + // JSR 292 + bool has_method_handle_invokes() const { return _has_method_handle_invokes; } + void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } + DebugInformationRecorder* debug_info_recorder() const; // = _env->debug_info(); Dependencies* dependency_recorder() const; // = _env->dependencies() ImplicitExceptionTable* implicit_exception_table() { return &_implicit_exception_table; } @@ -168,10 +173,19 @@ class Compilation: public StackObj { const char* bailout_msg() const { return _bailout_msg; } static int desired_max_code_buffer_size() { +#ifndef PPC return (int) NMethodSizeLimit; // default 256K or 512K +#else + // conditional branches on PPC are restricted to 16 bit signed + return MAX2((unsigned int)NMethodSizeLimit,32*K); +#endif } static int desired_max_constant_size() { +#ifndef PPC return (int) NMethodSizeLimit / 10; // about 25K +#else + return (MAX2((unsigned int)NMethodSizeLimit, 32*K)) / 10; +#endif } static void setup_code_buffer(CodeBuffer* cb, int call_stub_estimate); diff --git a/hotspot/src/share/vm/c1/c1_FrameMap.cpp b/hotspot/src/share/vm/c1/c1_FrameMap.cpp index 55fd77b9809..139572dd138 100644 --- a/hotspot/src/share/vm/c1/c1_FrameMap.cpp +++ b/hotspot/src/share/vm/c1/c1_FrameMap.cpp @@ -90,7 +90,7 @@ CallingConvention* FrameMap::java_calling_convention(const BasicTypeArray* signa if (outgoing) { // update the space reserved for arguments. - update_reserved_argument_area_size(out_preserve); + update_reserved_argument_area_size(out_preserve * BytesPerWord); } return new CallingConvention(args, out_preserve); } @@ -138,7 +138,7 @@ CallingConvention* FrameMap::c_calling_convention(const BasicTypeArray* signatur } assert(args->length() == signature->length(), "size mismatch"); out_preserve += SharedRuntime::out_preserve_stack_slots(); - update_reserved_argument_area_size(out_preserve); + update_reserved_argument_area_size(out_preserve * BytesPerWord); return new CallingConvention(args, out_preserve); } diff --git a/hotspot/src/share/vm/c1/c1_FrameMap.hpp b/hotspot/src/share/vm/c1/c1_FrameMap.hpp index 4c4c99a7492..4a229d6bf7e 100644 --- a/hotspot/src/share/vm/c1/c1_FrameMap.hpp +++ b/hotspot/src/share/vm/c1/c1_FrameMap.hpp @@ -154,7 +154,6 @@ class FrameMap : public CompilationResourceObj { static LIR_Opr method_handle_invoke_SP_save_opr(); static BasicTypeArray* signature_type_array_for(const ciMethod* method); - static BasicTypeArray* signature_type_array_for(const char * signature); // for outgoing calls, these also update the reserved area to // include space for arguments and any ABI area. diff --git a/hotspot/src/share/vm/c1/c1_LIR.cpp b/hotspot/src/share/vm/c1/c1_LIR.cpp index 6aa0f5e0f22..a55ed09fc49 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.cpp +++ b/hotspot/src/share/vm/c1/c1_LIR.cpp @@ -50,8 +50,7 @@ XMMRegister LIR_OprDesc::as_xmm_double_reg() const { #endif // X86 - -#ifdef SPARC +#if defined(SPARC) || defined(PPC) FloatRegister LIR_OprDesc::as_float_reg() const { return FrameMap::nr2floatreg(fpu_regnr()); @@ -63,6 +62,19 @@ FloatRegister LIR_OprDesc::as_double_reg() const { #endif +#ifdef ARM + +FloatRegister LIR_OprDesc::as_float_reg() const { + return as_FloatRegister(fpu_regnr()); +} + +FloatRegister LIR_OprDesc::as_double_reg() const { + return as_FloatRegister(fpu_regnrLo()); +} + +#endif + + LIR_Opr LIR_OprFact::illegalOpr = LIR_OprFact::illegal(); LIR_Opr LIR_OprFact::value_type(ValueType* type) { @@ -119,10 +131,14 @@ LIR_Address::Scale LIR_Address::scale(BasicType type) { #ifndef PRODUCT void LIR_Address::verify() const { -#ifdef SPARC - assert(scale() == times_1, "Scaled addressing mode not available on SPARC and should not be used"); +#if defined(SPARC) || defined(PPC) + assert(scale() == times_1, "Scaled addressing mode not available on SPARC/PPC and should not be used"); assert(disp() == 0 || index()->is_illegal(), "can't have both"); #endif +#ifdef ARM + assert(disp() == 0 || index()->is_illegal(), "can't have both"); + assert(-4096 < disp() && disp() < 4096, "architecture constraint"); +#endif #ifdef _LP64 assert(base()->is_cpu_register(), "wrong base operand"); assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand"); @@ -173,13 +189,22 @@ void LIR_OprDesc::validate_type() const { if (!is_pointer() && !is_illegal()) { switch (as_BasicType(type_field())) { case T_LONG: - assert((kind_field() == cpu_register || kind_field() == stack_value) && size_field() == double_size, "must match"); + assert((kind_field() == cpu_register || kind_field() == stack_value) && + size_field() == double_size, "must match"); break; case T_FLOAT: - assert((kind_field() == fpu_register || kind_field() == stack_value) && size_field() == single_size, "must match"); + // FP return values can be also in CPU registers on ARM and PPC (softfp ABI) + assert((kind_field() == fpu_register || kind_field() == stack_value + ARM_ONLY(|| kind_field() == cpu_register) + PPC_ONLY(|| kind_field() == cpu_register) ) && + size_field() == single_size, "must match"); break; case T_DOUBLE: - assert((kind_field() == fpu_register || kind_field() == stack_value) && size_field() == double_size, "must match"); + // FP return values can be also in CPU registers on ARM and PPC (softfp ABI) + assert((kind_field() == fpu_register || kind_field() == stack_value + ARM_ONLY(|| kind_field() == cpu_register) + PPC_ONLY(|| kind_field() == cpu_register) ) && + size_field() == double_size, "must match"); break; case T_BOOLEAN: case T_CHAR: @@ -188,7 +213,8 @@ void LIR_OprDesc::validate_type() const { case T_INT: case T_OBJECT: case T_ARRAY: - assert((kind_field() == cpu_register || kind_field() == stack_value) && size_field() == single_size, "must match"); + assert((kind_field() == cpu_register || kind_field() == stack_value) && + size_field() == single_size, "must match"); break; case T_ILLEGAL: @@ -503,6 +529,10 @@ void LIR_OpVisitState::visit(LIR_Op* op) { assert(opConvert->_info == NULL, "must be"); if (opConvert->_opr->is_valid()) do_input(opConvert->_opr); if (opConvert->_result->is_valid()) do_output(opConvert->_result); +#ifdef PPC + if (opConvert->_tmp1->is_valid()) do_temp(opConvert->_tmp1); + if (opConvert->_tmp2->is_valid()) do_temp(opConvert->_tmp2); +#endif do_stub(opConvert->_stub); break; @@ -530,7 +560,9 @@ void LIR_OpVisitState::visit(LIR_Op* op) { LIR_OpAllocObj* opAllocObj = (LIR_OpAllocObj*)op; if (opAllocObj->_info) do_info(opAllocObj->_info); - if (opAllocObj->_opr->is_valid()) do_input(opAllocObj->_opr); + if (opAllocObj->_opr->is_valid()) { do_input(opAllocObj->_opr); + do_temp(opAllocObj->_opr); + } if (opAllocObj->_tmp1->is_valid()) do_temp(opAllocObj->_tmp1); if (opAllocObj->_tmp2->is_valid()) do_temp(opAllocObj->_tmp2); if (opAllocObj->_tmp3->is_valid()) do_temp(opAllocObj->_tmp3); @@ -826,10 +858,16 @@ void LIR_OpVisitState::visit(LIR_Op* op) { assert(op->as_OpCompareAndSwap() != NULL, "must be"); LIR_OpCompareAndSwap* opCompareAndSwap = (LIR_OpCompareAndSwap*)op; + assert(opCompareAndSwap->_addr->is_valid(), "used"); + assert(opCompareAndSwap->_cmp_value->is_valid(), "used"); + assert(opCompareAndSwap->_new_value->is_valid(), "used"); if (opCompareAndSwap->_info) do_info(opCompareAndSwap->_info); - if (opCompareAndSwap->_addr->is_valid()) do_input(opCompareAndSwap->_addr); - if (opCompareAndSwap->_cmp_value->is_valid()) do_input(opCompareAndSwap->_cmp_value); - if (opCompareAndSwap->_new_value->is_valid()) do_input(opCompareAndSwap->_new_value); + do_input(opCompareAndSwap->_addr); + do_temp(opCompareAndSwap->_addr); + do_input(opCompareAndSwap->_cmp_value); + do_temp(opCompareAndSwap->_cmp_value); + do_input(opCompareAndSwap->_new_value); + do_temp(opCompareAndSwap->_new_value); if (opCompareAndSwap->_tmp1->is_valid()) do_temp(opCompareAndSwap->_tmp1); if (opCompareAndSwap->_tmp2->is_valid()) do_temp(opCompareAndSwap->_tmp2); if (opCompareAndSwap->_result->is_valid()) do_output(opCompareAndSwap->_result); @@ -1303,13 +1341,13 @@ void LIR_List::lock_object(LIR_Opr hdr, LIR_Opr obj, LIR_Opr lock, LIR_Opr scrat info)); } -void LIR_List::unlock_object(LIR_Opr hdr, LIR_Opr obj, LIR_Opr lock, CodeStub* stub) { +void LIR_List::unlock_object(LIR_Opr hdr, LIR_Opr obj, LIR_Opr lock, LIR_Opr scratch, CodeStub* stub) { append(new LIR_OpLock( lir_unlock, hdr, obj, lock, - LIR_OprFact::illegalOpr, + scratch, stub, NULL)); } @@ -1342,22 +1380,19 @@ void LIR_List::store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr } -void LIR_List::cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2) { - // Compare and swap produces condition code "zero" if contents_of(addr) == cmp_value, - // implying successful swap of new_value into addr - append(new LIR_OpCompareAndSwap(lir_cas_long, addr, cmp_value, new_value, t1, t2)); +void LIR_List::cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, + LIR_Opr t1, LIR_Opr t2, LIR_Opr result) { + append(new LIR_OpCompareAndSwap(lir_cas_long, addr, cmp_value, new_value, t1, t2, result)); } -void LIR_List::cas_obj(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2) { - // Compare and swap produces condition code "zero" if contents_of(addr) == cmp_value, - // implying successful swap of new_value into addr - append(new LIR_OpCompareAndSwap(lir_cas_obj, addr, cmp_value, new_value, t1, t2)); +void LIR_List::cas_obj(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, + LIR_Opr t1, LIR_Opr t2, LIR_Opr result) { + append(new LIR_OpCompareAndSwap(lir_cas_obj, addr, cmp_value, new_value, t1, t2, result)); } -void LIR_List::cas_int(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2) { - // Compare and swap produces condition code "zero" if contents_of(addr) == cmp_value, - // implying successful swap of new_value into addr - append(new LIR_OpCompareAndSwap(lir_cas_int, addr, cmp_value, new_value, t1, t2)); +void LIR_List::cas_int(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, + LIR_Opr t1, LIR_Opr t2, LIR_Opr result) { + append(new LIR_OpCompareAndSwap(lir_cas_int, addr, cmp_value, new_value, t1, t2, result)); } @@ -1400,6 +1435,11 @@ void LIR_OprDesc::print(outputStream* out) const { out->print("fpu%d", fpu_regnr()); } else if (is_double_fpu()) { out->print("fpu%d", fpu_regnrLo()); +#elif defined(ARM) + } else if (is_single_fpu()) { + out->print("s%d", fpu_regnr()); + } else if (is_double_fpu()) { + out->print("d%d", fpu_regnrLo() >> 1); #else } else if (is_single_fpu()) { out->print(as_float_reg()->name()); @@ -1756,6 +1796,12 @@ void LIR_OpConvert::print_instr(outputStream* out) const { print_bytecode(out, bytecode()); in_opr()->print(out); out->print(" "); result_opr()->print(out); out->print(" "); +#ifdef PPC + if(tmp1()->is_valid()) { + tmp1()->print(out); out->print(" "); + tmp2()->print(out); out->print(" "); + } +#endif } void LIR_OpConvert::print_bytecode(outputStream* out, Bytecodes::Code code) { diff --git a/hotspot/src/share/vm/c1/c1_LIR.hpp b/hotspot/src/share/vm/c1/c1_LIR.hpp index aabcfaa84f2..5c7dc4feb07 100644 --- a/hotspot/src/share/vm/c1/c1_LIR.hpp +++ b/hotspot/src/share/vm/c1/c1_LIR.hpp @@ -432,8 +432,7 @@ class LIR_OprDesc: public CompilationResourceObj { // for compatibility with RInfo int fpu () const { return lo_reg_half(); } #endif // X86 - -#ifdef SPARC +#if defined(SPARC) || defined(ARM) || defined(PPC) FloatRegister as_float_reg () const; FloatRegister as_double_reg () const; #endif @@ -519,14 +518,14 @@ class LIR_Address: public LIR_OprPtr { , _type(type) , _disp(0) { verify(); } -#ifdef X86 +#if defined(X86) || defined(ARM) LIR_Address(LIR_Opr base, LIR_Opr index, Scale scale, intx disp, BasicType type): _base(base) , _index(index) , _scale(scale) , _type(type) , _disp(disp) { verify(); } -#endif // X86 +#endif // X86 || ARM LIR_Opr base() const { return _base; } LIR_Opr index() const { return _index; } @@ -566,7 +565,11 @@ class LIR_OprFact: public AllStatic { LIR_OprDesc::float_type | LIR_OprDesc::fpu_register | LIR_OprDesc::single_size); } - +#if defined(ARM) + static LIR_Opr double_fpu(int reg1, int reg2) { return (LIR_Opr)((reg1 << LIR_OprDesc::reg1_shift) | (reg2 << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::fpu_register | LIR_OprDesc::double_size); } + static LIR_Opr single_softfp(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | LIR_OprDesc::float_type | LIR_OprDesc::cpu_register | LIR_OprDesc::single_size); } + static LIR_Opr double_softfp(int reg1, int reg2) { return (LIR_Opr)((reg1 << LIR_OprDesc::reg1_shift) | (reg2 << LIR_OprDesc::reg2_shift) | LIR_OprDesc::double_type | LIR_OprDesc::cpu_register | LIR_OprDesc::double_size); } +#endif #ifdef SPARC static LIR_Opr double_fpu(int reg1, int reg2) { return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | (reg2 << LIR_OprDesc::reg2_shift) | @@ -593,7 +596,22 @@ class LIR_OprFact: public AllStatic { LIR_OprDesc::double_size | LIR_OprDesc::is_xmm_mask); } #endif // X86 - +#ifdef PPC + static LIR_Opr double_fpu(int reg) { return (LIR_Opr)(intptr_t)((reg << LIR_OprDesc::reg1_shift) | + (reg << LIR_OprDesc::reg2_shift) | + LIR_OprDesc::double_type | + LIR_OprDesc::fpu_register | + LIR_OprDesc::double_size); } + static LIR_Opr single_softfp(int reg) { return (LIR_Opr)((reg << LIR_OprDesc::reg1_shift) | + LIR_OprDesc::float_type | + LIR_OprDesc::cpu_register | + LIR_OprDesc::single_size); } + static LIR_Opr double_softfp(int reg1, int reg2) { return (LIR_Opr)((reg2 << LIR_OprDesc::reg1_shift) | + (reg1 << LIR_OprDesc::reg2_shift) | + LIR_OprDesc::double_type | + LIR_OprDesc::cpu_register | + LIR_OprDesc::double_size); } +#endif // PPC static LIR_Opr virtual_register(int index, BasicType type) { LIR_Opr res; @@ -623,6 +641,22 @@ class LIR_OprFact: public AllStatic { LIR_OprDesc::virtual_mask); break; +#ifdef __SOFTFP__ + case T_FLOAT: + res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | + LIR_OprDesc::float_type | + LIR_OprDesc::cpu_register | + LIR_OprDesc::single_size | + LIR_OprDesc::virtual_mask); + break; + case T_DOUBLE: + res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | + LIR_OprDesc::double_type | + LIR_OprDesc::cpu_register | + LIR_OprDesc::double_size | + LIR_OprDesc::virtual_mask); + break; +#else // __SOFTFP__ case T_FLOAT: res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | LIR_OprDesc::float_type | @@ -638,7 +672,7 @@ class LIR_OprFact: public AllStatic { LIR_OprDesc::double_size | LIR_OprDesc::virtual_mask); break; - +#endif // __SOFTFP__ default: ShouldNotReachHere(); res = illegalOpr; } @@ -650,11 +684,18 @@ class LIR_OprFact: public AllStatic { // old-style calculation; check if old and new method are equal LIR_OprDesc::OprType t = as_OprType(type); +#ifdef __SOFTFP__ + LIR_Opr old_res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | + t | + LIR_OprDesc::cpu_register | + LIR_OprDesc::size_for(type) | LIR_OprDesc::virtual_mask); +#else // __SOFTFP__ LIR_Opr old_res = (LIR_Opr)(intptr_t)((index << LIR_OprDesc::data_shift) | t | ((type == T_FLOAT || type == T_DOUBLE) ? LIR_OprDesc::fpu_register : LIR_OprDesc::cpu_register) | LIR_OprDesc::size_for(type) | LIR_OprDesc::virtual_mask); assert(res == old_res, "old and new method not equal"); -#endif +#endif // __SOFTFP__ +#endif // ASSERT return res; } @@ -1306,15 +1347,37 @@ class LIR_OpConvert: public LIR_Op1 { private: Bytecodes::Code _bytecode; ConversionStub* _stub; +#ifdef PPC + LIR_Opr _tmp1; + LIR_Opr _tmp2; +#endif public: LIR_OpConvert(Bytecodes::Code code, LIR_Opr opr, LIR_Opr result, ConversionStub* stub) : LIR_Op1(lir_convert, opr, result) , _stub(stub) +#ifdef PPC + , _tmp1(LIR_OprDesc::illegalOpr()) + , _tmp2(LIR_OprDesc::illegalOpr()) +#endif , _bytecode(code) {} +#ifdef PPC + LIR_OpConvert(Bytecodes::Code code, LIR_Opr opr, LIR_Opr result, ConversionStub* stub + ,LIR_Opr tmp1, LIR_Opr tmp2) + : LIR_Op1(lir_convert, opr, result) + , _stub(stub) + , _tmp1(tmp1) + , _tmp2(tmp2) + , _bytecode(code) {} +#endif + Bytecodes::Code bytecode() const { return _bytecode; } ConversionStub* stub() const { return _stub; } +#ifdef PPC + LIR_Opr tmp1() const { return _tmp1; } + LIR_Opr tmp2() const { return _tmp2; } +#endif virtual void emit_code(LIR_Assembler* masm); virtual LIR_OpConvert* as_OpConvert() { return this; } @@ -1502,6 +1565,9 @@ class LIR_Op2: public LIR_Op { LIR_Condition condition() const { assert(code() == lir_cmp || code() == lir_cmove, "only valid for cmp and cmove"); return _condition; } + void set_condition(LIR_Condition condition) { + assert(code() == lir_cmp || code() == lir_cmove, "only valid for cmp and cmove"); _condition = condition; + } void set_fpu_stack_size(int size) { _fpu_stack_size = size; } int fpu_stack_size() const { return _fpu_stack_size; } @@ -1650,8 +1716,9 @@ class LIR_OpCompareAndSwap : public LIR_Op { LIR_Opr _tmp2; public: - LIR_OpCompareAndSwap(LIR_Code code, LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2) - : LIR_Op(code, LIR_OprFact::illegalOpr, NULL) // no result, no info + LIR_OpCompareAndSwap(LIR_Code code, LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, + LIR_Opr t1, LIR_Opr t2, LIR_Opr result) + : LIR_Op(code, result, NULL) // no result, no info , _addr(addr) , _cmp_value(cmp_value) , _new_value(new_value) @@ -1832,6 +1899,9 @@ class LIR_List: public CompilationResourceObj { void safepoint(LIR_Opr tmp, CodeEmitInfo* info) { append(new LIR_Op1(lir_safepoint, tmp, info)); } +#ifdef PPC + void convert(Bytecodes::Code code, LIR_Opr left, LIR_Opr dst, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_OpConvert(code, left, dst, NULL, tmp1, tmp2)); } +#endif void convert(Bytecodes::Code code, LIR_Opr left, LIR_Opr dst, ConversionStub* stub = NULL/*, bool is_32bit = false*/) { append(new LIR_OpConvert(code, left, dst, stub)); } void logical_and (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_and, left, right, dst)); } @@ -1867,9 +1937,12 @@ class LIR_List: public CompilationResourceObj { append(new LIR_Op2(lir_cmove, condition, src1, src2, dst)); } - void cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2); - void cas_obj(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2); - void cas_int(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, LIR_Opr t1, LIR_Opr t2); + void cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, + LIR_Opr t1, LIR_Opr t2, LIR_Opr result = LIR_OprFact::illegalOpr); + void cas_obj(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, + LIR_Opr t1, LIR_Opr t2, LIR_Opr result = LIR_OprFact::illegalOpr); + void cas_int(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, + LIR_Opr t1, LIR_Opr t2, LIR_Opr result = LIR_OprFact::illegalOpr); void abs (LIR_Opr from, LIR_Opr to, LIR_Opr tmp) { append(new LIR_Op2(lir_abs , from, tmp, to)); } void sqrt(LIR_Opr from, LIR_Opr to, LIR_Opr tmp) { append(new LIR_Op2(lir_sqrt, from, tmp, to)); } @@ -1950,7 +2023,7 @@ class LIR_List: public CompilationResourceObj { } void load_stack_address_monitor(int monitor_ix, LIR_Opr dst) { append(new LIR_Op1(lir_monaddr, LIR_OprFact::intConst(monitor_ix), dst)); } - void unlock_object(LIR_Opr hdr, LIR_Opr obj, LIR_Opr lock, CodeStub* stub); + void unlock_object(LIR_Opr hdr, LIR_Opr obj, LIR_Opr lock, LIR_Opr scratch, CodeStub* stub); void lock_object(LIR_Opr hdr, LIR_Opr obj, LIR_Opr lock, LIR_Opr scratch, CodeStub* stub, CodeEmitInfo* info); void set_24bit_fpu() { append(new LIR_Op0(lir_24bit_FPU )); } diff --git a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp index 75c713d501b..ee3c5ea8c5e 100644 --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp @@ -438,6 +438,12 @@ void LIR_Assembler::emit_call(LIR_OpJavaCall* op) { default: ShouldNotReachHere(); } + // JSR 292 + // Record if this method has MethodHandle invokes. + if (op->is_method_handle_invoke()) { + compilation()->set_has_method_handle_invokes(true); + } + #if defined(X86) && defined(TIERED) // C2 leave fpu stack dirty clean it if (UseSSE < 2) { diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 36b46eeaa9f..4e7605f2685 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -31,6 +31,12 @@ #define __ gen()->lir()-> #endif +// TODO: ARM - Use some recognizable constant which still fits architectural constraints +#ifdef ARM +#define PATCHED_ADDR (204) +#else +#define PATCHED_ADDR (max_jint) +#endif void PhiResolverState::reset(int max_vregs) { // Initialize array sizes @@ -225,13 +231,13 @@ void LIRItem::load_for_store(BasicType type) { void LIRItem::load_item_force(LIR_Opr reg) { LIR_Opr r = result(); if (r != reg) { +#if !defined(ARM) && !defined(E500V2) if (r->type() != reg->type()) { // moves between different types need an intervening spill slot - LIR_Opr tmp = _gen->force_to_spill(r, reg->type()); - __ move(tmp, reg); - } else { - __ move(r, reg); + r = _gen->force_to_spill(r, reg->type()); } +#endif + __ move(r, reg); _result = reg; } } @@ -628,14 +634,14 @@ void LIRGenerator::monitor_enter(LIR_Opr object, LIR_Opr lock, LIR_Opr hdr, LIR_ } -void LIRGenerator::monitor_exit(LIR_Opr object, LIR_Opr lock, LIR_Opr new_hdr, int monitor_no) { +void LIRGenerator::monitor_exit(LIR_Opr object, LIR_Opr lock, LIR_Opr new_hdr, LIR_Opr scratch, int monitor_no) { if (!GenerateSynchronizationCode) return; // setup registers LIR_Opr hdr = lock; lock = new_hdr; CodeStub* slow_path = new MonitorExitStub(lock, UseFastLocking, monitor_no); __ load_stack_address_monitor(monitor_no, lock); - __ unlock_object(hdr, object, lock, slow_path); + __ unlock_object(hdr, object, lock, scratch, slow_path); } @@ -1400,6 +1406,25 @@ void LIRGenerator::CardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* } assert(addr->is_register(), "must be a register at this point"); +#ifdef ARM + // TODO: ARM - move to platform-dependent code + LIR_Opr tmp = FrameMap::R14_opr; + if (VM_Version::supports_movw()) { + __ move((LIR_Opr)card_table_base, tmp); + } else { + __ move(new LIR_Address(FrameMap::Rthread_opr, in_bytes(JavaThread::card_table_base_offset()), T_ADDRESS), tmp); + } + + CardTableModRefBS* ct = (CardTableModRefBS*)_bs; + LIR_Address *card_addr = new LIR_Address(tmp, addr, (LIR_Address::Scale) -CardTableModRefBS::card_shift, 0, T_BYTE); + if(((int)ct->byte_map_base & 0xff) == 0) { + __ move(tmp, card_addr); + } else { + LIR_Opr tmp_zero = new_register(T_INT); + __ move(LIR_OprFact::intConst(0), tmp_zero); + __ move(tmp_zero, card_addr); + } +#else // ARM LIR_Opr tmp = new_pointer_register(); if (TwoOperandLIRForm) { __ move(addr, tmp); @@ -1415,6 +1440,7 @@ void LIRGenerator::CardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_OprDesc* new LIR_Address(tmp, load_constant(card_table_base), T_BYTE)); } +#endif // ARM } @@ -1507,7 +1533,7 @@ void LIRGenerator::do_StoreField(StoreField* x) { // generate_address to try to be smart about emitting the -1. // Otherwise the patching code won't know how to find the // instruction to patch. - address = new LIR_Address(object.result(), max_jint, field_type); + address = new LIR_Address(object.result(), PATCHED_ADDR, field_type); } else { address = generate_address(object.result(), x->offset(), field_type); } @@ -1584,7 +1610,7 @@ void LIRGenerator::do_LoadField(LoadField* x) { // generate_address to try to be smart about emitting the -1. // Otherwise the patching code won't know how to find the // instruction to patch. - address = new LIR_Address(object.result(), max_jint, field_type); + address = new LIR_Address(object.result(), PATCHED_ADDR, field_type); } else { address = generate_address(object.result(), x->offset(), field_type); } @@ -1844,6 +1870,8 @@ void LIRGenerator::do_UnsafeGetRaw(UnsafeGetRaw* x) { } #endif addr = new LIR_Address(base_op, index_op, LIR_Address::Scale(log2_scale), 0, dst_type); +#elif defined(ARM) + addr = generate_address(base_op, index_op, log2_scale, 0, dst_type); #else if (index_op->is_illegal() || log2_scale == 0) { #ifdef _LP64 @@ -1916,6 +1944,7 @@ void LIRGenerator::do_UnsafePutRaw(UnsafePutRaw* x) { __ convert(Bytecodes::_i2l, idx.result(), index_op); } else { #endif + // TODO: ARM also allows embedded shift in the address __ move(idx.result(), index_op); #ifdef _LP64 } @@ -2204,7 +2233,10 @@ void LIRGenerator::do_Base(Base* x) { // Assign new location to Local instruction for this local Local* local = x->state()->local_at(java_index)->as_Local(); assert(local != NULL, "Locals for incoming arguments must have been created"); +#ifndef __SOFTFP__ + // The java calling convention passes double as long and float as int. assert(as_ValueType(t)->tag() == local->type()->tag(), "check"); +#endif // __SOFTFP__ local->set_operand(dest); _instruction_for_operand.at_put_grow(dest->vreg_number(), local, NULL); java_index += type2size[t]; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp index 93d3276dd9d..4a69bd842ed 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp @@ -314,7 +314,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void logic_op (Bytecodes::Code code, LIR_Opr dst_reg, LIR_Opr left, LIR_Opr right); void monitor_enter (LIR_Opr object, LIR_Opr lock, LIR_Opr hdr, LIR_Opr scratch, int monitor_no, CodeEmitInfo* info_for_exception, CodeEmitInfo* info); - void monitor_exit (LIR_Opr object, LIR_Opr lock, LIR_Opr hdr, int monitor_no); + void monitor_exit (LIR_Opr object, LIR_Opr lock, LIR_Opr hdr, LIR_Opr scratch, int monitor_no); void new_instance (LIR_Opr dst, ciInstanceKlass* klass, LIR_Opr scratch1, LIR_Opr scratch2, LIR_Opr scratch3, LIR_Opr scratch4, LIR_Opr klass_reg, CodeEmitInfo* info); @@ -338,6 +338,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { } LIR_Address* emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, BasicType type, bool needs_card_mark); + // the helper for generate_address + void add_large_constant(LIR_Opr src, int c, LIR_Opr dest); + // machine preferences and characteristics bool can_inline_as_constant(Value i) const; bool can_inline_as_constant(LIR_Const* c) const; @@ -393,6 +396,10 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { return l; } +#ifdef __SOFTFP__ + void do_soft_float_compare(If *x); +#endif // __SOFTFP__ + void init(); SwitchRangeArray* create_lookup_ranges(TableSwitch* x); @@ -444,6 +451,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { static LIR_Opr remOutOpr(); static LIR_Opr shiftCountOpr(); LIR_Opr syncTempOpr(); + LIR_Opr atomicLockOpr(); // returns a register suitable for saving the thread in a // call_runtime_leaf if one is needed. diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index 0888bef3c01..b5adb2db479 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -169,7 +169,11 @@ bool LinearScan::is_precolored_cpu_interval(const Interval* i) { } bool LinearScan::is_virtual_cpu_interval(const Interval* i) { +#if defined(__SOFTFP__) || defined(E500V2) + return i->reg_num() >= LIR_OprDesc::vreg_base; +#else return i->reg_num() >= LIR_OprDesc::vreg_base && (i->type() != T_FLOAT && i->type() != T_DOUBLE); +#endif // __SOFTFP__ or E500V2 } bool LinearScan::is_precolored_fpu_interval(const Interval* i) { @@ -177,7 +181,11 @@ bool LinearScan::is_precolored_fpu_interval(const Interval* i) { } bool LinearScan::is_virtual_fpu_interval(const Interval* i) { +#if defined(__SOFTFP__) || defined(E500V2) + return false; +#else return i->reg_num() >= LIR_OprDesc::vreg_base && (i->type() == T_FLOAT || i->type() == T_DOUBLE); +#endif // __SOFTFP__ or E500V2 } bool LinearScan::is_in_fpu_register(const Interval* i) { @@ -2010,12 +2018,18 @@ LIR_Opr LinearScan::calc_operand_for_interval(const Interval* interval) { return LIR_OprFact::single_cpu_oop(assigned_reg); } +#ifdef __SOFTFP__ + case T_FLOAT: // fall through +#endif // __SOFTFP__ case T_INT: { assert(assigned_reg >= pd_first_cpu_reg && assigned_reg <= pd_last_cpu_reg, "no cpu register"); assert(interval->assigned_regHi() == any_reg, "must not have hi register"); return LIR_OprFact::single_cpu(assigned_reg); } +#ifdef __SOFTFP__ + case T_DOUBLE: // fall through +#endif // __SOFTFP__ case T_LONG: { int assigned_regHi = interval->assigned_regHi(); assert(assigned_reg >= pd_first_cpu_reg && assigned_reg <= pd_last_cpu_reg, "no cpu register"); @@ -2033,7 +2047,7 @@ LIR_Opr LinearScan::calc_operand_for_interval(const Interval* interval) { #ifdef _LP64 return LIR_OprFact::double_cpu(assigned_reg, assigned_reg); #else -#ifdef SPARC +#if defined(SPARC) || defined(PPC) return LIR_OprFact::double_cpu(assigned_regHi, assigned_reg); #else return LIR_OprFact::double_cpu(assigned_reg, assigned_regHi); @@ -2041,6 +2055,7 @@ LIR_Opr LinearScan::calc_operand_for_interval(const Interval* interval) { #endif // LP64 } +#ifndef __SOFTFP__ case T_FLOAT: { #ifdef X86 if (UseSSE >= 1) { @@ -2069,6 +2084,11 @@ LIR_Opr LinearScan::calc_operand_for_interval(const Interval* interval) { assert(interval->assigned_regHi() >= pd_first_fpu_reg && interval->assigned_regHi() <= pd_last_fpu_reg, "no fpu register"); assert(assigned_reg % 2 == 0 && assigned_reg + 1 == interval->assigned_regHi(), "must be sequential and even"); LIR_Opr result = LIR_OprFact::double_fpu(interval->assigned_regHi() - pd_first_fpu_reg, assigned_reg - pd_first_fpu_reg); +#elif defined(ARM) + assert(assigned_reg >= pd_first_fpu_reg && assigned_reg <= pd_last_fpu_reg, "no fpu register"); + assert(interval->assigned_regHi() >= pd_first_fpu_reg && interval->assigned_regHi() <= pd_last_fpu_reg, "no fpu register"); + assert(assigned_reg % 2 == 0 && assigned_reg + 1 == interval->assigned_regHi(), "must be sequential and even"); + LIR_Opr result = LIR_OprFact::double_fpu(assigned_reg - pd_first_fpu_reg, interval->assigned_regHi() - pd_first_fpu_reg); #else assert(assigned_reg >= pd_first_fpu_reg && assigned_reg <= pd_last_fpu_reg, "no fpu register"); assert(interval->assigned_regHi() == any_reg, "must not have hi register (double fpu values are stored in one register on Intel)"); @@ -2076,6 +2096,7 @@ LIR_Opr LinearScan::calc_operand_for_interval(const Interval* interval) { #endif return result; } +#endif // __SOFTFP__ default: { ShouldNotReachHere(); @@ -2638,6 +2659,12 @@ int LinearScan::append_scope_value_for_operand(LIR_Opr opr, GrowableArrayfpu_regnrLo() == opr->fpu_regnrHi() + 1, "assumed in calculation (only fpu_regnrHi is used)"); #endif +#ifdef ARM + assert(opr->fpu_regnrHi() == opr->fpu_regnrLo() + 1, "assumed in calculation (only fpu_regnrLo is used)"); +#endif +#ifdef PPC + assert(opr->fpu_regnrLo() == opr->fpu_regnrHi(), "assumed in calculation (only fpu_regnrHi is used)"); +#endif VMReg rname_first = frame_map()->fpu_regname(opr->fpu_regnrHi()); #ifdef _LP64 @@ -6135,6 +6162,17 @@ void ControlFlowOptimizer::delete_unnecessary_jumps(BlockList* code) { assert(prev_op->as_OpBranch() != NULL, "branch must be of type LIR_OpBranch"); LIR_OpBranch* prev_branch = (LIR_OpBranch*)prev_op; + LIR_Op2* prev_cmp = NULL; + + for(int j = instructions->length() - 3; j >= 0 && prev_cmp == NULL; j--) { + prev_op = instructions->at(j); + if(prev_op->code() == lir_cmp) { + assert(prev_op->as_Op2() != NULL, "branch must be of type LIR_Op2"); + prev_cmp = (LIR_Op2*)prev_op; + assert(prev_branch->cond() == prev_cmp->condition(), "should be the same"); + } + } + assert(prev_cmp != NULL, "should have found comp instruction for branch"); if (prev_branch->block() == code->at(i + 1) && prev_branch->info() == NULL) { TRACE_LINEAR_SCAN(3, tty->print_cr("Negating conditional branch and deleting unconditional branch at end of block B%d", block->block_id())); @@ -6142,6 +6180,7 @@ void ControlFlowOptimizer::delete_unnecessary_jumps(BlockList* code) { // eliminate a conditional branch to the immediate successor prev_branch->change_block(last_branch->block()); prev_branch->negate_cond(); + prev_cmp->set_condition(prev_branch->cond()); instructions->truncate(instructions->length() - 1); } } diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 924a4831410..96d4e713568 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -144,7 +144,7 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) { #ifndef TIERED case counter_overflow_id: // Not generated outside the tiered world #endif -#ifdef SPARC +#if defined(SPARC) || defined(PPC) case handle_exception_nofpu_id: // Unused on sparc #endif break; @@ -240,7 +240,8 @@ const char* Runtime1::name_for_address(address entry) { #undef FUNCTION_CASE - return ""; + // Soft float adds more runtime names. + return pd_name_for_address(entry); } @@ -896,7 +897,10 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i } else { // patch the instruction NativeMovConstReg* n_copy = nativeMovConstReg_at(copy_buff); - assert(n_copy->data() == 0, "illegal init value"); + + assert(n_copy->data() == 0 || + n_copy->data() == (int)Universe::non_oop_word(), + "illegal init value"); assert(load_klass() != NULL, "klass not set"); n_copy->set_data((intx) (load_klass())); @@ -904,7 +908,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i Disassembler::decode(copy_buff, copy_buff + *byte_count, tty); } -#ifdef SPARC +#if defined(SPARC) || defined(PPC) // Update the oop location in the nmethod with the proper // oop. When the code was generated, a NULL was stuffed // in the oop table and that table needs to be update to @@ -934,6 +938,14 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i if (do_patch) { // replace instructions // first replace the tail, then the call +#ifdef ARM + if(stub_id == Runtime1::load_klass_patching_id && !VM_Version::supports_movw()) { + copy_buff -= *byte_count; + NativeMovConstReg* n_copy2 = nativeMovConstReg_at(copy_buff); + n_copy2->set_data((intx) (load_klass()), instr_pc); + } +#endif + for (int i = NativeCall::instruction_size; i < *byte_count; i++) { address ptr = copy_buff + i; int a_byte = (*ptr) & 0xFF; @@ -960,6 +972,12 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i RelocIterator iter2(nm, instr_pc2, instr_pc2 + 1); relocInfo::change_reloc_info_for_address(&iter2, (address) instr_pc2, relocInfo::none, relocInfo::oop_type); +#endif +#ifdef PPC + { address instr_pc2 = instr_pc + NativeMovConstReg::lo_offset; + RelocIterator iter2(nm, instr_pc2, instr_pc2 + 1); + relocInfo::change_reloc_info_for_address(&iter2, (address) instr_pc2, relocInfo::none, relocInfo::oop_type); + } #endif } diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.hpp b/hotspot/src/share/vm/c1/c1_Runtime1.hpp index c2c589cc791..1f31ebfbf16 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.hpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.hpp @@ -159,6 +159,9 @@ class Runtime1: public AllStatic { static const char* name_for (StubID id); static const char* name_for_address(address entry); + // platform might add runtime names. + static const char* pd_name_for_address(address entry); + // method tracing static void trace_block_entry(jint block_id); diff --git a/hotspot/src/share/vm/ci/ciField.cpp b/hotspot/src/share/vm/ci/ciField.cpp index 2729d32d2f5..9851d9e2576 100644 --- a/hotspot/src/share/vm/ci/ciField.cpp +++ b/hotspot/src/share/vm/ci/ciField.cpp @@ -339,7 +339,7 @@ void ciField::print() { if (_type != NULL) _type->print_name(); else tty->print("(reference)"); tty->print(" is_constant=%s", bool_to_str(_is_constant)); - if (_is_constant) { + if (_is_constant && is_static()) { tty->print(" constant_value="); _constant_value.print(); } diff --git a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp index c92cb3345ab..cd75fd52409 100644 --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp @@ -403,8 +403,9 @@ GrowableArray* ciInstanceKlass::non_static_fields() { instanceKlass* ik = get_instanceKlass(); int max_n_fields = ik->fields()->length()/instanceKlass::next_offset; + Arena* arena = curEnv->arena(); _non_static_fields = - new (curEnv->arena()) GrowableArray(max_n_fields); + new (arena) GrowableArray(arena, max_n_fields, 0, NULL); NonStaticFieldFiller filler(curEnv, _non_static_fields); ik->do_nonstatic_fields(&filler); } diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index f8c784f2ffe..463c3b89dae 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -55,10 +55,10 @@ ciMethod::ciMethod(methodHandle h_m) : ciObject(h_m) { _exception_handlers = NULL; _liveness = NULL; _method_blocks = NULL; -#ifdef COMPILER2 +#if defined(COMPILER2) || defined(SHARK) _flow = NULL; _bcea = NULL; -#endif // COMPILER2 +#endif // COMPILER2 || SHARK ciEnv *env = CURRENT_ENV; if (env->jvmti_can_hotswap_or_post_breakpoint() && _is_compilable) { @@ -123,10 +123,10 @@ ciMethod::ciMethod(ciInstanceKlass* holder, _can_be_statically_bound = false; _method_blocks = NULL; _method_data = NULL; -#ifdef COMPILER2 +#if defined(COMPILER2) || defined(SHARK) _flow = NULL; _bcea = NULL; -#endif // COMPILER2 +#endif // COMPILER2 || SHARK } @@ -229,6 +229,20 @@ int ciMethod::vtable_index() { } +#ifdef SHARK +// ------------------------------------------------------------------ +// ciMethod::itable_index +// +// Get the position of this method's entry in the itable, if any. +int ciMethod::itable_index() { + check_is_loaded(); + assert(holder()->is_linked(), "must be linked"); + VM_ENTRY_MARK; + return klassItable::compute_itable_index(get_methodOop()); +} +#endif // SHARK + + // ------------------------------------------------------------------ // ciMethod::native_entry // @@ -294,34 +308,34 @@ bool ciMethod::has_balanced_monitors() { // ------------------------------------------------------------------ // ciMethod::get_flow_analysis ciTypeFlow* ciMethod::get_flow_analysis() { -#ifdef COMPILER2 +#if defined(COMPILER2) || defined(SHARK) if (_flow == NULL) { ciEnv* env = CURRENT_ENV; _flow = new (env->arena()) ciTypeFlow(env, this); _flow->do_flow(); } return _flow; -#else // COMPILER2 +#else // COMPILER2 || SHARK ShouldNotReachHere(); return NULL; -#endif // COMPILER2 +#endif // COMPILER2 || SHARK } // ------------------------------------------------------------------ // ciMethod::get_osr_flow_analysis ciTypeFlow* ciMethod::get_osr_flow_analysis(int osr_bci) { -#ifdef COMPILER2 +#if defined(COMPILER2) || defined(SHARK) // OSR entry points are always place after a call bytecode of some sort assert(osr_bci >= 0, "must supply valid OSR entry point"); ciEnv* env = CURRENT_ENV; ciTypeFlow* flow = new (env->arena()) ciTypeFlow(env, this, osr_bci); flow->do_flow(); return flow; -#else // COMPILER2 +#else // COMPILER2 || SHARK ShouldNotReachHere(); return NULL; -#endif // COMPILER2 +#endif // COMPILER2 || SHARK } // ------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 7d94b46b7e9..3a7a4a3e7f9 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -70,7 +70,7 @@ class ciMethod : public ciObject { // Optional liveness analyzer. MethodLiveness* _liveness; -#ifdef COMPILER2 +#if defined(COMPILER2) || defined(SHARK) ciTypeFlow* _flow; BCEscapeAnalyzer* _bcea; #endif @@ -141,6 +141,9 @@ class ciMethod : public ciObject { // Runtime information. int vtable_index(); +#ifdef SHARK + int itable_index(); +#endif // SHARK address native_entry(); address interpreter_entry(); diff --git a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp index 31701d998d4..36bfa813a18 100644 --- a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp +++ b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp @@ -252,7 +252,7 @@ ciMethodBlocks::ciMethodBlocks(Arena *arena, ciMethod *meth): _method(meth), _arena(arena), _num_blocks(0), _code_size(meth->code_size()) { int block_estimate = _code_size / 8; - _blocks = new(_arena) GrowableArray(block_estimate); + _blocks = new(_arena) GrowableArray(_arena, block_estimate, 0, NULL); int b2bsize = _code_size * sizeof(ciBlock **); _bci_to_block = (ciBlock **) arena->Amalloc(b2bsize); Copy::zero_to_words((HeapWord*) _bci_to_block, b2bsize / sizeof(HeapWord)); diff --git a/hotspot/src/share/vm/ci/ciTypeFlow.cpp b/hotspot/src/share/vm/ci/ciTypeFlow.cpp index d702d38bc79..3071856b948 100644 --- a/hotspot/src/share/vm/ci/ciTypeFlow.cpp +++ b/hotspot/src/share/vm/ci/ciTypeFlow.cpp @@ -2591,7 +2591,7 @@ void ciTypeFlow::df_flow_types(Block* start, StateVector* temp_vector, JsrSet* temp_set) { int dft_len = 100; - GrowableArray stk(arena(), dft_len, 0, NULL); + GrowableArray stk(dft_len); ciBlock* dummy = _methodBlocks->make_dummy_block(); JsrSet* root_set = new JsrSet(NULL, 0); diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index f9c1d637c83..36085a754f8 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -62,6 +62,7 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len ClassFileStream cfs1 = *cfs0; ClassFileStream* cfs = &cfs1; #ifdef ASSERT + assert(cfs->allocated_on_stack(),"should be local"); u1* old_current = cfs0->current(); #endif diff --git a/hotspot/src/share/vm/classfile/verificationType.cpp b/hotspot/src/share/vm/classfile/verificationType.cpp index ebb5ac85f16..7b507efa901 100644 --- a/hotspot/src/share/vm/classfile/verificationType.cpp +++ b/hotspot/src/share/vm/classfile/verificationType.cpp @@ -70,7 +70,9 @@ bool VerificationType::is_reference_assignable_from( } else if (is_array() && from.is_array()) { VerificationType comp_this = get_component(CHECK_false); VerificationType comp_from = from.get_component(CHECK_false); - return comp_this.is_assignable_from(comp_from, context, CHECK_false); + if (!comp_this.is_bogus() && !comp_from.is_bogus()) { + return comp_this.is_assignable_from(comp_from, context, CHECK_false); + } } return false; } @@ -98,7 +100,7 @@ VerificationType VerificationType::get_component(TRAPS) const { CHECK_(VerificationType::bogus_type())); return VerificationType::reference_type(component); default: - ShouldNotReachHere(); + // Met an invalid type signature, e.g. [X return VerificationType::bogus_type(); } } diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp index 10072bd2e59..6f2fd206381 100644 --- a/hotspot/src/share/vm/classfile/verifier.cpp +++ b/hotspot/src/share/vm/classfile/verifier.cpp @@ -1847,12 +1847,8 @@ void ClassVerifier::verify_invoke_init( if (type == VerificationType::uninitialized_this_type()) { // The method must be an method of either this class, or one of its // superclasses - klassOop oop = current_class()(); - Klass* klass = oop->klass_part(); - while (klass != NULL && ref_class_type.name() != klass->name()) { - klass = klass->super()->klass_part(); - } - if (klass == NULL) { + if (ref_class_type.name() != current_class()->name() && + !name_in_supers(ref_class_type.name(), current_class())) { verify_error(bci, "Bad method call"); return; } diff --git a/hotspot/src/share/vm/code/codeBlob.cpp b/hotspot/src/share/vm/code/codeBlob.cpp index b4c21c91f82..d5e4525fc83 100644 --- a/hotspot/src/share/vm/code/codeBlob.cpp +++ b/hotspot/src/share/vm/code/codeBlob.cpp @@ -564,72 +564,53 @@ void CodeBlob::verify() { ShouldNotReachHere(); } -#ifndef PRODUCT - -void CodeBlob::print() const { - tty->print_cr("[CodeBlob (" INTPTR_FORMAT ")]", this); - tty->print_cr("Framesize: %d", _frame_size); +void CodeBlob::print_on(outputStream* st) const { + st->print_cr("[CodeBlob (" INTPTR_FORMAT ")]", this); + st->print_cr("Framesize: %d", _frame_size); } - void CodeBlob::print_value_on(outputStream* st) const { st->print_cr("[CodeBlob]"); } -#endif - void BufferBlob::verify() { // unimplemented } -#ifndef PRODUCT - -void BufferBlob::print() const { - CodeBlob::print(); - print_value_on(tty); +void BufferBlob::print_on(outputStream* st) const { + CodeBlob::print_on(st); + print_value_on(st); } - void BufferBlob::print_value_on(outputStream* st) const { st->print_cr("BufferBlob (" INTPTR_FORMAT ") used for %s", this, name()); } - -#endif - void RuntimeStub::verify() { // unimplemented } -#ifndef PRODUCT - -void RuntimeStub::print() const { - CodeBlob::print(); - tty->print("Runtime Stub (" INTPTR_FORMAT "): ", this); - tty->print_cr(name()); - Disassembler::decode((CodeBlob*)this); +void RuntimeStub::print_on(outputStream* st) const { + CodeBlob::print_on(st); + st->print("Runtime Stub (" INTPTR_FORMAT "): ", this); + st->print_cr(name()); + Disassembler::decode((CodeBlob*)this, st); } - void RuntimeStub::print_value_on(outputStream* st) const { st->print("RuntimeStub (" INTPTR_FORMAT "): ", this); st->print(name()); } -#endif - void SingletonBlob::verify() { // unimplemented } -#ifndef PRODUCT - -void SingletonBlob::print() const { - CodeBlob::print(); - tty->print_cr(name()); - Disassembler::decode((CodeBlob*)this); +void SingletonBlob::print_on(outputStream* st) const { + CodeBlob::print_on(st); + st->print_cr(name()); + Disassembler::decode((CodeBlob*)this, st); } - void SingletonBlob::print_value_on(outputStream* st) const { st->print_cr(name()); } @@ -637,5 +618,3 @@ void SingletonBlob::print_value_on(outputStream* st) const { void DeoptimizationBlob::print_value_on(outputStream* st) const { st->print_cr("Deoptimization (frame not available)"); } - -#endif // PRODUCT diff --git a/hotspot/src/share/vm/code/codeBlob.hpp b/hotspot/src/share/vm/code/codeBlob.hpp index 790f15be64b..28cd68aa6ae 100644 --- a/hotspot/src/share/vm/code/codeBlob.hpp +++ b/hotspot/src/share/vm/code/codeBlob.hpp @@ -163,8 +163,9 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC { // Debugging virtual void verify(); - virtual void print() const PRODUCT_RETURN; - virtual void print_value_on(outputStream* st) const PRODUCT_RETURN; + void print() const { print_on(tty); } + virtual void print_on(outputStream* st) const; + virtual void print_value_on(outputStream* st) const; // Print the comment associated with offset on stream, if there is one virtual void print_block_comment(outputStream* stream, address block_begin) { @@ -209,8 +210,8 @@ class BufferBlob: public CodeBlob { bool is_alive() const { return true; } void verify(); - void print() const PRODUCT_RETURN; - void print_value_on(outputStream* st) const PRODUCT_RETURN; + void print_on(outputStream* st) const; + void print_value_on(outputStream* st) const; }; @@ -292,8 +293,8 @@ class RuntimeStub: public CodeBlob { bool is_alive() const { return true; } void verify(); - void print() const PRODUCT_RETURN; - void print_value_on(outputStream* st) const PRODUCT_RETURN; + void print_on(outputStream* st) const; + void print_value_on(outputStream* st) const; }; @@ -317,8 +318,8 @@ class SingletonBlob: public CodeBlob { bool is_alive() const { return true; } void verify(); // does nothing - void print() const PRODUCT_RETURN; - void print_value_on(outputStream* st) const PRODUCT_RETURN; + void print_on(outputStream* st) const; + void print_value_on(outputStream* st) const; }; @@ -373,7 +374,7 @@ class DeoptimizationBlob: public SingletonBlob { void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* Nothing to do */ } // Printing - void print_value_on(outputStream* st) const PRODUCT_RETURN; + void print_value_on(outputStream* st) const; address unpack() const { return instructions_begin() + _unpack_offset; } address unpack_with_exception() const { return instructions_begin() + _unpack_with_exception; } diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 3f95285af12..af0f1833368 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -65,6 +65,11 @@ bool nmethod::is_compiled_by_c2() const { if (is_native_method()) return false; return compiler()->is_c2(); } +bool nmethod::is_compiled_by_shark() const { + if (is_native_method()) return false; + assert(compiler() != NULL, "must be"); + return compiler()->is_shark(); +} @@ -1353,6 +1358,10 @@ void nmethod::flush() { CodeCache::remove_saved_code(this); } +#ifdef SHARK + ((SharkCompiler *) compiler())->free_compiled_method(instructions_begin()); +#endif // SHARK + ((CodeBlob*)(this))->flush(); CodeCache::free(this); @@ -1769,6 +1778,7 @@ bool nmethod::detect_scavenge_root_oops() { // Method that knows how to preserve outgoing arguments at call. This method must be // called with a frame corresponding to a Java invoke void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { +#ifndef SHARK if (!method()->is_native()) { SimpleScopeDesc ssd(this, fr.pc()); Bytecode_invoke* call = Bytecode_invoke_at(ssd.method(), ssd.bci()); @@ -1776,6 +1786,7 @@ void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map symbolOop signature = call->signature(); fr.oops_compiled_arguments_do(signature, has_receiver, reg_map, f); } +#endif // !SHARK } @@ -2279,6 +2290,8 @@ void nmethod::print() const { tty->print("(c1) "); } else if (is_compiled_by_c2()) { tty->print("(c2) "); + } else if (is_compiled_by_shark()) { + tty->print("(shark) "); } else { tty->print("(nm) "); } @@ -2472,8 +2485,12 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) { if (block_begin == exception_begin()) stream->print_cr("[Exception Handler]"); if (block_begin == stub_begin()) stream->print_cr("[Stub Code]"); if (block_begin == deopt_handler_begin()) stream->print_cr("[Deopt Handler Code]"); - if (block_begin == deopt_mh_handler_begin()) stream->print_cr("[Deopt MH Handler Code]"); + + if (has_method_handle_invokes()) + if (block_begin == deopt_mh_handler_begin()) stream->print_cr("[Deopt MH Handler Code]"); + if (block_begin == consts_begin()) stream->print_cr("[Constants]"); + if (block_begin == entry_point()) { methodHandle m = method(); if (m.not_null()) { diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 67a87a64ad8..b57cb5e3dc7 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -329,6 +329,7 @@ class nmethod : public CodeBlob { bool is_compiled_by_c1() const; bool is_compiled_by_c2() const; + bool is_compiled_by_shark() const; // boundaries for different parts address code_begin () const { return _entry_point; } @@ -606,6 +607,8 @@ public: void print_nul_chk_table() PRODUCT_RETURN; void print_nmethod(bool print_code); + // need to re-define this from CodeBlob else the overload hides it + virtual void print_on(outputStream* st) const { CodeBlob::print_on(st); } void print_on(outputStream* st, const char* title) const; // Logging diff --git a/hotspot/src/share/vm/code/vtableStubs.cpp b/hotspot/src/share/vm/code/vtableStubs.cpp index 3a4c5e53635..028cfe83850 100644 --- a/hotspot/src/share/vm/code/vtableStubs.cpp +++ b/hotspot/src/share/vm/code/vtableStubs.cpp @@ -67,8 +67,8 @@ void* VtableStub::operator new(size_t size, int code_size) { } -void VtableStub::print() { - tty->print("vtable stub (index = %d, receiver_location = %d, code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "[)", +void VtableStub::print_on(outputStream* st) const { + st->print("vtable stub (index = %d, receiver_location = %d, code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "[)", index(), receiver_location(), code_begin(), code_end()); } diff --git a/hotspot/src/share/vm/code/vtableStubs.hpp b/hotspot/src/share/vm/code/vtableStubs.hpp index 526aa648ecf..e74582f98bf 100644 --- a/hotspot/src/share/vm/code/vtableStubs.hpp +++ b/hotspot/src/share/vm/code/vtableStubs.hpp @@ -86,7 +86,9 @@ class VtableStub { bool is_abstract_method_error(address epc) { return epc == code_begin()+_ame_offset; } bool is_null_pointer_exception(address epc) { return epc == code_begin()+_npe_offset; } - void print(); + void print_on(outputStream* st) const; + void print() const { print_on(tty); } + }; diff --git a/hotspot/src/share/vm/compiler/abstractCompiler.hpp b/hotspot/src/share/vm/compiler/abstractCompiler.hpp index fc54c9836db..720ded6ebe9 100644 --- a/hotspot/src/share/vm/compiler/abstractCompiler.hpp +++ b/hotspot/src/share/vm/compiler/abstractCompiler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,18 +45,26 @@ class AbstractCompiler : public CHeapObj { // Missing feature tests virtual bool supports_native() { return true; } virtual bool supports_osr () { return true; } -#if defined(TIERED) || ( !defined(COMPILER1) && !defined(COMPILER2)) +#if defined(TIERED) || ( !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK)) virtual bool is_c1 () { return false; } virtual bool is_c2 () { return false; } + virtual bool is_shark() { return false; } #else #ifdef COMPILER1 bool is_c1 () { return true; } bool is_c2 () { return false; } + bool is_shark() { return false; } #endif // COMPILER1 #ifdef COMPILER2 bool is_c1 () { return false; } bool is_c2 () { return true; } + bool is_shark() { return false; } #endif // COMPILER2 +#ifdef SHARK + bool is_c1 () { return false; } + bool is_c2 () { return false; } + bool is_shark() { return true; } +#endif // SHARK #endif // TIERED // Customization diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 9ae477e3e15..7288cac07ba 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -568,6 +568,14 @@ void CompileBroker::compilation_init() { #endif #endif // COMPILER2 +#ifdef SHARK +#if defined(COMPILER1) || defined(COMPILER2) +#error "Can't use COMPILER1 or COMPILER2 with shark" +#endif + _compilers[0] = new SharkCompiler(); + _compilers[1] = _compilers[0]; +#endif + // Initialize the CompileTask free list _task_free_list = NULL; diff --git a/hotspot/src/share/vm/compiler/disassembler.cpp b/hotspot/src/share/vm/compiler/disassembler.cpp index 2d73e83f628..8176a816463 100644 --- a/hotspot/src/share/vm/compiler/disassembler.cpp +++ b/hotspot/src/share/vm/compiler/disassembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -371,7 +371,7 @@ static int printf_to_env(void* env_pv, const char* format, ...) { address decode_env::decode_instructions(address start, address end) { _start = start; _end = end; - assert((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment() == 0), "misaligned insn addr"); + assert(((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment()) == 0), "misaligned insn addr"); const int show_bytes = false; // for disassembler debugging @@ -423,8 +423,14 @@ void Disassembler::decode(nmethod* nm, outputStream* st) { env.output()->print_cr("Decoding compiled method " INTPTR_FORMAT ":", nm); env.output()->print_cr("Code:"); +#ifdef SHARK + SharkEntry* entry = (SharkEntry *) nm->instructions_begin(); + unsigned char* p = entry->code_start(); + unsigned char* end = entry->code_limit(); +#else unsigned char* p = nm->instructions_begin(); unsigned char* end = nm->instructions_end(); +#endif // SHARK // If there has been profiling, print the buckets. if (FlatProfiler::bucket_start_for(p) != NULL) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp index 2b46502b67d..1cbb86c0371 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp @@ -158,13 +158,18 @@ CollectionSetChooser::CollectionSetChooser() : // The line below is the worst bit of C++ hackery I've ever written // (Detlefs, 11/23). You should think of it as equivalent to // "_regions(100, true)": initialize the growable array and inform it - // that it should allocate its elem array(s) on the C heap. The first - // argument, however, is actually a comma expression (new-expr, 100). - // The purpose of the new_expr is to inform the growable array that it - // is *already* allocated on the C heap: it uses the placement syntax to - // keep it from actually doing any allocation. - _markedRegions((ResourceObj::operator new (sizeof(GrowableArray), - (void*)&_markedRegions, + // that it should allocate its elem array(s) on the C heap. + // + // The first argument, however, is actually a comma expression + // (set_allocation_type(this, C_HEAP), 100). The purpose of the + // set_allocation_type() call is to replace the default allocation + // type for embedded objects STACK_OR_EMBEDDED with C_HEAP. It will + // allow to pass the assert in GenericGrowableArray() which checks + // that a growable array object must be on C heap if elements are. + // + // Note: containing object is allocated on C heap since it is CHeapObj. + // + _markedRegions((ResourceObj::set_allocation_type((address)&_markedRegions, ResourceObj::C_HEAP), 100), true), diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp index cbd325adc16..b71cf1918c9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSeq.cpp @@ -42,14 +42,19 @@ HeapRegionSeq::HeapRegionSeq(const size_t max_size) : // The line below is the worst bit of C++ hackery I've ever written // (Detlefs, 11/23). You should think of it as equivalent to // "_regions(100, true)": initialize the growable array and inform it - // that it should allocate its elem array(s) on the C heap. The first - // argument, however, is actually a comma expression (new-expr, 100). - // The purpose of the new_expr is to inform the growable array that it - // is *already* allocated on the C heap: it uses the placement syntax to - // keep it from actually doing any allocation. - _regions((ResourceObj::operator new (sizeof(GrowableArray), - (void*)&_regions, - ResourceObj::C_HEAP), + // that it should allocate its elem array(s) on the C heap. + // + // The first argument, however, is actually a comma expression + // (set_allocation_type(this, C_HEAP), 100). The purpose of the + // set_allocation_type() call is to replace the default allocation + // type for embedded objects STACK_OR_EMBEDDED with C_HEAP. It will + // allow to pass the assert in GenericGrowableArray() which checks + // that a growable array object must be on C heap if elements are. + // + // Note: containing object is allocated on C heap since it is CHeapObj. + // + _regions((ResourceObj::set_allocation_type((address)&_regions, + ResourceObj::C_HEAP), (int)max_size), true), _next_rr_candidate(0), diff --git a/hotspot/src/share/vm/includeDB_compiler1 b/hotspot/src/share/vm/includeDB_compiler1 index 302bcc59600..bdfea08070c 100644 --- a/hotspot/src/share/vm/includeDB_compiler1 +++ b/hotspot/src/share/vm/includeDB_compiler1 @@ -252,6 +252,7 @@ c1_LIRGenerator.cpp ciCPCache.hpp c1_LIRGenerator.cpp ciInstance.hpp c1_LIRGenerator.cpp heapRegion.hpp c1_LIRGenerator.cpp sharedRuntime.hpp +c1_LIRGenerator.cpp stubRoutines.hpp c1_LIRGenerator.hpp c1_Instruction.hpp c1_LIRGenerator.hpp c1_LIR.hpp @@ -270,6 +271,8 @@ c1_LIRGenerator_.cpp ciObjArrayKlass.hpp c1_LIRGenerator_.cpp ciTypeArrayKlass.hpp c1_LIRGenerator_.cpp sharedRuntime.hpp c1_LIRGenerator_.cpp vmreg_.inline.hpp +c1_LIRGenerator_.cpp stubRoutines.hpp + c1_LinearScan.cpp bitMap.inline.hpp c1_LinearScan.cpp c1_CFGPrinter.hpp @@ -413,6 +416,7 @@ codeBlob.cpp c1_Runtime1.hpp compileBroker.cpp c1_Compiler.hpp frame_.cpp c1_Runtime1.hpp +frame_.cpp vframeArray.hpp globals.cpp c1_globals.hpp diff --git a/hotspot/src/share/vm/includeDB_compiler2 b/hotspot/src/share/vm/includeDB_compiler2 index a7695d75c56..33bb7152cda 100644 --- a/hotspot/src/share/vm/includeDB_compiler2 +++ b/hotspot/src/share/vm/includeDB_compiler2 @@ -911,6 +911,7 @@ postaloc.cpp machnode.hpp reg_split.cpp addnode.hpp reg_split.cpp allocation.inline.hpp reg_split.cpp callnode.hpp +reg_split.cpp c2compiler.hpp reg_split.cpp cfgnode.hpp reg_split.cpp chaitin.hpp reg_split.cpp loopnode.hpp diff --git a/hotspot/src/share/vm/includeDB_core b/hotspot/src/share/vm/includeDB_core index 3e9089f24a8..fe4252dfcfd 100644 --- a/hotspot/src/share/vm/includeDB_core +++ b/hotspot/src/share/vm/includeDB_core @@ -284,6 +284,7 @@ atomic.hpp allocation.hpp atomic_.inline.hpp atomic.hpp atomic_.inline.hpp os.hpp atomic_.inline.hpp vm_version_.hpp +atomic_.inline.hpp orderAccess_.inline.hpp // attachListener is jck optional, put cpp deps in includeDB_features @@ -1734,6 +1735,7 @@ genCollectedHeap.cpp sharedHeap.hpp genCollectedHeap.cpp space.hpp genCollectedHeap.cpp symbolTable.hpp genCollectedHeap.cpp systemDictionary.hpp +genCollectedHeap.cpp vmError.hpp genCollectedHeap.cpp vmGCOperations.hpp genCollectedHeap.cpp vmSymbols.hpp genCollectedHeap.cpp vmThread.hpp @@ -3230,6 +3232,7 @@ os.cpp defaultStream.hpp os.cpp events.hpp os.cpp frame.inline.hpp os.cpp hpi.hpp +os.cpp icBuffer.hpp os.cpp interfaceSupport.hpp os.cpp interpreter.hpp os.cpp java.hpp @@ -3241,6 +3244,7 @@ os.cpp mutexLocker.hpp os.cpp oop.inline.hpp os.cpp os.hpp os.cpp os_.inline.hpp +os.cpp privilegedStack.hpp os.cpp stubRoutines.hpp os.cpp systemDictionary.hpp os.cpp threadService.hpp diff --git a/hotspot/src/share/vm/includeDB_shark b/hotspot/src/share/vm/includeDB_shark new file mode 100644 index 00000000000..17e451daecd --- /dev/null +++ b/hotspot/src/share/vm/includeDB_shark @@ -0,0 +1,371 @@ +// +// Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. +// Copyright 2008, 2009, 2010 Red Hat, Inc. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// +// + +// NOTE: DO NOT CHANGE THIS COPYRIGHT TO NEW STYLE - IT WILL BREAK makeDeps! + +ciMethod.cpp ciTypeFlow.hpp +ciMethod.cpp methodOop.hpp + +ciTypeFlow.cpp allocation.inline.hpp +ciTypeFlow.cpp bytecode.hpp +ciTypeFlow.cpp bytecodes.hpp +ciTypeFlow.cpp ciConstant.hpp +ciTypeFlow.cpp ciField.hpp +ciTypeFlow.cpp ciMethod.hpp +ciTypeFlow.cpp ciMethodData.hpp +ciTypeFlow.cpp ciObjArrayKlass.hpp +ciTypeFlow.cpp ciStreams.hpp +ciTypeFlow.cpp ciTypeArrayKlass.hpp +ciTypeFlow.cpp ciTypeFlow.hpp +ciTypeFlow.cpp compileLog.hpp +ciTypeFlow.cpp deoptimization.hpp +ciTypeFlow.cpp growableArray.hpp +ciTypeFlow.cpp shark_globals.hpp + +ciTypeFlow.hpp ciEnv.hpp +ciTypeFlow.hpp ciKlass.hpp +ciTypeFlow.hpp ciMethodBlocks.hpp + +cppInterpreter_.cpp shark_globals.hpp + +compileBroker.cpp sharkCompiler.hpp + +disassembler.cpp sharkEntry.hpp + +globals.hpp shark_globals_.hpp + +globals.cpp shark_globals.hpp + +llvmValue.hpp llvmHeaders.hpp +llvmValue.hpp sharkContext.hpp +llvmValue.hpp sharkType.hpp + +nmethod.cpp sharkCompiler.hpp + +sharedRuntime_.cpp compileBroker.hpp +sharedRuntime_.cpp sharkCompiler.hpp + +shark_globals.cpp shark_globals.hpp + +shark_globals.hpp shark_globals_.hpp +shark_globals.hpp globals.hpp + +sharkBlock.cpp debug.hpp +sharkBlock.cpp bytecodes.hpp +sharkBlock.cpp llvmHeaders.hpp +sharkBlock.cpp llvmValue.hpp +sharkBlock.cpp shark_globals.hpp +sharkBlock.cpp sharkBlock.hpp +sharkBlock.cpp sharkBuilder.hpp +sharkBlock.cpp sharkConstant.hpp +sharkBlock.cpp sharkState.hpp +sharkBlock.cpp sharkValue.hpp + +sharkBlock.hpp allocation.hpp +sharkBlock.hpp ciMethod.hpp +sharkBlock.hpp ciStreams.hpp +sharkBlock.hpp debug.hpp +sharkBlock.hpp llvmHeaders.hpp +sharkBlock.hpp sharkBuilder.hpp +sharkBlock.hpp sharkConstant.hpp +sharkBlock.hpp sharkInvariants.hpp +sharkBlock.hpp sharkState.hpp +sharkBlock.hpp sharkValue.hpp + +sharkBuilder.cpp ciMethod.hpp +sharkBuilder.cpp debug.hpp +sharkBuilder.cpp llvmHeaders.hpp +sharkBuilder.cpp llvmValue.hpp +sharkBuilder.cpp methodOop.hpp +sharkBuilder.cpp os.hpp +sharkBuilder.cpp resourceArea.hpp +sharkBuilder.cpp llvmHeaders.hpp +sharkBuilder.cpp sharkBuilder.hpp +sharkBuilder.cpp sharkContext.hpp +sharkBuilder.cpp sharkRuntime.hpp +sharkBuilder.cpp synchronizer.hpp +sharkBuilder.cpp thread.hpp + +sharkBuilder.hpp barrierSet.hpp +sharkBuilder.hpp cardTableModRefBS.hpp +sharkBuilder.hpp ciType.hpp +sharkBuilder.hpp debug.hpp +sharkBuilder.hpp llvmHeaders.hpp +sharkBuilder.hpp llvmValue.hpp +sharkBuilder.hpp sizes.hpp +sharkBuilder.hpp sharkCodeBuffer.hpp +sharkBuilder.hpp sharkType.hpp +sharkBuilder.hpp sharkValue.hpp +sharkBuilder.hpp sharkEntry.hpp + +sharkCacheDecache.cpp ciMethod.hpp +sharkCacheDecache.cpp debugInfoRec.hpp +sharkCacheDecache.cpp llvmValue.hpp +sharkCacheDecache.cpp sharkBuilder.hpp +sharkCacheDecache.cpp sharkCacheDecache.hpp +sharkCacheDecache.cpp sharkFunction.hpp +sharkCacheDecache.cpp sharkState.hpp + +sharkCacheDecache.hpp ciMethod.hpp +sharkCacheDecache.hpp debugInfoRec.hpp +sharkCacheDecache.hpp sharkBuilder.hpp +sharkCacheDecache.hpp sharkFunction.hpp +sharkCacheDecache.hpp sharkStateScanner.hpp + +sharkCodeBuffer.hpp allocation.hpp +sharkCodeBuffer.hpp codeBuffer.hpp +sharkCodeBuffer.hpp llvmHeaders.hpp + +sharkCompiler.cpp abstractCompiler.hpp +sharkCompiler.cpp ciEnv.hpp +sharkCompiler.cpp ciMethod.hpp +sharkCompiler.cpp debug.hpp +sharkCompiler.cpp debugInfoRec.hpp +sharkCompiler.cpp dependencies.hpp +sharkCompiler.cpp exceptionHandlerTable.hpp +sharkCompiler.cpp llvmHeaders.hpp +sharkCompiler.cpp oopMap.hpp +sharkCompiler.cpp oopRecorder.hpp +sharkCompiler.cpp shark_globals.hpp +sharkCompiler.cpp sharkBuilder.hpp +sharkCompiler.cpp sharkCodeBuffer.hpp +sharkCompiler.cpp sharkCompiler.hpp +sharkCompiler.cpp sharkContext.hpp +sharkCompiler.cpp sharkEntry.hpp +sharkCompiler.cpp sharkFunction.hpp +sharkCompiler.cpp sharkMemoryManager.hpp +sharkCompiler.cpp sharkNativeWrapper.hpp + +sharkCompiler.hpp abstractCompiler.hpp +sharkCompiler.hpp ciEnv.hpp +sharkCompiler.hpp ciMethod.hpp +sharkCompiler.hpp compileBroker.hpp +sharkCompiler.hpp llvmHeaders.hpp +sharkCompiler.hpp sharkMemoryManager.hpp + +sharkContext.cpp arrayOop.hpp +sharkContext.cpp globalDefinitions.hpp +sharkContext.cpp llvmHeaders.hpp +sharkContext.cpp oop.hpp +sharkContext.cpp sharkContext.hpp + +sharkContext.hpp llvmHeaders.hpp +sharkContext.hpp sharkCompiler.hpp + +sharkConstant.cpp ciInstance.hpp +sharkConstant.cpp ciStreams.hpp +sharkConstant.cpp sharkBuilder.hpp +sharkConstant.cpp sharkConstant.hpp +sharkConstant.cpp sharkValue.hpp + +sharkConstant.hpp allocation.hpp +sharkConstant.hpp ciStreams.hpp +sharkConstant.hpp sharkBuilder.hpp +sharkConstant.hpp sharkValue.hpp + +sharkEntry.hpp llvmHeaders.hpp + +sharkFunction.cpp allocation.hpp +sharkFunction.cpp ciTypeFlow.hpp +sharkFunction.cpp debug.hpp +sharkFunction.cpp llvmHeaders.hpp +sharkFunction.cpp llvmValue.hpp +sharkFunction.cpp shark_globals.hpp +sharkFunction.cpp sharkBuilder.hpp +sharkFunction.cpp sharkEntry.hpp +sharkFunction.cpp sharkFunction.hpp +sharkFunction.cpp sharkState.hpp +sharkFunction.cpp sharkTopLevelBlock.hpp + +sharkFunction.hpp allocation.hpp +sharkFunction.hpp ciEnv.hpp +sharkFunction.hpp ciStreams.hpp +sharkFunction.hpp ciTypeFlow.hpp +sharkFunction.hpp llvmHeaders.hpp +sharkFunction.hpp llvmValue.hpp +sharkFunction.hpp sharkBuilder.hpp +sharkFunction.hpp sharkContext.hpp +sharkFunction.hpp sharkInvariants.hpp +sharkFunction.hpp sharkStack.hpp + +sharkInliner.cpp allocation.hpp +sharkInliner.cpp bytecodes.hpp +sharkInliner.cpp ciField.hpp +sharkInliner.cpp ciMethod.hpp +sharkInliner.cpp ciStreams.hpp +sharkInliner.cpp shark_globals.hpp +sharkInliner.cpp sharkBlock.hpp +sharkInliner.cpp sharkConstant.hpp +sharkInliner.cpp sharkInliner.hpp +sharkInliner.cpp sharkIntrinsics.hpp +sharkInliner.cpp sharkState.hpp +sharkInliner.cpp sharkValue.hpp + +sharkInliner.hpp allocation.hpp +sharkInliner.hpp ciMethod.hpp +sharkInliner.hpp llvmHeaders.hpp +sharkInliner.hpp sharkState.hpp + +sharkIntrinsics.cpp ciMethod.hpp +sharkIntrinsics.cpp llvmHeaders.hpp +sharkIntrinsics.cpp shark_globals.hpp +sharkIntrinsics.cpp sharkIntrinsics.hpp +sharkIntrinsics.cpp sharkState.hpp +sharkIntrinsics.cpp sharkValue.hpp + +sharkIntrinsics.hpp allocation.hpp +sharkIntrinsics.hpp ciMethod.hpp +sharkIntrinsics.hpp llvmHeaders.hpp +sharkIntrinsics.hpp sharkState.hpp + +sharkInvariants.cpp sharkInvariants.hpp + +sharkInvariants.hpp allocation.hpp +sharkInvariants.hpp ciEnv.hpp +sharkInvariants.hpp ciMethod.hpp +sharkInvariants.hpp ciInstanceKlass.hpp +sharkInvariants.hpp ciTypeFlow.hpp +sharkInvariants.hpp debugInfoRec.hpp +sharkInvariants.hpp dependencies.hpp +sharkInvariants.hpp llvmHeaders.hpp +sharkInvariants.hpp sharkBuilder.hpp + +sharkMemoryManager.hpp llvmHeaders.hpp +sharkMemoryManager.hpp sharkEntry.hpp + +sharkMemoryManager.cpp llvmHeaders.hpp +sharkMemoryManager.cpp sharkEntry.hpp +sharkMemoryManager.cpp sharkMemoryManager.hpp + +sharkNativeWrapper.cpp llvmHeaders.hpp +sharkNativeWrapper.cpp sharkNativeWrapper.hpp +sharkNativeWrapper.cpp sharkType.hpp + +sharkNativeWrapper.hpp handles.hpp +sharkNativeWrapper.hpp llvmHeaders.hpp +sharkNativeWrapper.hpp sharkBuilder.hpp +sharkNativeWrapper.hpp sharkContext.hpp +sharkNativeWrapper.hpp sharkInvariants.hpp +sharkNativeWrapper.hpp sharkStack.hpp + +sharkRuntime.cpp biasedLocking.hpp +sharkRuntime.cpp deoptimization.hpp +sharkRuntime.cpp llvmHeaders.hpp +sharkRuntime.cpp klassOop.hpp +sharkRuntime.cpp sharkRuntime.hpp +sharkRuntime.cpp stack_.inline.hpp +sharkRuntime.cpp thread.hpp + +sharkRuntime.hpp allocation.hpp +sharkRuntime.hpp llvmHeaders.hpp +sharkRuntime.hpp llvmValue.hpp +sharkRuntime.hpp klassOop.hpp +sharkRuntime.hpp thread.hpp + +sharkStack.cpp llvmHeaders.hpp +sharkStack.cpp sharkFunction.hpp +sharkStack.cpp sharkNativeWrapper.hpp +sharkStack.cpp sharkStack.hpp +sharkStack.cpp sharkType.hpp + +sharkStack.hpp llvmHeaders.hpp +sharkStack.hpp sharkInvariants.hpp +sharkStack.hpp sharkType.hpp + +sharkState.cpp allocation.hpp +sharkState.cpp ciType.hpp +sharkState.cpp ciTypeFlow.hpp +sharkState.cpp sharkBuilder.hpp +sharkState.cpp sharkCacheDecache.hpp +sharkState.cpp sharkState.hpp +sharkState.cpp sharkTopLevelBlock.hpp +sharkState.cpp sharkType.hpp +sharkState.cpp sharkValue.hpp + +sharkState.hpp allocation.hpp +sharkState.hpp ciMethod.hpp +sharkState.hpp llvmHeaders.hpp +sharkState.hpp sharkBuilder.hpp +sharkState.hpp sharkInvariants.hpp +sharkState.hpp sharkValue.hpp + +sharkStateScanner.cpp sharkState.hpp +sharkStateScanner.cpp sharkStateScanner.hpp + +sharkStateScanner.hpp allocation.hpp +sharkStateScanner.hpp llvmHeaders.hpp +sharkStateScanner.hpp sharkFunction.hpp +sharkStateScanner.hpp sharkInvariants.hpp + +sharkTopLevelBlock.cpp allocation.hpp +sharkTopLevelBlock.cpp bytecodes.hpp +sharkTopLevelBlock.cpp ciField.hpp +sharkTopLevelBlock.cpp ciInstance.hpp +sharkTopLevelBlock.cpp ciObjArrayKlass.hpp +sharkTopLevelBlock.cpp ciStreams.hpp +sharkTopLevelBlock.cpp ciType.hpp +sharkTopLevelBlock.cpp ciTypeFlow.hpp +sharkTopLevelBlock.cpp debug.hpp +sharkTopLevelBlock.cpp deoptimization.hpp +sharkTopLevelBlock.cpp llvmHeaders.hpp +sharkTopLevelBlock.cpp llvmValue.hpp +sharkTopLevelBlock.cpp shark_globals.hpp +sharkTopLevelBlock.cpp sharkCacheDecache.hpp +sharkTopLevelBlock.cpp sharkTopLevelBlock.hpp +sharkTopLevelBlock.cpp sharkBuilder.hpp +sharkTopLevelBlock.cpp sharkConstant.hpp +sharkTopLevelBlock.cpp sharkInliner.hpp +sharkTopLevelBlock.cpp sharkState.hpp +sharkTopLevelBlock.cpp sharkValue.hpp + +sharkTopLevelBlock.hpp allocation.hpp +sharkTopLevelBlock.hpp bytecodes.hpp +sharkTopLevelBlock.hpp ciStreams.hpp +sharkTopLevelBlock.hpp ciType.hpp +sharkTopLevelBlock.hpp ciTypeFlow.hpp +sharkTopLevelBlock.hpp llvmHeaders.hpp +sharkTopLevelBlock.hpp sharkBlock.hpp +sharkTopLevelBlock.hpp sharkBuilder.hpp +sharkTopLevelBlock.hpp sharkFunction.hpp +sharkTopLevelBlock.hpp sharkState.hpp +sharkTopLevelBlock.hpp sharkValue.hpp + +sharkType.hpp allocation.hpp +sharkType.hpp ciType.hpp +sharkType.hpp globalDefinitions.hpp +sharkType.hpp llvmHeaders.hpp +sharkType.hpp sharkContext.hpp + +sharkValue.cpp ciType.hpp +sharkValue.cpp llvmHeaders.hpp +sharkValue.cpp llvmValue.hpp +sharkValue.cpp sharkBuilder.hpp +sharkValue.cpp sharkValue.hpp + +sharkValue.hpp allocation.hpp +sharkValue.hpp ciType.hpp +sharkValue.hpp llvmHeaders.hpp +sharkValue.hpp llvmValue.hpp +sharkValue.hpp sharkType.hpp diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index a9d0d0484f7..29b4ede2bd9 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -339,7 +339,8 @@ #define CHECK_NULL(obj_) \ if ((obj_) == NULL) { \ VM_JAVA_ERROR(vmSymbols::java_lang_NullPointerException(), ""); \ - } + } \ + VERIFY_OOP(obj_) #define VMdoubleConstZero() 0.0 #define VMdoubleConstOne() 1.0 @@ -509,7 +510,7 @@ BytecodeInterpreter::run(interpreterState istate) { /* 0xB0 */ &&opc_areturn, &&opc_return, &&opc_getstatic, &&opc_putstatic, /* 0xB4 */ &&opc_getfield, &&opc_putfield, &&opc_invokevirtual,&&opc_invokespecial, -/* 0xB8 */ &&opc_invokestatic,&&opc_invokeinterface,NULL, &&opc_new, +/* 0xB8 */ &&opc_invokestatic,&&opc_invokeinterface,&&opc_default, &&opc_new, /* 0xBC */ &&opc_newarray, &&opc_anewarray, &&opc_arraylength, &&opc_athrow, /* 0xC0 */ &&opc_checkcast, &&opc_instanceof, &&opc_monitorenter, &&opc_monitorexit, @@ -539,6 +540,7 @@ BytecodeInterpreter::run(interpreterState istate) { // this will trigger a VERIFY_OOP on entry if (istate->msg() != initialize && ! METHOD->is_static()) { oop rcvr = LOCALS_OBJECT(0); + VERIFY_OOP(rcvr); } #endif // #define HACK @@ -547,7 +549,7 @@ BytecodeInterpreter::run(interpreterState istate) { #endif // HACK /* QQQ this should be a stack method so we don't know actual direction */ - assert(istate->msg() == initialize || + guarantee(istate->msg() == initialize || topOfStack >= istate->stack_limit() && topOfStack < istate->stack_base(), "Stack top out of range"); @@ -613,6 +615,7 @@ BytecodeInterpreter::run(interpreterState istate) { rcvr = METHOD->constants()->pool_holder()->klass_part()->java_mirror(); } else { rcvr = LOCALS_OBJECT(0); + VERIFY_OOP(rcvr); } // The initial monitor is ours for the taking BasicObjectLock* mon = &istate->monitor_base()[-1]; @@ -735,6 +738,7 @@ BytecodeInterpreter::run(interpreterState istate) { case popping_frame: { // returned from a java call to pop the frame, restart the call // clear the message so we don't confuse ourselves later + ShouldNotReachHere(); // we don't return this. assert(THREAD->pop_frame_in_process(), "wrong frame pop state"); istate->set_msg(no_request); THREAD->clr_pop_frame_in_process(); @@ -801,6 +805,7 @@ BytecodeInterpreter::run(interpreterState istate) { // continue locking now that we have a monitor to use // we expect to find newly allocated monitor at the "top" of the monitor stack. oop lockee = STACK_OBJECT(-1); + VERIFY_OOP(lockee); // derefing's lockee ought to provoke implicit null check // find a free monitor BasicObjectLock* entry = (BasicObjectLock*) istate->stack_base(); @@ -911,6 +916,7 @@ run: /* load from local variable */ CASE(_aload): + VERIFY_OOP(LOCALS_OBJECT(pc[1])); SET_STACK_OBJECT(LOCALS_OBJECT(pc[1]), 0); UPDATE_PC_AND_TOS_AND_CONTINUE(2, 1); @@ -930,6 +936,7 @@ run: #undef OPC_LOAD_n #define OPC_LOAD_n(num) \ CASE(_aload_##num): \ + VERIFY_OOP(LOCALS_OBJECT(num)); \ SET_STACK_OBJECT(LOCALS_OBJECT(num), 0); \ UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1); \ \ @@ -975,6 +982,7 @@ run: opcode = pc[1]; switch(opcode) { case Bytecodes::_aload: + VERIFY_OOP(LOCALS_OBJECT(reg)); SET_STACK_OBJECT(LOCALS_OBJECT(reg), 0); UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1); @@ -1099,7 +1107,7 @@ run: CASE(_i##opcname): \ if (test && (STACK_INT(-1) == 0)) { \ VM_JAVA_ERROR(vmSymbols::java_lang_ArithmeticException(), \ - "/ by int zero"); \ + "/ by zero"); \ } \ SET_STACK_INT(VMint##opname(STACK_INT(-2), \ STACK_INT(-1)), \ @@ -1277,7 +1285,12 @@ run: jfloat f; jdouble r; f = STACK_FLOAT(-1); +#ifdef IA64 + // IA64 gcc bug + r = ( f == 0.0f ) ? (jdouble) f : (jdouble) f + ia64_double_zero; +#else r = (jdouble) f; +#endif MORE_STACK(-1); // POP SET_STACK_DOUBLE(r, 1); UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2); @@ -1471,6 +1484,7 @@ run: CASE(_return_register_finalizer): { oop rcvr = LOCALS_OBJECT(0); + VERIFY_OOP(rcvr); if (rcvr->klass()->klass_part()->has_finalizer()) { CALL_VM(InterpreterRuntime::register_finalizer(THREAD, rcvr), handle_exception); } @@ -1561,6 +1575,7 @@ run: */ CASE(_aastore): { oop rhsObject = STACK_OBJECT(-1); + VERIFY_OOP(rhsObject); ARRAY_INTRO( -3); // arrObj, index are set if (rhsObject != NULL) { @@ -1703,6 +1718,7 @@ run: obj = (oop)NULL; } else { obj = (oop) STACK_OBJECT(-1); + VERIFY_OOP(obj); } CALL_VM(InterpreterRuntime::post_field_access(THREAD, obj, @@ -1728,6 +1744,7 @@ run: int field_offset = cache->f2(); if (cache->is_volatile()) { if (tos_type == atos) { + VERIFY_OOP(obj->obj_field_acquire(field_offset)); SET_STACK_OBJECT(obj->obj_field_acquire(field_offset), -1); } else if (tos_type == itos) { SET_STACK_INT(obj->int_field_acquire(field_offset), -1); @@ -1748,6 +1765,7 @@ run: } } else { if (tos_type == atos) { + VERIFY_OOP(obj->obj_field(field_offset)); SET_STACK_OBJECT(obj->obj_field(field_offset), -1); } else if (tos_type == itos) { SET_STACK_INT(obj->int_field(field_offset), -1); @@ -1799,6 +1817,7 @@ run: } else { obj = (oop) STACK_OBJECT(-2); } + VERIFY_OOP(obj); } CALL_VM(InterpreterRuntime::post_field_modification(THREAD, @@ -1837,6 +1856,7 @@ run: if (tos_type == itos) { obj->release_int_field_put(field_offset, STACK_INT(-1)); } else if (tos_type == atos) { + VERIFY_OOP(STACK_OBJECT(-1)); obj->release_obj_field_put(field_offset, STACK_OBJECT(-1)); OrderAccess::release_store(&BYTE_MAP_BASE[(uintptr_t)obj >> CardTableModRefBS::card_shift], 0); } else if (tos_type == btos) { @@ -1857,6 +1877,7 @@ run: if (tos_type == itos) { obj->int_field_put(field_offset, STACK_INT(-1)); } else if (tos_type == atos) { + VERIFY_OOP(STACK_OBJECT(-1)); obj->obj_field_put(field_offset, STACK_OBJECT(-1)); OrderAccess::release_store(&BYTE_MAP_BASE[(uintptr_t)obj >> CardTableModRefBS::card_shift], 0); } else if (tos_type == btos) { @@ -1961,6 +1982,7 @@ run: } CASE(_checkcast): if (STACK_OBJECT(-1) != NULL) { + VERIFY_OOP(STACK_OBJECT(-1)); u2 index = Bytes::get_Java_u2(pc+1); if (ProfileInterpreter) { // needs Profile_checkcast QQQ @@ -1999,6 +2021,7 @@ run: if (STACK_OBJECT(-1) == NULL) { SET_STACK_INT(0, -1); } else { + VERIFY_OOP(STACK_OBJECT(-1)); u2 index = Bytes::get_Java_u2(pc+1); // Constant pool may have actual klass or unresolved klass. If it is // unresolved we must resolve it @@ -2044,10 +2067,12 @@ run: break; case JVM_CONSTANT_String: + VERIFY_OOP(constants->resolved_string_at(index)); SET_STACK_OBJECT(constants->resolved_string_at(index), 0); break; case JVM_CONSTANT_Class: + VERIFY_OOP(constants->resolved_klass_at(index)->klass_part()->java_mirror()); SET_STACK_OBJECT(constants->resolved_klass_at(index)->klass_part()->java_mirror(), 0); break; @@ -2059,17 +2084,6 @@ run: THREAD->set_vm_result(NULL); break; -#if 0 - CASE(_fast_igetfield): - CASE(_fastagetfield): - CASE(_fast_aload_0): - CASE(_fast_iaccess_0): - CASE(__fast_aaccess_0): - CASE(_fast_linearswitch): - CASE(_fast_binaryswitch): - fatal("unsupported fast bytecode"); -#endif - default: ShouldNotReachHere(); } UPDATE_PC_AND_TOS_AND_CONTINUE(incr, 1); @@ -2122,6 +2136,7 @@ run: // get receiver int parms = cache->parameter_size(); // Same comments as invokevirtual apply here + VERIFY_OOP(STACK_OBJECT(-parms)); instanceKlass* rcvrKlass = (instanceKlass*) STACK_OBJECT(-parms)->klass()->klass_part(); callee = (methodOop) rcvrKlass->start_of_vtable()[ cache->f2()]; @@ -2205,6 +2220,7 @@ run: // this fails with an assert // instanceKlass* rcvrKlass = instanceKlass::cast(STACK_OBJECT(-parms)->klass()); // but this works + VERIFY_OOP(STACK_OBJECT(-parms)); instanceKlass* rcvrKlass = (instanceKlass*) STACK_OBJECT(-parms)->klass()->klass_part(); /* Executing this code in java.lang.String: @@ -2651,14 +2667,14 @@ handle_return: LOCALS_SLOT(METHOD->size_of_parameters() - 1)); THREAD->set_popframe_condition_bit(JavaThread::popframe_force_deopt_reexecution_bit); } - UPDATE_PC_AND_RETURN(1); - } else { - // Normal return - // Advance the pc and return to frame manager - istate->set_msg(return_from_method); - istate->set_return_kind((Bytecodes::Code)opcode); - UPDATE_PC_AND_RETURN(1); + THREAD->clr_pop_frame_in_process(); } + + // Normal return + // Advance the pc and return to frame manager + istate->set_msg(return_from_method); + istate->set_return_kind((Bytecodes::Code)opcode); + UPDATE_PC_AND_RETURN(1); } /* handle_return: */ // This is really a fatal error return diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp index 44c8e8bb75d..086b26b7f8e 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp @@ -440,7 +440,7 @@ static jint VMintXor(jint op1, jint op2); * iushr, ishl, and ishr bytecodes, respectively. */ -static jint VMintUshr(jint op, jint num); +static juint VMintUshr(jint op, jint num); static jint VMintShl (jint op, jint num); static jint VMintShr (jint op, jint num); diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp index 887e5459a9c..041d6a1453f 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.inline.hpp @@ -27,14 +27,11 @@ #ifdef CC_INTERP #ifdef ASSERT -extern "C" { typedef void (*verify_oop_fn_t)(oop, const char *);}; -#define VERIFY_OOP(o) \ - /*{ verify_oop_fn_t verify_oop_entry = \ - *StubRoutines::verify_oop_subroutine_entry_address(); \ - if (verify_oop_entry) { \ - (*verify_oop_entry)((o), "Not an oop!"); \ - } \ - }*/ +#define VERIFY_OOP(o_) \ + if (VerifyOops) { \ + assert((oop(o_))->is_oop_or_null(), "Not an oop!"); \ + StubRoutines::_verify_oop_count++; \ + } #else #define VERIFY_OOP(o) #endif diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp index edef0fafc94..1b1a16333e8 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.cpp +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp @@ -41,20 +41,20 @@ void InterpreterCodelet::verify() { } -void InterpreterCodelet::print() { +void InterpreterCodelet::print_on(outputStream* st) const { if (PrintInterpreter) { - tty->cr(); - tty->print_cr("----------------------------------------------------------------------"); + st->cr(); + st->print_cr("----------------------------------------------------------------------"); } - if (description() != NULL) tty->print("%s ", description()); - if (bytecode() >= 0 ) tty->print("%d %s ", bytecode(), Bytecodes::name(bytecode())); - tty->print_cr("[" INTPTR_FORMAT ", " INTPTR_FORMAT "] %d bytes", + if (description() != NULL) st->print("%s ", description()); + if (bytecode() >= 0 ) st->print("%d %s ", bytecode(), Bytecodes::name(bytecode())); + st->print_cr("[" INTPTR_FORMAT ", " INTPTR_FORMAT "] %d bytes", code_begin(), code_end(), code_size()); if (PrintInterpreter) { - tty->cr(); - Disassembler::decode(code_begin(), code_end(), tty); + st->cr(); + Disassembler::decode(code_begin(), code_end(), st); } } diff --git a/hotspot/src/share/vm/interpreter/interpreter.hpp b/hotspot/src/share/vm/interpreter/interpreter.hpp index fdb9f993bbb..e8da2ce3123 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.hpp +++ b/hotspot/src/share/vm/interpreter/interpreter.hpp @@ -52,7 +52,8 @@ class InterpreterCodelet: public Stub { // Debugging void verify(); - void print(); + void print_on(outputStream* st) const; + void print() const { print_on(tty); } // Interpreter-specific initialization void initialize(const char* description, Bytecodes::Code bytecode); diff --git a/hotspot/src/share/vm/interpreter/oopMapCache.cpp b/hotspot/src/share/vm/interpreter/oopMapCache.cpp index 1ee2675d67e..4ad801c9243 100644 --- a/hotspot/src/share/vm/interpreter/oopMapCache.cpp +++ b/hotspot/src/share/vm/interpreter/oopMapCache.cpp @@ -281,9 +281,7 @@ class MaskFillerForNative: public NativeSignatureIterator { public: void pass_int() { /* ignore */ } void pass_long() { /* ignore */ } -#if defined(_LP64) || defined(ZERO) void pass_float() { /* ignore */ } -#endif void pass_double() { /* ignore */ } void pass_object() { set_one(offset()); } diff --git a/hotspot/src/share/vm/memory/allocation.cpp b/hotspot/src/share/vm/memory/allocation.cpp index e2979646c9c..6331bcefc78 100644 --- a/hotspot/src/share/vm/memory/allocation.cpp +++ b/hotspot/src/share/vm/memory/allocation.cpp @@ -43,24 +43,73 @@ void* ResourceObj::operator new(size_t size, allocation_type type) { switch (type) { case C_HEAP: res = (address)AllocateHeap(size, "C_Heap: ResourceOBJ"); + DEBUG_ONLY(set_allocation_type(res, C_HEAP);) break; case RESOURCE_AREA: + // new(size) sets allocation type RESOURCE_AREA. res = (address)operator new(size); break; default: ShouldNotReachHere(); } - // Set allocation type in the resource object for assertion checks. - DEBUG_ONLY(((ResourceObj *)res)->_allocation = type;) return res; } void ResourceObj::operator delete(void* p) { assert(((ResourceObj *)p)->allocated_on_C_heap(), "delete only allowed for C_HEAP objects"); + DEBUG_ONLY(((ResourceObj *)p)->_allocation = badHeapOopVal;) FreeHeap(p); } +#ifdef ASSERT +void ResourceObj::set_allocation_type(address res, allocation_type type) { + // Set allocation type in the resource object + uintptr_t allocation = (uintptr_t)res; + assert((allocation & allocation_mask) == 0, "address should be aligned to 4 bytes at least"); + assert(type <= allocation_mask, "incorrect allocation type"); + ((ResourceObj *)res)->_allocation = ~(allocation + type); +} + +ResourceObj::allocation_type ResourceObj::get_allocation_type() const { + assert(~(_allocation | allocation_mask) == (uintptr_t)this, "lost resource object"); + return (allocation_type)((~_allocation) & allocation_mask); +} + +ResourceObj::ResourceObj() { // default constructor + if (~(_allocation | allocation_mask) != (uintptr_t)this) { + set_allocation_type((address)this, STACK_OR_EMBEDDED); + } else if (allocated_on_stack()) { + // For some reason we got a value which looks like an allocation on stack. + // Pass if it is really allocated on stack. + assert(Thread::current()->on_local_stack((address)this),"should be on stack"); + } else { + assert(allocated_on_res_area() || allocated_on_C_heap() || allocated_on_arena(), + "allocation_type should be set by operator new()"); + } +} + +ResourceObj::ResourceObj(const ResourceObj& r) { // default copy constructor + // Used in ClassFileParser::parse_constant_pool_entries() for ClassFileStream. + set_allocation_type((address)this, STACK_OR_EMBEDDED); +} + +ResourceObj& ResourceObj::operator=(const ResourceObj& r) { // default copy assignment + // Used in InlineTree::ok_to_inline() for WarmCallInfo. + assert(allocated_on_stack(), "copy only into local"); + // Keep current _allocation value; + return *this; +} + +ResourceObj::~ResourceObj() { + // allocated_on_C_heap() also checks that encoded (in _allocation) address == this. + if (!allocated_on_C_heap()) { // ResourceObj::delete() zaps _allocation for C_heap. + _allocation = badHeapOopVal; // zap type + } +} +#endif // ASSERT + + void trace_heap_malloc(size_t size, const char* name, void* p) { // A lock is not needed here - tty uses a lock internally tty->print_cr("Heap malloc " INTPTR_FORMAT " %7d %s", p, size, name == NULL ? "" : name); @@ -166,32 +215,40 @@ class ChunkPool { _medium_pool = new ChunkPool(Chunk::medium_size + Chunk::aligned_overhead_size()); _small_pool = new ChunkPool(Chunk::init_size + Chunk::aligned_overhead_size()); } + + static void clean() { + enum { BlocksToKeep = 5 }; + _small_pool->free_all_but(BlocksToKeep); + _medium_pool->free_all_but(BlocksToKeep); + _large_pool->free_all_but(BlocksToKeep); + } }; ChunkPool* ChunkPool::_large_pool = NULL; ChunkPool* ChunkPool::_medium_pool = NULL; ChunkPool* ChunkPool::_small_pool = NULL; - void chunkpool_init() { ChunkPool::initialize(); } +void +Chunk::clean_chunk_pool() { + ChunkPool::clean(); +} + //-------------------------------------------------------------------------------------- // ChunkPoolCleaner implementation +// class ChunkPoolCleaner : public PeriodicTask { - enum { CleaningInterval = 5000, // cleaning interval in ms - BlocksToKeep = 5 // # of extra blocks to keep - }; + enum { CleaningInterval = 5000 }; // cleaning interval in ms public: ChunkPoolCleaner() : PeriodicTask(CleaningInterval) {} void task() { - ChunkPool::small_pool()->free_all_but(BlocksToKeep); - ChunkPool::medium_pool()->free_all_but(BlocksToKeep); - ChunkPool::large_pool()->free_all_but(BlocksToKeep); + ChunkPool::clean(); } }; diff --git a/hotspot/src/share/vm/memory/allocation.hpp b/hotspot/src/share/vm/memory/allocation.hpp index 0200670c757..a9f363b499b 100644 --- a/hotspot/src/share/vm/memory/allocation.hpp +++ b/hotspot/src/share/vm/memory/allocation.hpp @@ -174,8 +174,9 @@ class Chunk: public CHeapObj { // Start the chunk_pool cleaner task static void start_chunk_pool_cleaner_task(); -}; + static void clean_chunk_pool(); +}; //------------------------------Arena------------------------------------------ // Fast allocation of memory @@ -316,32 +317,36 @@ extern void resource_free_bytes( char *old, size_t size ); // use delete to deallocate. class ResourceObj ALLOCATION_SUPER_CLASS_SPEC { public: - enum allocation_type { UNKNOWN = 0, C_HEAP, RESOURCE_AREA, ARENA }; + enum allocation_type { STACK_OR_EMBEDDED = 0, RESOURCE_AREA, C_HEAP, ARENA, allocation_mask = 0x3 }; + static void set_allocation_type(address res, allocation_type type) NOT_DEBUG_RETURN; #ifdef ASSERT private: - allocation_type _allocation; + // When this object is allocated on stack the new() operator is not + // called but garbage on stack may look like a valid allocation_type. + // Store negated 'this' pointer when new() is called to distinguish cases. + uintptr_t _allocation; public: - bool allocated_on_C_heap() { return _allocation == C_HEAP; } + allocation_type get_allocation_type() const; + bool allocated_on_stack() const { return get_allocation_type() == STACK_OR_EMBEDDED; } + bool allocated_on_res_area() const { return get_allocation_type() == RESOURCE_AREA; } + bool allocated_on_C_heap() const { return get_allocation_type() == C_HEAP; } + bool allocated_on_arena() const { return get_allocation_type() == ARENA; } + ResourceObj(); // default construtor + ResourceObj(const ResourceObj& r); // default copy construtor + ResourceObj& operator=(const ResourceObj& r); // default copy assignment + ~ResourceObj(); #endif // ASSERT public: void* operator new(size_t size, allocation_type type); void* operator new(size_t size, Arena *arena) { address res = (address)arena->Amalloc(size); - // Set allocation type in the resource object - DEBUG_ONLY(((ResourceObj *)res)->_allocation = ARENA;) + DEBUG_ONLY(set_allocation_type(res, ARENA);) return res; } void* operator new(size_t size) { address res = (address)resource_allocate_bytes(size); - // Set allocation type in the resource object - DEBUG_ONLY(((ResourceObj *)res)->_allocation = RESOURCE_AREA;) - return res; - } - void* operator new(size_t size, void* where, allocation_type type) { - void* res = where; - // Set allocation type in the resource object - DEBUG_ONLY(((ResourceObj *)res)->_allocation = type;) + DEBUG_ONLY(set_allocation_type(res, RESOURCE_AREA);) return res; } void operator delete(void* p); diff --git a/hotspot/src/share/vm/memory/cardTableModRefBS.hpp b/hotspot/src/share/vm/memory/cardTableModRefBS.hpp index a972e159ff4..6bacb22f320 100644 --- a/hotspot/src/share/vm/memory/cardTableModRefBS.hpp +++ b/hotspot/src/share/vm/memory/cardTableModRefBS.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ class CardTableModRefBS: public ModRefBarrierSet { friend class VMStructs; friend class CardTableRS; friend class CheckForUnmarkedOops; // Needs access to raw card bytes. + friend class SharkBuilder; #ifndef PRODUCT // For debugging. friend class GuaranteeNotModClosure; diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 79005deba1d..0f7d2dc738d 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -941,7 +941,9 @@ bool GenCollectedHeap::is_in(const void* p) const { VerifyBeforeExit || PrintAssembly || tty->count() != 0 || // already printing - VerifyAfterGC, "too expensive"); + VerifyAfterGC || + VMError::fatal_error_in_progress(), "too expensive"); + #endif // This might be sped up with a cache of the last generation that // answered yes. diff --git a/hotspot/src/share/vm/memory/generation.hpp b/hotspot/src/share/vm/memory/generation.hpp index 021dd45e0ec..af0bdf2b3f5 100644 --- a/hotspot/src/share/vm/memory/generation.hpp +++ b/hotspot/src/share/vm/memory/generation.hpp @@ -131,7 +131,9 @@ class Generation: public CHeapObj { enum SomePublicConstants { // Generations are GenGrain-aligned and have size that are multiples of // GenGrain. - LogOfGenGrain = 16, + // Note: on ARM we add 1 bit for card_table_base to be properly aligned + // (we expect its low byte to be zero - see implementation of post_barrier) + LogOfGenGrain = 16 ARM_ONLY(+1), GenGrain = 1 << LogOfGenGrain }; diff --git a/hotspot/src/share/vm/oops/arrayKlass.cpp b/hotspot/src/share/vm/oops/arrayKlass.cpp index d5a5abdda46..8ed78221916 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlass.cpp @@ -179,8 +179,6 @@ jint arrayKlass::jvmti_class_status() const { return JVMTI_CLASS_STATUS_ARRAY; } -#ifndef PRODUCT - // Printing void arrayKlass::oop_print_on(oop obj, outputStream* st) { @@ -189,8 +187,6 @@ void arrayKlass::oop_print_on(oop obj, outputStream* st) { st->print_cr(" - length: %d", arrayOop(obj)->length()); } -#endif - // Verification void arrayKlass::oop_verify_on(oop obj, outputStream* st) { diff --git a/hotspot/src/share/vm/oops/arrayKlass.hpp b/hotspot/src/share/vm/oops/arrayKlass.hpp index a78e2f79aa0..199131ee465 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.hpp +++ b/hotspot/src/share/vm/oops/arrayKlass.hpp @@ -115,20 +115,15 @@ class arrayKlass: public Klass { // Return a handle. static void complete_create_array_klass(arrayKlassHandle k, KlassHandle super_klass, TRAPS); - public: - // jvm support - jint compute_modifier_flags(TRAPS) const; + // jvm support + jint compute_modifier_flags(TRAPS) const; - public: - // JVMTI support - jint jvmti_class_status() const; + // JVMTI support + jint jvmti_class_status() const; -#ifndef PRODUCT - public: // Printing void oop_print_on(oop obj, outputStream* st); -#endif - public: + // Verification void oop_verify_on(oop obj, outputStream* st); }; diff --git a/hotspot/src/share/vm/oops/arrayKlassKlass.cpp b/hotspot/src/share/vm/oops/arrayKlassKlass.cpp index e2bb1432c58..2128f61f93e 100644 --- a/hotspot/src/share/vm/oops/arrayKlassKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlassKlass.cpp @@ -151,15 +151,12 @@ arrayKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj, } #endif // SERIALGC -#ifndef PRODUCT - // Printing void arrayKlassKlass::oop_print_on(oop obj, outputStream* st) { assert(obj->is_klass(), "must be klass"); klassKlass::oop_print_on(obj, st); } -#endif //PRODUCT void arrayKlassKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_klass(), "must be klass"); diff --git a/hotspot/src/share/vm/oops/arrayKlassKlass.hpp b/hotspot/src/share/vm/oops/arrayKlassKlass.hpp index 6377fd689c3..4fe4fb51aad 100644 --- a/hotspot/src/share/vm/oops/arrayKlassKlass.hpp +++ b/hotspot/src/share/vm/oops/arrayKlassKlass.hpp @@ -55,12 +55,9 @@ class arrayKlassKlass : public klassKlass { int oop_oop_iterate(oop obj, OopClosure* blk); int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); - public: // Printing void oop_print_value_on(oop obj, outputStream* st); -#ifndef PRODUCT void oop_print_on(oop obj, outputStream* st); -#endif //PRODUCT // Verification const char* internal_name() const; diff --git a/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp b/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp index fcda8a56adb..800b7eba9b1 100644 --- a/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp +++ b/hotspot/src/share/vm/oops/compiledICHolderKlass.cpp @@ -154,8 +154,6 @@ int compiledICHolderKlass::oop_update_pointers(ParCompactionManager* cm, } #endif // SERIALGC -#ifndef PRODUCT - // Printing void compiledICHolderKlass::oop_print_on(oop obj, outputStream* st) { @@ -166,8 +164,6 @@ void compiledICHolderKlass::oop_print_on(oop obj, outputStream* st) { st->print(" - klass: "); c->holder_klass()->print_value_on(st); st->cr(); } -#endif //PRODUCT - void compiledICHolderKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_compiledICHolder(), "must be compiledICHolder"); Klass::oop_print_value_on(obj, st); diff --git a/hotspot/src/share/vm/oops/compiledICHolderKlass.hpp b/hotspot/src/share/vm/oops/compiledICHolderKlass.hpp index 2baefb79444..33fd89b0d62 100644 --- a/hotspot/src/share/vm/oops/compiledICHolderKlass.hpp +++ b/hotspot/src/share/vm/oops/compiledICHolderKlass.hpp @@ -68,12 +68,9 @@ class compiledICHolderKlass : public Klass { int oop_oop_iterate(oop obj, OopClosure* blk); int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); - public: // Printing void oop_print_value_on(oop obj, outputStream* st); -#ifndef PRODUCT void oop_print_on (oop obj, outputStream* st); -#endif //PRODUCT // Verification const char* internal_name() const; diff --git a/hotspot/src/share/vm/oops/constMethodKlass.cpp b/hotspot/src/share/vm/oops/constMethodKlass.cpp index 593e4c9838a..b5f15e5f6b7 100644 --- a/hotspot/src/share/vm/oops/constMethodKlass.cpp +++ b/hotspot/src/share/vm/oops/constMethodKlass.cpp @@ -197,8 +197,6 @@ int constMethodKlass::oop_update_pointers(ParCompactionManager* cm, oop obj, } #endif // SERIALGC -#ifndef PRODUCT - // Printing void constMethodKlass::oop_print_on(oop obj, outputStream* st) { @@ -216,8 +214,6 @@ void constMethodKlass::oop_print_on(oop obj, outputStream* st) { } } -#endif //PRODUCT - // Short version of printing constMethodOop - just print the name of the // method it belongs to. void constMethodKlass::oop_print_value_on(oop obj, outputStream* st) { diff --git a/hotspot/src/share/vm/oops/constMethodKlass.hpp b/hotspot/src/share/vm/oops/constMethodKlass.hpp index bc478142177..4e99518c675 100644 --- a/hotspot/src/share/vm/oops/constMethodKlass.hpp +++ b/hotspot/src/share/vm/oops/constMethodKlass.hpp @@ -77,12 +77,9 @@ public: int oop_oop_iterate(oop obj, OopClosure* blk); int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); - public: // Printing void oop_print_value_on(oop obj, outputStream* st); -#ifndef PRODUCT void oop_print_on (oop obj, outputStream* st); -#endif //PRODUCT // Verify operations const char* internal_name() const; diff --git a/hotspot/src/share/vm/oops/constantPoolKlass.cpp b/hotspot/src/share/vm/oops/constantPoolKlass.cpp index dd4cb287c4a..7ca3c79b1da 100644 --- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp +++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp @@ -299,8 +299,6 @@ void constantPoolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { } #endif // SERIALGC -#ifndef PRODUCT - // Printing void constantPoolKlass::oop_print_on(oop obj, outputStream* st) { @@ -392,8 +390,6 @@ void constantPoolKlass::oop_print_on(oop obj, outputStream* st) { st->cr(); } -#endif - void constantPoolKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_constantPool(), "must be constantPool"); constantPoolOop cp = constantPoolOop(obj); diff --git a/hotspot/src/share/vm/oops/constantPoolKlass.hpp b/hotspot/src/share/vm/oops/constantPoolKlass.hpp index 65f9a931f1f..95adcbe307b 100644 --- a/hotspot/src/share/vm/oops/constantPoolKlass.hpp +++ b/hotspot/src/share/vm/oops/constantPoolKlass.hpp @@ -61,18 +61,13 @@ class constantPoolKlass : public Klass { int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr); // Allocation profiling support - // no idea why this is pure virtual and not in Klass ??? juint alloc_size() const { return _alloc_size; } void set_alloc_size(juint n) { _alloc_size = n; } - public: // Printing void oop_print_value_on(oop obj, outputStream* st); -#ifndef PRODUCT void oop_print_on(oop obj, outputStream* st); -#endif - public: // Verification const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/cpCacheKlass.cpp b/hotspot/src/share/vm/oops/cpCacheKlass.cpp index afff3352a6c..3d7916ffaa5 100644 --- a/hotspot/src/share/vm/oops/cpCacheKlass.cpp +++ b/hotspot/src/share/vm/oops/cpCacheKlass.cpp @@ -248,8 +248,6 @@ constantPoolCacheKlass::oop_update_pointers(ParCompactionManager* cm, oop obj, } #endif // SERIALGC -#ifndef PRODUCT - void constantPoolCacheKlass::oop_print_on(oop obj, outputStream* st) { assert(obj->is_constantPoolCache(), "obj must be constant pool cache"); constantPoolCacheOop cache = (constantPoolCacheOop)obj; @@ -259,8 +257,6 @@ void constantPoolCacheKlass::oop_print_on(oop obj, outputStream* st) { for (int i = 0; i < cache->length(); i++) cache->entry_at(i)->print(st, i); } -#endif - void constantPoolCacheKlass::oop_print_value_on(oop obj, outputStream* st) { assert(obj->is_constantPoolCache(), "obj must be constant pool cache"); constantPoolCacheOop cache = (constantPoolCacheOop)obj; diff --git a/hotspot/src/share/vm/oops/cpCacheKlass.hpp b/hotspot/src/share/vm/oops/cpCacheKlass.hpp index 2104dbbe0a5..f790e16374e 100644 --- a/hotspot/src/share/vm/oops/cpCacheKlass.hpp +++ b/hotspot/src/share/vm/oops/cpCacheKlass.hpp @@ -61,14 +61,10 @@ class constantPoolCacheKlass: public Klass { juint alloc_size() const { return _alloc_size; } void set_alloc_size(juint n) { _alloc_size = n; } - public: // Printing void oop_print_value_on(oop obj, outputStream* st); -#ifndef PRODUCT void oop_print_on(oop obj, outputStream* st); -#endif - public: // Verification const char* internal_name() const; void oop_verify_on(oop obj, outputStream* st); diff --git a/hotspot/src/share/vm/oops/generateOopMap.cpp b/hotspot/src/share/vm/oops/generateOopMap.cpp index 952e2661ef9..25067a84d32 100644 --- a/hotspot/src/share/vm/oops/generateOopMap.cpp +++ b/hotspot/src/share/vm/oops/generateOopMap.cpp @@ -2111,7 +2111,13 @@ void GenerateOopMap::verify_error(const char *format, ...) { // We do not distinguish between different types of errors for verification // errors. Let the verifier give a better message. const char *msg = "Illegal class file encountered. Try running with -Xverify:all"; - error_work(msg, NULL); + _got_error = true; + // Append method name + char msg_buffer2[512]; + jio_snprintf(msg_buffer2, sizeof(msg_buffer2), "%s in method %s", msg, + method()->name()->as_C_string()); + _exception = Exceptions::new_exception(Thread::current(), + vmSymbols::java_lang_LinkageError(), msg_buffer2); } // diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index 867d715b4a6..2b6dc261ef9 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -520,8 +520,6 @@ jint Klass::jvmti_class_status() const { return 0; } -#ifndef PRODUCT - // Printing void Klass::oop_print_on(oop obj, outputStream* st) { @@ -541,8 +539,6 @@ void Klass::oop_print_on(oop obj, outputStream* st) { st->cr(); } -#endif //PRODUCT - void Klass::oop_print_value_on(oop obj, outputStream* st) { // print title ResourceMark rm; // Cannot print in debug mode without this diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 8895a64e3b5..ca4571b9b39 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -772,16 +772,12 @@ class Klass : public Klass_vtbl { // jvm support virtual jint compute_modifier_flags(TRAPS) const; - public: // JVMTI support virtual jint jvmti_class_status() const; - public: // Printing virtual void oop_print_value_on(oop obj, outputStream* st); -#ifndef PRODUCT virtual void oop_print_on (oop obj, outputStream* st); -#endif //PRODUCT // Verification virtual const char* internal_name() const = 0; diff --git a/hotspot/src/share/vm/oops/klassKlass.cpp b/hotspot/src/share/vm/oops/klassKlass.cpp index d4647e1081f..74a352fda35 100644 --- a/hotspot/src/share/vm/oops/klassKlass.cpp +++ b/hotspot/src/share/vm/oops/klassKlass.cpp @@ -194,16 +194,12 @@ int klassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj, #endif // SERIALGC -#ifndef PRODUCT - // Printing void klassKlass::oop_print_on(oop obj, outputStream* st) { Klass::oop_print_on(obj, st); } -#endif //PRODUCT - void klassKlass::oop_print_value_on(oop obj, outputStream* st) { Klass::oop_print_value_on(obj, st); } diff --git a/hotspot/src/share/vm/oops/klassKlass.hpp b/hotspot/src/share/vm/oops/klassKlass.hpp index 14b56ff9e7e..168e8daad8d 100644 --- a/hotspot/src/share/vm/oops/klassKlass.hpp +++ b/hotspot/src/share/vm/oops/klassKlass.hpp @@ -67,12 +67,9 @@ class klassKlass: public Klass { juint alloc_size() const { return _alloc_size; } void set_alloc_size(juint n) { _alloc_size = n; } - public: // Printing void oop_print_value_on(oop obj, outputStream* st); -#ifndef PRODUCT void oop_print_on (oop obj, outputStream* st); -#endif //PRODUCT // Verification const char* internal_name() const; diff --git a/hotspot/src/share/vm/oops/methodOop.cpp b/hotspot/src/share/vm/oops/methodOop.cpp index ec32108d2a6..32032c0022c 100644 --- a/hotspot/src/share/vm/oops/methodOop.cpp +++ b/hotspot/src/share/vm/oops/methodOop.cpp @@ -751,10 +751,14 @@ void methodOopDesc::set_code(methodHandle mh, nmethod *code) { } OrderAccess::storestore(); +#ifdef SHARK + mh->_from_interpreted_entry = code->instructions_begin(); +#else mh->_from_compiled_entry = code->verified_entry_point(); OrderAccess::storestore(); // Instantly compiled code can execute. mh->_from_interpreted_entry = mh->get_i2c_entry(); +#endif // SHARK } diff --git a/hotspot/src/share/vm/oops/oop.cpp b/hotspot/src/share/vm/oops/oop.cpp index 1db8b7f0bd2..ff7c78a5073 100644 --- a/hotspot/src/share/vm/oops/oop.cpp +++ b/hotspot/src/share/vm/oops/oop.cpp @@ -29,15 +29,6 @@ bool always_do_update_barrier = false; BarrierSet* oopDesc::_bs = NULL; -#ifdef PRODUCT -void oopDesc::print_on(outputStream* st) const {} -void oopDesc::print_address_on(outputStream* st) const {} -char* oopDesc::print_string() { return NULL; } -void oopDesc::print() {} -void oopDesc::print_address() {} - -#else //PRODUCT - void oopDesc::print_on(outputStream* st) const { if (this == NULL) { st->print_cr("NULL"); @@ -62,10 +53,6 @@ char* oopDesc::print_string() { return st.as_string(); } -#endif // PRODUCT - -// The print_value functions are present in all builds, to support the disassembler. - void oopDesc::print_value() { print_value_on(tty); } @@ -83,9 +70,7 @@ void oopDesc::print_value_on(outputStream* st) const { st->print("NULL"); } else if (java_lang_String::is_instance(obj)) { java_lang_String::print(obj, st); -#ifndef PRODUCT if (PrintOopAddress) print_address_on(st); -#endif //PRODUCT #ifdef ASSERT } else if (!Universe::heap()->is_in(obj) || !Universe::heap()->is_in(klass())) { st->print("### BAD OOP %p ###", (address)obj); diff --git a/hotspot/src/share/vm/opto/block.cpp b/hotspot/src/share/vm/opto/block.cpp index d7cf639c9c4..1d7a84048d5 100644 --- a/hotspot/src/share/vm/opto/block.cpp +++ b/hotspot/src/share/vm/opto/block.cpp @@ -353,7 +353,8 @@ void Block::dump( const Block_Array *bbs ) const { PhaseCFG::PhaseCFG( Arena *a, RootNode *r, Matcher &m ) : Phase(CFG), _bbs(a), - _root(r) + _root(r), + _node_latency(NULL) #ifndef PRODUCT , _trace_opto_pipelining(TraceOptoPipelining || C->method_has_option("TraceOptoPipelining")) #endif diff --git a/hotspot/src/share/vm/opto/block.hpp b/hotspot/src/share/vm/opto/block.hpp index 9bd989539b2..cc06263f18e 100644 --- a/hotspot/src/share/vm/opto/block.hpp +++ b/hotspot/src/share/vm/opto/block.hpp @@ -374,7 +374,7 @@ class PhaseCFG : public Phase { float _outer_loop_freq; // Outmost loop frequency // Per node latency estimation, valid only during GCM - GrowableArray _node_latency; + GrowableArray *_node_latency; #ifndef PRODUCT bool _trace_opto_pipelining; // tracing flag diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index ac0a991d485..3fdaf842740 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -281,6 +281,12 @@ product(bool, InsertMemBarAfterArraycopy, true, \ "Insert memory barrier after arraycopy call") \ \ + develop(bool, SubsumeLoads, true, \ + "Attempt to compile while subsuming loads into machine instructions.") \ + \ + develop(bool, StressRecompilation, false, \ + "Recompile each compiled method without subsuming loads or escape analysis.") \ + \ /* controls for tier 1 compilations */ \ \ develop(bool, Tier1CountInvocations, true, \ diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp index ff4fa6bade6..142273b2626 100644 --- a/hotspot/src/share/vm/opto/c2compiler.cpp +++ b/hotspot/src/share/vm/opto/c2compiler.cpp @@ -103,13 +103,14 @@ void C2Compiler::compile_method(ciEnv* env, if (!is_initialized()) { initialize(); } - bool subsume_loads = true; + bool subsume_loads = SubsumeLoads; bool do_escape_analysis = DoEscapeAnalysis && !env->jvmti_can_access_local_variables(); while (!env->failing()) { // Attempt to compile while subsuming loads into machine instructions. Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis); + // Check result and retry if appropriate. if (C.failure_reason() != NULL) { if (C.failure_reason_is(retry_no_subsuming_loads())) { @@ -127,6 +128,16 @@ void C2Compiler::compile_method(ciEnv* env, // on the ciEnv via env->record_method_not_compilable(). env->record_failure(C.failure_reason()); } + if (StressRecompilation) { + if (subsume_loads) { + subsume_loads = false; + continue; // retry + } + if (do_escape_analysis) { + do_escape_analysis = false; + continue; // retry + } + } // No retry; just break the loop. break; diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index ed9124b24f8..4a8e0e3f526 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -569,7 +569,7 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { if (trace_spilling() && lrg._def != NULL) { // collect defs for MultiDef printing if (lrg._defs == NULL) { - lrg._defs = new (_ifg->_arena) GrowableArray(); + lrg._defs = new (_ifg->_arena) GrowableArray(_ifg->_arena, 2, 0, NULL); lrg._defs->append(lrg._def); } lrg._defs->append(n); diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 63206652187..e5d3c4fdd67 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -904,8 +904,8 @@ void Compile::Init(int aliaslevel) { probe_alias_cache(NULL)->_index = AliasIdxTop; _intrinsics = NULL; - _macro_nodes = new GrowableArray(comp_arena(), 8, 0, NULL); - _predicate_opaqs = new GrowableArray(comp_arena(), 8, 0, NULL); + _macro_nodes = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); + _predicate_opaqs = new(comp_arena()) GrowableArray(comp_arena(), 8, 0, NULL); register_library_intrinsics(); } diff --git a/hotspot/src/share/vm/opto/gcm.cpp b/hotspot/src/share/vm/opto/gcm.cpp index 5fc0b1c1b6a..f222001d315 100644 --- a/hotspot/src/share/vm/opto/gcm.cpp +++ b/hotspot/src/share/vm/opto/gcm.cpp @@ -841,7 +841,7 @@ void PhaseCFG::partial_latency_of_defs(Node *n) { #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print("# latency_to_inputs: node_latency[%d] = %d for node", - n->_idx, _node_latency.at_grow(n->_idx)); + n->_idx, _node_latency->at_grow(n->_idx)); dump(); } #endif @@ -853,7 +853,7 @@ void PhaseCFG::partial_latency_of_defs(Node *n) { return; uint nlen = n->len(); - uint use_latency = _node_latency.at_grow(n->_idx); + uint use_latency = _node_latency->at_grow(n->_idx); uint use_pre_order = _bbs[n->_idx]->_pre_order; for ( uint j=0; jlatency(j); uint current_latency = delta_latency + use_latency; - if (_node_latency.at_grow(def->_idx) < current_latency) { - _node_latency.at_put_grow(def->_idx, current_latency); + if (_node_latency->at_grow(def->_idx) < current_latency) { + _node_latency->at_put_grow(def->_idx, current_latency); } #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print_cr("# %d + edge_latency(%d) == %d -> %d, node_latency[%d] = %d", use_latency, j, delta_latency, current_latency, def->_idx, - _node_latency.at_grow(def->_idx)); + _node_latency->at_grow(def->_idx)); } #endif } @@ -926,7 +926,7 @@ int PhaseCFG::latency_from_use(Node *n, const Node *def, Node *use) { return 0; uint nlen = use->len(); - uint nl = _node_latency.at_grow(use->_idx); + uint nl = _node_latency->at_grow(use->_idx); for ( uint j=0; jin(j) == n) { @@ -962,7 +962,7 @@ void PhaseCFG::latency_from_uses(Node *n) { #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print("# latency_from_outputs: node_latency[%d] = %d for node", - n->_idx, _node_latency.at_grow(n->_idx)); + n->_idx, _node_latency->at_grow(n->_idx)); dump(); } #endif @@ -975,7 +975,7 @@ void PhaseCFG::latency_from_uses(Node *n) { if (latency < l) latency = l; } - _node_latency.at_put_grow(n->_idx, latency); + _node_latency->at_put_grow(n->_idx, latency); } //------------------------------hoist_to_cheaper_block------------------------- @@ -985,9 +985,9 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { const double delta = 1+PROB_UNLIKELY_MAG(4); Block* least = LCA; double least_freq = least->_freq; - uint target = _node_latency.at_grow(self->_idx); - uint start_latency = _node_latency.at_grow(LCA->_nodes[0]->_idx); - uint end_latency = _node_latency.at_grow(LCA->_nodes[LCA->end_idx()]->_idx); + uint target = _node_latency->at_grow(self->_idx); + uint start_latency = _node_latency->at_grow(LCA->_nodes[0]->_idx); + uint end_latency = _node_latency->at_grow(LCA->_nodes[LCA->end_idx()]->_idx); bool in_latency = (target <= start_latency); const Block* root_block = _bbs[_root->_idx]; @@ -1005,7 +1005,7 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print("# Find cheaper block for latency %d: ", - _node_latency.at_grow(self->_idx)); + _node_latency->at_grow(self->_idx)); self->dump(); tty->print_cr("# B%d: start latency for [%4d]=%d, end latency for [%4d]=%d, freq=%g", LCA->_pre_order, @@ -1032,9 +1032,9 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { if (mach && LCA == root_block) break; - uint start_lat = _node_latency.at_grow(LCA->_nodes[0]->_idx); + uint start_lat = _node_latency->at_grow(LCA->_nodes[0]->_idx); uint end_idx = LCA->end_idx(); - uint end_lat = _node_latency.at_grow(LCA->_nodes[end_idx]->_idx); + uint end_lat = _node_latency->at_grow(LCA->_nodes[end_idx]->_idx); double LCA_freq = LCA->_freq; #ifndef PRODUCT if (trace_opto_pipelining()) { @@ -1073,7 +1073,7 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { tty->print_cr("# Change latency for [%4d] from %d to %d", self->_idx, target, end_latency); } #endif - _node_latency.at_put_grow(self->_idx, end_latency); + _node_latency->at_put_grow(self->_idx, end_latency); partial_latency_of_defs(self); } @@ -1255,8 +1255,7 @@ void PhaseCFG::GlobalCodeMotion( Matcher &matcher, uint unique, Node_List &proj_ // Compute the latency information (via backwards walk) for all the // instructions in the graph - GrowableArray node_latency; - _node_latency = node_latency; + _node_latency = new GrowableArray(); // resource_area allocation if( C->do_scheduling() ) ComputeLatenciesBackwards(visited, stack); @@ -1341,6 +1340,8 @@ void PhaseCFG::GlobalCodeMotion( Matcher &matcher, uint unique, Node_List &proj_ } } #endif + // Dead. + _node_latency = (GrowableArray *)0xdeadbeef; } diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index 0afde90166d..2e43346c7e4 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -113,7 +113,8 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe if( !m->is_Mach() ) continue; MachNode *mach = m->as_Mach(); was_store = false; - switch( mach->ideal_Opcode() ) { + int iop = mach->ideal_Opcode(); + switch( iop ) { case Op_LoadB: case Op_LoadUS: case Op_LoadD: @@ -155,6 +156,12 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe default: // Also check for embedded loads if( !mach->needs_anti_dependence_check() ) continue; // Not an memory op; skip it + if( must_clone[iop] ) { + // Do not move nodes which produce flags because + // RA will try to clone it to place near branch and + // it will cause recompilation, see clone_node(). + continue; + } { // Check that value is used in memory address in // instructions with embedded load (CmpP val1,(val2+off)). @@ -461,7 +468,7 @@ Node *Block::select(PhaseCFG *cfg, Node_List &worklist, int *ready_cnt, VectorSe n_choice = 1; } - uint n_latency = cfg->_node_latency.at_grow(n->_idx); + uint n_latency = cfg->_node_latency->at_grow(n->_idx); uint n_score = n->req(); // Many inputs get high score to break ties // Keep best latency found @@ -738,7 +745,7 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect Node *n = _nodes[j]; int idx = n->_idx; tty->print("# ready cnt:%3d ", ready_cnt[idx]); - tty->print("latency:%3d ", cfg->_node_latency.at_grow(idx)); + tty->print("latency:%3d ", cfg->_node_latency->at_grow(idx)); tty->print("%4d: %s\n", idx, n->Name()); } } @@ -765,7 +772,7 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect #ifndef PRODUCT if (cfg->trace_opto_pipelining()) { tty->print("# select %d: %s", n->_idx, n->Name()); - tty->print(", latency:%d", cfg->_node_latency.at_grow(n->_idx)); + tty->print(", latency:%d", cfg->_node_latency->at_grow(n->_idx)); n->dump(); if (Verbose) { tty->print("# ready list:"); @@ -957,6 +964,8 @@ void Block::call_catch_cleanup(Block_Array &bbs) { Block *sb = _succs[i]; // Clone the entire area; ignoring the edge fixup for now. for( uint j = end; j > beg; j-- ) { + // It is safe here to clone a node with anti_dependence + // since clones dominate on each path. Node *clone = _nodes[j-1]->clone(); sb->_nodes.insert( 1, clone ); bbs.map(clone->_idx,sb); diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 3431731674d..214c3150e40 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -720,7 +720,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode *alloc, GrowableArray is_loaded()) { field_type = TypeInstPtr::BOTTOM; - } else if (field != NULL && field->is_constant()) { + } else if (field != NULL && field->is_constant() && field->is_static()) { // This can happen if the constant oop is non-perm. ciObject* con = field->constant_value().as_object(); // Do not "join" in the previous type; it doesn't add value, diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index e3d331f57d7..010743959c7 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -382,6 +382,10 @@ void Compile::Shorten_branches(Label *labels, int& code_size, int& reloc_size, i if (min_offset_from_last_call == 0) { blk_size += nop_size; } + } else if (mach->ideal_Opcode() == Op_Jump) { + const_size += b->_num_succs; // Address table size + // The size is valid even for 64 bit since it is + // multiplied by 2*jintSize on this method exit. } } min_offset_from_last_call += inst_size; diff --git a/hotspot/src/share/vm/opto/reg_split.cpp b/hotspot/src/share/vm/opto/reg_split.cpp index a0927213a18..a4fee6f7cc2 100644 --- a/hotspot/src/share/vm/opto/reg_split.cpp +++ b/hotspot/src/share/vm/opto/reg_split.cpp @@ -271,6 +271,32 @@ uint PhaseChaitin::split_USE( Node *def, Block *b, Node *use, uint useidx, uint return maxlrg; } +//------------------------------clone_node---------------------------- +// Clone node with anti dependence check. +Node* clone_node(Node* def, Block *b, Compile* C) { + if (def->needs_anti_dependence_check()) { +#ifdef ASSERT + if (Verbose) { + tty->print_cr("RA attempts to clone node with anti_dependence:"); + def->dump(-1); tty->cr(); + tty->print_cr("into block:"); + b->dump(); + } +#endif + if (C->subsume_loads() == true && !C->failing()) { + // Retry with subsume_loads == false + // If this is the first failure, the sentinel string will "stick" + // to the Compile object, and the C2Compiler will see it and retry. + C->record_failure(C2Compiler::retry_no_subsuming_loads()); + } else { + // Bailout without retry + C->record_method_not_compilable("RA Split failed: attempt to clone node with anti_dependence"); + } + return 0; + } + return def->clone(); +} + //------------------------------split_Rematerialize---------------------------- // Clone a local copy of the def. Node *PhaseChaitin::split_Rematerialize( Node *def, Block *b, uint insidx, uint &maxlrg, GrowableArray splits, int slidx, uint *lrg2reach, Node **Reachblock, bool walkThru ) { @@ -298,8 +324,8 @@ Node *PhaseChaitin::split_Rematerialize( Node *def, Block *b, uint insidx, uint } } - Node *spill = def->clone(); - if (C->check_node_count(NodeLimitFudgeFactor, out_of_nodes)) { + Node *spill = clone_node(def, b, C); + if (spill == NULL || C->check_node_count(NodeLimitFudgeFactor, out_of_nodes)) { // Check when generating nodes return 0; } @@ -834,13 +860,13 @@ uint PhaseChaitin::Split( uint maxlrg ) { // The effect of this clone is to drop the node out of the block, // so that the allocator does not see it anymore, and therefore // does not attempt to assign it a register. - def = def->clone(); + def = clone_node(def, b, C); + if (def == NULL || C->check_node_count(NodeLimitFudgeFactor, out_of_nodes)) { + return 0; + } _names.extend(def->_idx,0); _cfg._bbs.map(def->_idx,b); n->set_req(inpidx, def); - if (C->check_node_count(NodeLimitFudgeFactor, out_of_nodes)) { - return 0; - } continue; } diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index c81a6f9c34d..b9961726bad 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -3414,6 +3414,8 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae thread->initialize_tlab(); + thread->cache_global_variables(); + // Crucial that we do not have a safepoint check for this thread, since it has // not been added to the Thread list yet. { Threads_lock->lock_without_safepoint_check(); diff --git a/hotspot/src/share/vm/prims/jvmtiEnvThreadState.hpp b/hotspot/src/share/vm/prims/jvmtiEnvThreadState.hpp index 64a30b46d41..b0ebb066741 100644 --- a/hotspot/src/share/vm/prims/jvmtiEnvThreadState.hpp +++ b/hotspot/src/share/vm/prims/jvmtiEnvThreadState.hpp @@ -24,6 +24,8 @@ #ifndef _JAVA_JVMTIENVTHREADSTATE_H_ #define _JAVA_JVMTIENVTHREADSTATE_H_ +class JvmtiEnv; + /////////////////////////////////////////////////////////////// // // class JvmtiFramePop diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 5ba65fba422..48b61217130 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -2593,6 +2593,12 @@ SOLARIS_ONLY( FLAG_IS_DEFAULT(UseVMInterruptibleIO)) { FLAG_SET_DEFAULT(UseVMInterruptibleIO, true); } +#ifdef LINUX + if (JDK_Version::current().compare_major(6) <= 0 && + FLAG_IS_DEFAULT(UseLinuxPosixThreadCPUClocks)) { + FLAG_SET_DEFAULT(UseLinuxPosixThreadCPUClocks, false); + } +#endif // LINUX return JNI_OK; } @@ -2659,6 +2665,28 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req } #endif + // If we are running in a headless jre, force java.awt.headless property + // to be true unless the property has already been set. + // Also allow the OS environment variable JAVA_AWT_HEADLESS to set headless state. + if (os::is_headless_jre()) { + const char* headless = Arguments::get_property("java.awt.headless"); + if (headless == NULL) { + char envbuffer[128]; + if (!os::getenv("JAVA_AWT_HEADLESS", envbuffer, sizeof(envbuffer))) { + if (!add_property("java.awt.headless=true")) { + return JNI_ENOMEM; + } + } else { + char buffer[256]; + strcpy(buffer, "java.awt.headless="); + strcat(buffer, envbuffer); + if (!add_property(buffer)) { + return JNI_ENOMEM; + } + } + } + } + if (!check_vm_args_consistency()) { return JNI_ERR; } @@ -2979,6 +3007,14 @@ jint Arguments::parse(const JavaVMInitArgs* args) { CommandLineFlags::printFlags(); } + // Apply CPU specific policy for the BiasedLocking + if (UseBiasedLocking) { + if (!VM_Version::use_biased_locking() && + !(FLAG_IS_CMDLINE(UseBiasedLocking))) { + UseBiasedLocking = false; + } + } + return JNI_OK; } diff --git a/hotspot/src/share/vm/runtime/deoptimization.cpp b/hotspot/src/share/vm/runtime/deoptimization.cpp index a0f26be2e49..2fc5edc360d 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.cpp +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp @@ -254,6 +254,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread } +#ifndef SHARK // Compute the caller frame based on the sender sp of stub_frame and stored frame sizes info. CodeBlob* cb = stub_frame.cb(); // Verify we have the right vframeArray @@ -270,6 +271,10 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking"); Events::log("fetch unroll sp " INTPTR_FORMAT, unpack_sp); #endif +#else + intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp(); +#endif // !SHARK + // This is a guarantee instead of an assert because if vframe doesn't match // we will unpack the wrong deoptimized frame and wind up in strange places // where it will be very difficult to figure out what went wrong. Better @@ -380,7 +385,9 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread frame_pcs[0] = deopt_sender.raw_pc(); +#ifndef SHARK assert(CodeCache::find_blob_unsafe(frame_pcs[0]) != NULL, "bad pc"); +#endif // SHARK UnrollBlock* info = new UnrollBlock(array->frame_size() * BytesPerWord, caller_adjustment * BytesPerWord, @@ -1073,7 +1080,7 @@ JRT_LEAF(void, Deoptimization::popframe_preserve_args(JavaThread* thread, int by JRT_END -#ifdef COMPILER2 +#if defined(COMPILER2) || defined(SHARK) void Deoptimization::load_class_by_index(constantPoolHandle constant_pool, int index, TRAPS) { // in case of an unresolved klass entry, load the class. if (constant_pool->tag_at(index).is_unresolved_klass()) { @@ -1835,7 +1842,7 @@ void Deoptimization::print_statistics() { if (xtty != NULL) xtty->tail("statistics"); } } -#else // COMPILER2 +#else // COMPILER2 || SHARK // Stubs for C1 only system. @@ -1871,4 +1878,4 @@ const char* Deoptimization::format_trap_state(char* buf, size_t buflen, return buf; } -#endif // COMPILER2 +#endif // COMPILER2 || SHARK diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index 9fb56f972c4..89de3ca1a99 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -876,6 +876,7 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer #endif /* CC_INTERP */ +#ifndef PPC if (m->is_native()) { #ifdef CC_INTERP f->do_oop((oop*)&istate->_oop_temp); @@ -883,6 +884,11 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer f->do_oop((oop*)( fp() + interpreter_frame_oop_temp_offset )); #endif /* CC_INTERP */ } +#else // PPC + if (m->is_native() && m->is_static()) { + f->do_oop(interpreter_frame_mirror_addr()); + } +#endif // PPC int max_locals = m->is_native() ? m->size_of_parameters() : m->max_locals(); @@ -1094,6 +1100,10 @@ void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* ma oops_entry_do(f, map); } else if (CodeCache::contains(pc())) { oops_code_blob_do(f, cf, map); +#ifdef SHARK + } else if (is_fake_stub_frame()) { + // nothing to do +#endif // SHARK } else { ShouldNotReachHere(); } diff --git a/hotspot/src/share/vm/runtime/frame.hpp b/hotspot/src/share/vm/runtime/frame.hpp index 68f7115ec6d..4f2df2ad964 100644 --- a/hotspot/src/share/vm/runtime/frame.hpp +++ b/hotspot/src/share/vm/runtime/frame.hpp @@ -25,6 +25,7 @@ typedef class BytecodeInterpreter* interpreterState; class CodeBlob; +class vframeArray; // A frame represents a physical stack frame (an activation). Frames @@ -296,6 +297,9 @@ class frame VALUE_OBJ_CLASS_SPEC { void interpreter_frame_set_method(methodOop method); methodOop* interpreter_frame_method_addr() const; constantPoolCacheOop* interpreter_frame_cache_addr() const; +#ifdef PPC + oop* interpreter_frame_mirror_addr() const; +#endif public: // Entry frames diff --git a/hotspot/src/share/vm/runtime/globals.cpp b/hotspot/src/share/vm/runtime/globals.cpp index d172030f2db..e0603d38d6a 100644 --- a/hotspot/src/share/vm/runtime/globals.cpp +++ b/hotspot/src/share/vm/runtime/globals.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -181,6 +181,18 @@ void Flag::print_as_flag(outputStream* st) { #define C2_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 notproduct}", DEFAULT }, #endif +#define SHARK_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark product}", DEFAULT }, +#define SHARK_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{Shark pd product}", DEFAULT }, +#define SHARK_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark diagnostic}", DEFAULT }, +#ifdef PRODUCT + #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ + #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ + #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) +#else + #define SHARK_DEVELOP_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark}", DEFAULT }, + #define SHARK_PD_DEVELOP_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{Shark pd}", DEFAULT }, + #define SHARK_NOTPRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{Shark notproduct}", DEFAULT }, +#endif static Flag flagTable[] = { RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT, RUNTIME_LP64_PRODUCT_FLAG_STRUCT) @@ -193,6 +205,9 @@ static Flag flagTable[] = { #endif #ifdef COMPILER2 C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, C2_PD_DEVELOP_FLAG_STRUCT, C2_PRODUCT_FLAG_STRUCT, C2_PD_PRODUCT_FLAG_STRUCT, C2_DIAGNOSTIC_FLAG_STRUCT, C2_EXPERIMENTAL_FLAG_STRUCT, C2_NOTPRODUCT_FLAG_STRUCT) +#endif +#ifdef SHARK + SHARK_FLAGS(SHARK_DEVELOP_FLAG_STRUCT, SHARK_PD_DEVELOP_FLAG_STRUCT, SHARK_PRODUCT_FLAG_STRUCT, SHARK_PD_PRODUCT_FLAG_STRUCT, SHARK_DIAGNOSTIC_FLAG_STRUCT, SHARK_NOTPRODUCT_FLAG_STRUCT) #endif {0, NULL, NULL} }; diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index daf5b6b6ba5..28b26381fba 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -22,7 +22,7 @@ * */ -#if !defined(COMPILER1) && !defined(COMPILER2) +#if !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK) define_pd_global(bool, BackgroundCompilation, false); define_pd_global(bool, UseTLAB, false); define_pd_global(bool, CICompileOSR, false); @@ -607,7 +607,7 @@ class CommandLineFlags { notproduct(bool, PrintMallocFree, false, \ "Trace calls to C heap malloc/free allocation") \ \ - notproduct(bool, PrintOopAddress, false, \ + product(bool, PrintOopAddress, false, \ "Always print the location of the oop") \ \ notproduct(bool, VerifyCodeCacheOften, false, \ @@ -2442,6 +2442,10 @@ class CommandLineFlags { "Call fatal if this exception is thrown. Example: " \ "java -XX:AbortVMOnException=java.lang.NullPointerException Foo") \ \ + notproduct(ccstr, AbortVMOnExceptionMessage, NULL, \ + "Call fatal if the exception pointed by AbortVMOnException " \ + "has this message.") \ + \ develop(bool, DebugVtables, false, \ "add debugging code to vtable dispatch") \ \ @@ -3554,7 +3558,6 @@ class CommandLineFlags { "EINTR for I/O operations results in OS_INTRPT. The default value"\ " of this flag is true for JDK 6 and earliers") - /* * Macros for factoring of globals */ diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 76048dcdad7..b831a0fcb3d 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -378,7 +378,8 @@ void before_exit(JavaThread * thread) { } // Terminate watcher thread - must before disenrolling any periodic task - WatcherThread::stop(); + if (PeriodicTask::num_tasks() > 0) + WatcherThread::stop(); // Print statistics gathered (profiling ...) if (Arguments::has_profile()) { diff --git a/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp b/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp index 062bceb53fc..7f99e020c8e 100644 --- a/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp +++ b/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp @@ -76,7 +76,6 @@ public: JavaFrameAnchor() { clear(); } JavaFrameAnchor(JavaFrameAnchor *src) { copy(src); } - address last_Java_pc(void) { return _last_Java_pc; } void set_last_Java_pc(address pc) { _last_Java_pc = pc; } // Assembly stub generation helpers diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index 31b6078f1c3..b51a6c5f30c 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -735,6 +735,152 @@ void os::print_date_and_time(outputStream *st) { st->print_cr("elapsed time: %d seconds", (int)t); } +// moved from debug.cpp (used to be find()) but still called from there +// The print_pc parameter is only set by the debug code in one case +void os::print_location(outputStream* st, intptr_t x, bool print_pc) { + address addr = (address)x; + CodeBlob* b = CodeCache::find_blob_unsafe(addr); + if (b != NULL) { + if (b->is_buffer_blob()) { + // the interpreter is generated into a buffer blob + InterpreterCodelet* i = Interpreter::codelet_containing(addr); + if (i != NULL) { + i->print_on(st); + return; + } + if (Interpreter::contains(addr)) { + st->print_cr(INTPTR_FORMAT " is pointing into interpreter code" + " (not bytecode specific)", addr); + return; + } + // + if (AdapterHandlerLibrary::contains(b)) { + st->print_cr("Printing AdapterHandler"); + AdapterHandlerLibrary::print_handler_on(st, b); + } + // the stubroutines are generated into a buffer blob + StubCodeDesc* d = StubCodeDesc::desc_for(addr); + if (d != NULL) { + d->print_on(st); + if (print_pc) st->cr(); + return; + } + if (StubRoutines::contains(addr)) { + st->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) " + "stub routine", addr); + return; + } + // the InlineCacheBuffer is using stubs generated into a buffer blob + if (InlineCacheBuffer::contains(addr)) { + st->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", addr); + return; + } + VtableStub* v = VtableStubs::stub_containing(addr); + if (v != NULL) { + v->print_on(st); + return; + } + } + if (print_pc && b->is_nmethod()) { + ResourceMark rm; + st->print("%#p: Compiled ", addr); + ((nmethod*)b)->method()->print_value_on(st); + st->print(" = (CodeBlob*)" INTPTR_FORMAT, b); + st->cr(); + return; + } + if ( b->is_nmethod()) { + if (b->is_zombie()) { + st->print_cr(INTPTR_FORMAT " is zombie nmethod", b); + } else if (b->is_not_entrant()) { + st->print_cr(INTPTR_FORMAT " is non-entrant nmethod", b); + } + } + b->print_on(st); + return; + } + + if (Universe::heap()->is_in(addr)) { + HeapWord* p = Universe::heap()->block_start(addr); + bool print = false; + // If we couldn't find it it just may mean that heap wasn't parseable + // See if we were just given an oop directly + if (p != NULL && Universe::heap()->block_is_obj(p)) { + print = true; + } else if (p == NULL && ((oopDesc*)addr)->is_oop()) { + p = (HeapWord*) addr; + print = true; + } + if (print) { + oop(p)->print_on(st); + if (p != (HeapWord*)x && oop(p)->is_constMethod() && + constMethodOop(p)->contains(addr)) { + Thread *thread = Thread::current(); + HandleMark hm(thread); + methodHandle mh (thread, constMethodOop(p)->method()); + if (!mh->is_native()) { + st->print_cr("bci_from(%p) = %d; print_codes():", + addr, mh->bci_from(address(x))); + mh->print_codes_on(st); + } + } + return; + } + } else { + if (Universe::heap()->is_in_reserved(addr)) { + st->print_cr(INTPTR_FORMAT " is an unallocated location " + "in the heap", addr); + return; + } + } + if (JNIHandles::is_global_handle((jobject) addr)) { + st->print_cr(INTPTR_FORMAT " is a global jni handle", addr); + return; + } + if (JNIHandles::is_weak_global_handle((jobject) addr)) { + st->print_cr(INTPTR_FORMAT " is a weak global jni handle", addr); + return; + } +#ifndef PRODUCT + // we don't keep the block list in product mode + if (JNIHandleBlock::any_contains((jobject) addr)) { + st->print_cr(INTPTR_FORMAT " is a local jni handle", addr); + return; + } +#endif + + for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) { + // Check for privilege stack + if (thread->privileged_stack_top() != NULL && + thread->privileged_stack_top()->contains(addr)) { + st->print_cr(INTPTR_FORMAT " is pointing into the privilege stack " + "for thread: " INTPTR_FORMAT, addr, thread); + thread->print_on(st); + return; + } + // If the addr is a java thread print information about that. + if (addr == (address)thread) { + thread->print_on(st); + return; + } + // If the addr is in the stack region for this thread then report that + // and print thread info + if (thread->stack_base() >= addr && + addr > (thread->stack_base() - thread->stack_size())) { + st->print_cr(INTPTR_FORMAT " is pointing into the stack for thread: " + INTPTR_FORMAT, addr, thread); + thread->print_on(st); + return; + } + + } + // Try an OS specific find + if (os::find(addr, st)) { + return; + } + + st->print_cr(INTPTR_FORMAT " is pointing to unknown location", addr); +} // Looks like all platforms except IA64 can use the same function to check // if C stack is walkable beyond current frame. The check for fp() is not diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 4f7539167d2..b0286535d5d 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,8 +78,10 @@ class os: AllStatic { } public: - static void init(void); // Called before command line parsing - static jint init_2(void); // Called after command line parsing + + static void init(void); // Called before command line parsing + static jint init_2(void); // Called after command line parsing + static void init_3(void); // Called at the end of vm init // File names are case-insensitive on windows only // Override me as needed @@ -322,7 +324,8 @@ class os: AllStatic { pgc_thread, // Parallel GC thread java_thread, compiler_thread, - watcher_thread + watcher_thread, + os_thread }; static bool create_thread(Thread* thread, @@ -451,6 +454,8 @@ class os: AllStatic { static void print_signal_handlers(outputStream* st, char* buf, size_t buflen); static void print_date_and_time(outputStream* st); + static void print_location(outputStream* st, intptr_t x, bool print_pc = false); + // The following two functions are used by fatal error handler to trace // native (C) frames. They are not part of frame.hpp/frame.cpp because // frame.hpp/cpp assume thread is JavaThread, and also because different @@ -480,6 +485,9 @@ class os: AllStatic { // Fills in path to jvm.dll/libjvm.so (this info used to find hpi). static void jvm_path(char *buf, jint buflen); + // Returns true if we are running in a headless jre. + static bool is_headless_jre(); + // JNI names static void print_jni_name_prefix_on(outputStream* st, int args_size); static void print_jni_name_suffix_on(outputStream* st, int args_size); @@ -580,8 +588,8 @@ class os: AllStatic { // Platform dependent stuff #include "incls/_os_pd.hpp.incl" - // debugging support (mostly used by debug.cpp) - static bool find(address pc) PRODUCT_RETURN0; // OS specific function to make sense out of an address + // debugging support (mostly used by debug.cpp but also fatal error handler) + static bool find(address pc, outputStream* st = tty); // OS specific function to make sense out of an address static bool dont_yield(); // when true, JVM_Yield() is nop static void print_statistics(); diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index a059585ce4b..4ff5aa0fa88 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -191,6 +191,121 @@ JRT_LEAF(jdouble, SharedRuntime::drem(jdouble x, jdouble y)) return ((jdouble)fmod((double)x,(double)y)); JRT_END +#ifdef __SOFTFP__ +JRT_LEAF(jfloat, SharedRuntime::fadd(jfloat x, jfloat y)) + return x + y; +JRT_END + +JRT_LEAF(jfloat, SharedRuntime::fsub(jfloat x, jfloat y)) + return x - y; +JRT_END + +JRT_LEAF(jfloat, SharedRuntime::fmul(jfloat x, jfloat y)) + return x * y; +JRT_END + +JRT_LEAF(jfloat, SharedRuntime::fdiv(jfloat x, jfloat y)) + return x / y; +JRT_END + +JRT_LEAF(jdouble, SharedRuntime::dadd(jdouble x, jdouble y)) + return x + y; +JRT_END + +JRT_LEAF(jdouble, SharedRuntime::dsub(jdouble x, jdouble y)) + return x - y; +JRT_END + +JRT_LEAF(jdouble, SharedRuntime::dmul(jdouble x, jdouble y)) + return x * y; +JRT_END + +JRT_LEAF(jdouble, SharedRuntime::ddiv(jdouble x, jdouble y)) + return x / y; +JRT_END + +JRT_LEAF(jfloat, SharedRuntime::i2f(jint x)) + return (jfloat)x; +JRT_END + +JRT_LEAF(jdouble, SharedRuntime::i2d(jint x)) + return (jdouble)x; +JRT_END + +JRT_LEAF(jdouble, SharedRuntime::f2d(jfloat x)) + return (jdouble)x; +JRT_END + +JRT_LEAF(int, SharedRuntime::fcmpl(float x, float y)) + return x>y ? 1 : (x==y ? 0 : -1); /* xy or is_nan */ +JRT_END + +JRT_LEAF(int, SharedRuntime::dcmpl(double x, double y)) + return x>y ? 1 : (x==y ? 0 : -1); /* xy or is_nan */ +JRT_END + +// Functions to return the opposite of the aeabi functions for nan. +JRT_LEAF(int, SharedRuntime::unordered_fcmplt(float x, float y)) + return (x < y) ? 1 : ((g_isnan(x) || g_isnan(y)) ? 1 : 0); +JRT_END + +JRT_LEAF(int, SharedRuntime::unordered_dcmplt(double x, double y)) + return (x < y) ? 1 : ((g_isnan(x) || g_isnan(y)) ? 1 : 0); +JRT_END + +JRT_LEAF(int, SharedRuntime::unordered_fcmple(float x, float y)) + return (x <= y) ? 1 : ((g_isnan(x) || g_isnan(y)) ? 1 : 0); +JRT_END + +JRT_LEAF(int, SharedRuntime::unordered_dcmple(double x, double y)) + return (x <= y) ? 1 : ((g_isnan(x) || g_isnan(y)) ? 1 : 0); +JRT_END + +JRT_LEAF(int, SharedRuntime::unordered_fcmpge(float x, float y)) + return (x >= y) ? 1 : ((g_isnan(x) || g_isnan(y)) ? 1 : 0); +JRT_END + +JRT_LEAF(int, SharedRuntime::unordered_dcmpge(double x, double y)) + return (x >= y) ? 1 : ((g_isnan(x) || g_isnan(y)) ? 1 : 0); +JRT_END + +JRT_LEAF(int, SharedRuntime::unordered_fcmpgt(float x, float y)) + return (x > y) ? 1 : ((g_isnan(x) || g_isnan(y)) ? 1 : 0); +JRT_END + +JRT_LEAF(int, SharedRuntime::unordered_dcmpgt(double x, double y)) + return (x > y) ? 1 : ((g_isnan(x) || g_isnan(y)) ? 1 : 0); +JRT_END + +// Intrinsics make gcc generate code for these. +float SharedRuntime::fneg(float f) { + return -f; +} + +double SharedRuntime::dneg(double f) { + return -f; +} + +#endif // __SOFTFP__ + +#if defined(__SOFTFP__) || defined(E500V2) +// Intrinsics make gcc generate code for these. +double SharedRuntime::dabs(double f) { + return (f <= (double)0.0) ? (double)0.0 - f : f; +} + +double SharedRuntime::dsqrt(double f) { + return sqrt(f); +} +#endif JRT_LEAF(jint, SharedRuntime::f2i(jfloat x)) if (g_isnan(x)) @@ -2046,6 +2161,8 @@ int AdapterHandlerTable::_equals; int AdapterHandlerTable::_hits; int AdapterHandlerTable::_compact; +#endif + class AdapterHandlerTableIterator : public StackObj { private: AdapterHandlerTable* _table; @@ -2081,7 +2198,6 @@ class AdapterHandlerTableIterator : public StackObj { } } }; -#endif // --------------------------------------------------------------------------- @@ -2619,7 +2735,6 @@ JRT_LEAF(void, SharedRuntime::OSR_migration_end( intptr_t* buf) ) FREE_C_HEAP_ARRAY(intptr_t,buf); JRT_END -#ifndef PRODUCT bool AdapterHandlerLibrary::contains(CodeBlob* b) { AdapterHandlerTableIterator iter(_adapters); while (iter.has_next()) { @@ -2629,21 +2744,24 @@ bool AdapterHandlerLibrary::contains(CodeBlob* b) { return false; } -void AdapterHandlerLibrary::print_handler(CodeBlob* b) { +void AdapterHandlerLibrary::print_handler_on(outputStream* st, CodeBlob* b) { AdapterHandlerTableIterator iter(_adapters); while (iter.has_next()) { AdapterHandlerEntry* a = iter.next(); if ( b == CodeCache::find_blob(a->get_i2c_entry()) ) { - tty->print("Adapter for signature: "); - tty->print_cr("%s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT, - a->fingerprint()->as_string(), - a->get_i2c_entry(), a->get_c2i_entry(), a->get_c2i_unverified_entry()); + st->print("Adapter for signature: "); + st->print_cr("%s i2c: " INTPTR_FORMAT " c2i: " INTPTR_FORMAT " c2iUV: " INTPTR_FORMAT, + a->fingerprint()->as_string(), + a->get_i2c_entry(), a->get_c2i_entry(), a->get_c2i_unverified_entry()); + return; } } assert(false, "Should have found handler"); } +#ifndef PRODUCT + void AdapterHandlerLibrary::print_statistics() { _adapters->print_statistics(); } diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index 00b486b24ca..bd5031e49a4 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -78,6 +78,18 @@ class SharedRuntime: AllStatic { static jfloat frem(jfloat x, jfloat y); static jdouble drem(jdouble x, jdouble y); +#ifdef __SOFTFP__ + static jfloat fadd(jfloat x, jfloat y); + static jfloat fsub(jfloat x, jfloat y); + static jfloat fmul(jfloat x, jfloat y); + static jfloat fdiv(jfloat x, jfloat y); + + static jdouble dadd(jdouble x, jdouble y); + static jdouble dsub(jdouble x, jdouble y); + static jdouble dmul(jdouble x, jdouble y); + static jdouble ddiv(jdouble x, jdouble y); +#endif // __SOFTFP__ + // float conversion (needs to set appropriate rounding mode) static jint f2i (jfloat x); static jlong f2l (jfloat x); @@ -87,6 +99,12 @@ class SharedRuntime: AllStatic { static jfloat l2f (jlong x); static jdouble l2d (jlong x); +#ifdef __SOFTFP__ + static jfloat i2f (jint x); + static jdouble i2d (jint x); + static jdouble f2d (jfloat x); +#endif // __SOFTFP__ + // double trigonometrics and transcendentals static jdouble dsin(jdouble x); static jdouble dcos(jdouble x); @@ -96,6 +114,32 @@ class SharedRuntime: AllStatic { static jdouble dexp(jdouble x); static jdouble dpow(jdouble x, jdouble y); +#if defined(__SOFTFP__) || defined(E500V2) + static double dabs(double f); + static double dsqrt(double f); +#endif + +#ifdef __SOFTFP__ + // C++ compiler generates soft float instructions as well as passing + // float and double in registers. + static int fcmpl(float x, float y); + static int fcmpg(float x, float y); + static int dcmpl(double x, double y); + static int dcmpg(double x, double y); + + static int unordered_fcmplt(float x, float y); + static int unordered_dcmplt(double x, double y); + static int unordered_fcmple(float x, float y); + static int unordered_dcmple(double x, double y); + static int unordered_fcmpge(float x, float y); + static int unordered_dcmpge(double x, double y); + static int unordered_fcmpgt(float x, float y); + static int unordered_dcmpgt(double x, double y); + + static float fneg(float f); + static double dneg(double f); +#endif + // exception handling across interpreter/compiler boundaries static address raw_exception_handler_for_return_address(JavaThread* thread, address return_address); static address exception_handler_for_return_address(JavaThread* thread, address return_address); @@ -585,9 +629,7 @@ class AdapterHandlerEntry : public BasicHashtableEntry { bool compare_code(unsigned char* code, int length, int total_args_passed, BasicType* sig_bt); #endif -#ifndef PRODUCT void print(); -#endif /* PRODUCT */ }; class AdapterHandlerLibrary: public AllStatic { @@ -609,9 +651,10 @@ class AdapterHandlerLibrary: public AllStatic { static nmethod* create_dtrace_nmethod (methodHandle method); #endif // HAVE_DTRACE_H -#ifndef PRODUCT - static void print_handler(CodeBlob* b); + static void print_handler(CodeBlob* b) { print_handler_on(tty, b); } + static void print_handler_on(outputStream* st, CodeBlob* b); static bool contains(CodeBlob* b); +#ifndef PRODUCT static void print_statistics(); #endif /* PRODUCT */ diff --git a/hotspot/src/share/vm/runtime/sharedRuntimeTrans.cpp b/hotspot/src/share/vm/runtime/sharedRuntimeTrans.cpp index 69fd010532b..d507290d77e 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntimeTrans.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntimeTrans.cpp @@ -572,7 +572,11 @@ double __ieee754_pow(double x, double y) { if(hy<0) z = one/z; /* z = (1/|x|) */ if(hx<0) { if(((ix-0x3ff00000)|yisint)==0) { +#ifdef CAN_USE_NAN_DEFINE + z = NAN; +#else z = (z-z)/(z-z); /* (-1)**non-int is NaN */ +#endif } else if(yisint==1) z = -1.0*z; /* (x<0)**odd = -(|x|**odd) */ } @@ -583,7 +587,12 @@ double __ieee754_pow(double x, double y) { n = (hx>>31)+1; /* (x<0)**(non-int) is NaN */ - if((n|yisint)==0) return (x-x)/(x-x); + if((n|yisint)==0) +#ifdef CAN_USE_NAN_DEFINE + return NAN; +#else + return (x-x)/(x-x); +#endif s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ diff --git a/hotspot/src/share/vm/runtime/signature.hpp b/hotspot/src/share/vm/runtime/signature.hpp index e0635a13727..00c3bceec10 100644 --- a/hotspot/src/share/vm/runtime/signature.hpp +++ b/hotspot/src/share/vm/runtime/signature.hpp @@ -275,11 +275,7 @@ class NativeSignatureIterator: public SignatureIterator { void do_bool () { pass_int(); _jni_offset++; _offset++; } void do_char () { pass_int(); _jni_offset++; _offset++; } -#if defined(_LP64) || defined(ZERO) void do_float () { pass_float(); _jni_offset++; _offset++; } -#else - void do_float () { pass_int(); _jni_offset++; _offset++; } -#endif #ifdef _LP64 void do_double() { pass_double(); _jni_offset++; _offset += 2; } #else @@ -306,9 +302,7 @@ class NativeSignatureIterator: public SignatureIterator { virtual void pass_int() = 0; virtual void pass_long() = 0; virtual void pass_object() = 0; -#if defined(_LP64) || defined(ZERO) virtual void pass_float() = 0; -#endif #ifdef _LP64 virtual void pass_double() = 0; #else diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp index f9983e1c1f9..e5215dc2b43 100644 --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp @@ -53,15 +53,13 @@ const char* StubCodeDesc::name_for(address pc) { } -void StubCodeDesc::print() { - tty->print(group()); - tty->print("::"); - tty->print(name()); - tty->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT "[ (%d bytes)", begin(), end(), size_in_bytes()); +void StubCodeDesc::print_on(outputStream* st) const { + st->print(group()); + st->print("::"); + st->print(name()); + st->print(" [" INTPTR_FORMAT ", " INTPTR_FORMAT "[ (%d bytes)", begin(), end(), size_in_bytes()); } - - // Implementation of StubCodeGenerator StubCodeGenerator::StubCodeGenerator(CodeBuffer* code) { diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp index 96a6761695b..f47f0dbffd4 100644 --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp @@ -79,7 +79,8 @@ class StubCodeDesc: public CHeapObj { address end() const { return _end; } int size_in_bytes() const { return _end - _begin; } bool contains(address pc) const { return _begin <= pc && pc < _end; } - void print(); + void print_on(outputStream* st) const; + void print() const { print_on(tty); } }; // The base class for all stub-generating code generators. diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index f729a387a34..35afb6fe6b5 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -807,7 +807,7 @@ bool Thread::is_in_stack(address adr) const { // should be revisited, and they should be removed if possible. bool Thread::is_lock_owned(address adr) const { - return (_stack_base >= adr && adr >= (_stack_base - _stack_size)); + return on_local_stack(adr); } bool Thread::set_as_starting_thread() { @@ -1020,7 +1020,7 @@ void NamedThread::set_name(const char* format, ...) { // timer interrupts exists on the platform. WatcherThread* WatcherThread::_watcher_thread = NULL; -bool WatcherThread::_should_terminate = false; +volatile bool WatcherThread::_should_terminate = false; WatcherThread::WatcherThread() : Thread() { assert(watcher_thread() == NULL, "we can only allocate one WatcherThread"); @@ -1052,8 +1052,26 @@ void WatcherThread::run() { // Calculate how long it'll be until the next PeriodicTask work // should be done, and sleep that amount of time. - const size_t time_to_wait = PeriodicTask::time_to_wait(); - os::sleep(this, time_to_wait, false); + size_t time_to_wait = PeriodicTask::time_to_wait(); + + // we expect this to timeout - we only ever get unparked when + // we should terminate + { + OSThreadWaitState osts(this->osthread(), false /* not Object.wait() */); + + jlong prev_time = os::javaTimeNanos(); + for (;;) { + int res= _SleepEvent->park(time_to_wait); + if (res == OS_TIMEOUT || _should_terminate) + break; + // spurious wakeup of some kind + jlong now = os::javaTimeNanos(); + time_to_wait -= (now - prev_time) / 1000000; + if (time_to_wait <= 0) + break; + prev_time = now; + } + } if (is_error_reported()) { // A fatal error has happened, the error handler(VMError::report_and_die) @@ -1115,6 +1133,12 @@ void WatcherThread::stop() { // it is ok to take late safepoints here, if needed MutexLocker mu(Terminator_lock); _should_terminate = true; + OrderAccess::fence(); // ensure WatcherThread sees update in main loop + + Thread* watcher = watcher_thread(); + if (watcher != NULL) + watcher->_SleepEvent->unpark(); + while(watcher_thread() != NULL) { // This wait should make safepoint checks, wait without a timeout, // and wait as a suspend-equivalent condition. @@ -1364,6 +1388,8 @@ void JavaThread::run() { this->create_stack_guard_pages(); + this->cache_global_variables(); + // Thread is now sufficient initialized to be handled by the safepoint code as being // in the VM. Change thread state from _thread_new to _thread_in_vm ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm); @@ -2955,6 +2981,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { return status; } + // Should be done after the heap is fully created + main_thread->cache_global_variables(); + HandleMark hm; { MutexLocker mu(Threads_lock); @@ -3230,6 +3259,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { WatcherThread::start(); } + // Give os specific code one last chance to start + os::init_3(); + create_vm_timer.end(); return JNI_OK; } @@ -3249,12 +3281,18 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym char buffer[JVM_MAXPATHLEN]; char ebuf[1024]; const char *name = agent->name(); + const char *msg = "Could not find agent library "; if (agent->is_absolute_path()) { library = hpi::dll_load(name, ebuf, sizeof ebuf); if (library == NULL) { + const char *sub_msg = " in absolute path, with error: "; + size_t len = strlen(msg) + strlen(name) + strlen(sub_msg) + strlen(ebuf) + 1; + char *buf = NEW_C_HEAP_ARRAY(char, len); + jio_snprintf(buf, len, "%s%s%s%s", msg, name, sub_msg, ebuf); // If we can't find the agent, exit. - vm_exit_during_initialization("Could not find agent library in absolute path", name); + vm_exit_during_initialization(buf, NULL); + FREE_C_HEAP_ARRAY(char, buf); } } else { // Try to load the agent from the standard dll directory @@ -3267,17 +3305,17 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym char *home = Arguments::get_java_home(); const char *fmt = "%s/bin/java %s -Dkernel.background.download=false" " sun.jkernel.DownloadManager -download client_jvm"; - int length = strlen(props) + strlen(home) + strlen(fmt) + 1; - char *cmd = AllocateHeap(length); + size_t length = strlen(props) + strlen(home) + strlen(fmt) + 1; + char *cmd = NEW_C_HEAP_ARRAY(char, length); jio_snprintf(cmd, length, fmt, home, props); int status = os::fork_and_exec(cmd); FreeHeap(props); - FreeHeap(cmd); if (status == -1) { warning(cmd); vm_exit_during_initialization("fork_and_exec failed: %s", strerror(errno)); } + FREE_C_HEAP_ARRAY(char, cmd); // when this comes back the instrument.dll should be where it belongs. library = hpi::dll_load(buffer, ebuf, sizeof ebuf); } @@ -3287,8 +3325,13 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym hpi::dll_build_name(buffer, sizeof(buffer), ns, name); library = hpi::dll_load(buffer, ebuf, sizeof ebuf); if (library == NULL) { + const char *sub_msg = " on the library path, with error: "; + size_t len = strlen(msg) + strlen(name) + strlen(sub_msg) + strlen(ebuf) + 1; + char *buf = NEW_C_HEAP_ARRAY(char, len); + jio_snprintf(buf, len, "%s%s%s%s", msg, name, sub_msg, ebuf); // If we can't find the agent, exit. - vm_exit_during_initialization("Could not find agent library on the library path or in the local directory", name); + vm_exit_during_initialization(buf, NULL); + FREE_C_HEAP_ARRAY(char, buf); } } } diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 323bb604c41..61237f41323 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -410,9 +410,6 @@ public: // Sweeper support void nmethods_do(CodeBlobClosure* cf); - // Tells if adr belong to this thread. This is used - // for checking if a lock is owned by the running thread. - // Used by fast lock support virtual bool is_lock_owned(address adr) const; @@ -449,6 +446,11 @@ public: void set_stack_size(size_t size) { _stack_size = size; } void record_stack_base_and_size(); + bool on_local_stack(address adr) const { + /* QQQ this has knowledge of direction, ought to be a stack method */ + return (_stack_base >= adr && adr >= (_stack_base - _stack_size)); + } + int lgrp_id() const { return _lgrp_id; } void set_lgrp_id(int value) { _lgrp_id = value; } @@ -609,7 +611,7 @@ class WatcherThread: public Thread { private: static WatcherThread* _watcher_thread; - static bool _should_terminate; + volatile static bool _should_terminate; // updated without holding lock public: enum SomeConstants { delay_interval = 10 // interrupt delay in milliseconds @@ -839,6 +841,10 @@ class JavaThread: public Thread { return (struct JNINativeInterface_ *)_jni_environment.functions; } + // This function is called at thread creation to allow + // platform specific thread variables to be initialized. + void cache_global_variables(); + // Executes Shutdown.shutdown() void invoke_shutdown_hooks(); diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index 8639a1d442f..30dada5e07a 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,11 @@ void Abstract_VM_Version::initialize() { #define VMTYPE "Server" #else // TIERED #ifdef ZERO +#ifdef SHARK + #define VMTYPE "Shark" +#else // SHARK #define VMTYPE "Zero" +#endif // SHARK #else // ZERO #define VMTYPE COMPILER1_PRESENT("Client") \ COMPILER2_PRESENT("Server") @@ -152,6 +156,8 @@ const char* Abstract_VM_Version::vm_release() { #define CPU IA32_ONLY("x86") \ IA64_ONLY("ia64") \ AMD64_ONLY("amd64") \ + ARM_ONLY("arm") \ + PPC_ONLY("ppc") \ SPARC_ONLY("sparc") #endif // ZERO diff --git a/hotspot/src/share/vm/runtime/vm_version.hpp b/hotspot/src/share/vm/runtime/vm_version.hpp index 9cfd88be12b..d012786ba8d 100644 --- a/hotspot/src/share/vm/runtime/vm_version.hpp +++ b/hotspot/src/share/vm/runtime/vm_version.hpp @@ -70,6 +70,9 @@ class Abstract_VM_Version: AllStatic { return _logical_processors_per_package; } + // ARCH specific policy for the BiasedLocking + static bool use_biased_locking() { return true; } + // Number of page sizes efficiently supported by the hardware. Most chips now // support two sizes, thus this default implementation. Processor-specific // subclasses should define new versions to hide this one as needed. Note diff --git a/hotspot/src/share/vm/shark/llvmHeaders.hpp b/hotspot/src/share/vm/shark/llvmHeaders.hpp new file mode 100644 index 00000000000..5bd71adc8e2 --- /dev/null +++ b/hotspot/src/share/vm/shark/llvmHeaders.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifdef assert + #undef assert +#endif + +#ifdef DEBUG + #define SHARK_DEBUG + #undef DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#if SHARK_LLVM_VERSION < 27 +#include +#endif +#include +#include +#include +#include +#include +#include +#if SHARK_LLVM_VERSION >= 27 +#include +#include +#include +#include +#endif + +#include + +#ifdef assert + #undef assert +#endif + +// from hotspot/src/share/vm/utilities/debug.hpp +#ifdef ASSERT +#ifndef USE_REPEATED_ASSERTS +#define assert(p, msg) \ +do { \ + if (!(p)) { \ + report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg); \ + BREAKPOINT; \ + } \ +} while (0) +#else // #ifndef USE_REPEATED_ASSERTS +#define assert(p, msg) +do { \ + for (int __i = 0; __i < AssertRepeat; __i++) { \ + if (!(p)) { \ + report_vm_error(__FILE__, __LINE__, "assert(" #p ") failed", msg); \ + BREAKPOINT; \ + } \ + } \ +} while (0) +#endif // #ifndef USE_REPEATED_ASSERTS +#else + #define assert(p, msg) +#endif + +#ifdef DEBUG + #undef DEBUG +#endif +#ifdef SHARK_DEBUG + #define DEBUG + #undef SHARK_DEBUG +#endif diff --git a/hotspot/src/share/vm/shark/llvmValue.hpp b/hotspot/src/share/vm/shark/llvmValue.hpp new file mode 100644 index 00000000000..4088858b644 --- /dev/null +++ b/hotspot/src/share/vm/shark/llvmValue.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class LLVMValue : public AllStatic { + public: + static llvm::ConstantInt* jbyte_constant(jbyte value) + { + return llvm::ConstantInt::get(SharkType::jbyte_type(), value, true); + } + static llvm::ConstantInt* jint_constant(jint value) + { + return llvm::ConstantInt::get(SharkType::jint_type(), value, true); + } + static llvm::ConstantInt* jlong_constant(jlong value) + { + return llvm::ConstantInt::get(SharkType::jlong_type(), value, true); + } + static llvm::ConstantFP* jfloat_constant(jfloat value) + { + return llvm::ConstantFP::get(SharkContext::current(), llvm::APFloat(value)); + } + static llvm::ConstantFP* jdouble_constant(jdouble value) + { + return llvm::ConstantFP::get(SharkContext::current(), llvm::APFloat(value)); + } + static llvm::ConstantPointerNull* null() + { + return llvm::ConstantPointerNull::get(SharkType::oop_type()); + } + + public: + static llvm::ConstantInt* bit_constant(int value) + { + return llvm::ConstantInt::get(SharkType::bit_type(), value, false); + } + static llvm::ConstantInt* intptr_constant(intptr_t value) + { + return llvm::ConstantInt::get(SharkType::intptr_type(), value, false); + } +}; diff --git a/hotspot/src/share/vm/shark/sharkBlock.cpp b/hotspot/src/share/vm/shark/sharkBlock.cpp new file mode 100644 index 00000000000..4f0f437bbdc --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkBlock.cpp @@ -0,0 +1,1260 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkBlock.cpp.incl" + +using namespace llvm; + +void SharkBlock::parse_bytecode(int start, int limit) { + SharkValue *a, *b, *c, *d; + int i; + + // Ensure the current state is initialized before we emit any code, + // so that any setup code for the state is at the start of the block + current_state(); + + // Parse the bytecodes + iter()->reset_to_bci(start); + while (iter()->next_bci() < limit) { + NOT_PRODUCT(a = b = c = d = NULL); + iter()->next(); + + if (SharkTraceBytecodes) + tty->print_cr("%4d: %s", bci(), Bytecodes::name(bc())); + + if (has_trap() && trap_bci() == bci()) { + do_trap(trap_request()); + return; + } + + if (UseLoopSafepoints) { + // XXX if a lcmp is followed by an if_?? then C2 maybe-inserts + // the safepoint before the lcmp rather than before the if. + // Maybe we should do this too. See parse2.cpp for details. + switch (bc()) { + case Bytecodes::_goto: + case Bytecodes::_ifnull: + case Bytecodes::_ifnonnull: + case Bytecodes::_if_acmpeq: + case Bytecodes::_if_acmpne: + case Bytecodes::_ifeq: + case Bytecodes::_ifne: + case Bytecodes::_iflt: + case Bytecodes::_ifle: + case Bytecodes::_ifgt: + case Bytecodes::_ifge: + case Bytecodes::_if_icmpeq: + case Bytecodes::_if_icmpne: + case Bytecodes::_if_icmplt: + case Bytecodes::_if_icmple: + case Bytecodes::_if_icmpgt: + case Bytecodes::_if_icmpge: + if (iter()->get_dest() <= bci()) + maybe_add_backedge_safepoint(); + break; + + case Bytecodes::_goto_w: + if (iter()->get_far_dest() <= bci()) + maybe_add_backedge_safepoint(); + break; + + case Bytecodes::_tableswitch: + case Bytecodes::_lookupswitch: + if (switch_default_dest() <= bci()) { + maybe_add_backedge_safepoint(); + break; + } + int len = switch_table_length(); + for (int i = 0; i < len; i++) { + if (switch_dest(i) <= bci()) { + maybe_add_backedge_safepoint(); + break; + } + } + break; + } + } + + switch (bc()) { + case Bytecodes::_nop: + break; + + case Bytecodes::_aconst_null: + push(SharkValue::null()); + break; + + case Bytecodes::_iconst_m1: + push(SharkValue::jint_constant(-1)); + break; + case Bytecodes::_iconst_0: + push(SharkValue::jint_constant(0)); + break; + case Bytecodes::_iconst_1: + push(SharkValue::jint_constant(1)); + break; + case Bytecodes::_iconst_2: + push(SharkValue::jint_constant(2)); + break; + case Bytecodes::_iconst_3: + push(SharkValue::jint_constant(3)); + break; + case Bytecodes::_iconst_4: + push(SharkValue::jint_constant(4)); + break; + case Bytecodes::_iconst_5: + push(SharkValue::jint_constant(5)); + break; + + case Bytecodes::_lconst_0: + push(SharkValue::jlong_constant(0)); + break; + case Bytecodes::_lconst_1: + push(SharkValue::jlong_constant(1)); + break; + + case Bytecodes::_fconst_0: + push(SharkValue::jfloat_constant(0)); + break; + case Bytecodes::_fconst_1: + push(SharkValue::jfloat_constant(1)); + break; + case Bytecodes::_fconst_2: + push(SharkValue::jfloat_constant(2)); + break; + + case Bytecodes::_dconst_0: + push(SharkValue::jdouble_constant(0)); + break; + case Bytecodes::_dconst_1: + push(SharkValue::jdouble_constant(1)); + break; + + case Bytecodes::_bipush: + push(SharkValue::jint_constant(iter()->get_constant_u1())); + break; + case Bytecodes::_sipush: + push(SharkValue::jint_constant(iter()->get_constant_u2())); + break; + + case Bytecodes::_ldc: + case Bytecodes::_ldc_w: + case Bytecodes::_ldc2_w: + push(SharkConstant::for_ldc(iter())->value(builder())); + break; + + case Bytecodes::_iload_0: + case Bytecodes::_lload_0: + case Bytecodes::_fload_0: + case Bytecodes::_dload_0: + case Bytecodes::_aload_0: + push(local(0)); + break; + case Bytecodes::_iload_1: + case Bytecodes::_lload_1: + case Bytecodes::_fload_1: + case Bytecodes::_dload_1: + case Bytecodes::_aload_1: + push(local(1)); + break; + case Bytecodes::_iload_2: + case Bytecodes::_lload_2: + case Bytecodes::_fload_2: + case Bytecodes::_dload_2: + case Bytecodes::_aload_2: + push(local(2)); + break; + case Bytecodes::_iload_3: + case Bytecodes::_lload_3: + case Bytecodes::_fload_3: + case Bytecodes::_dload_3: + case Bytecodes::_aload_3: + push(local(3)); + break; + case Bytecodes::_iload: + case Bytecodes::_lload: + case Bytecodes::_fload: + case Bytecodes::_dload: + case Bytecodes::_aload: + push(local(iter()->get_index())); + break; + + case Bytecodes::_baload: + do_aload(T_BYTE); + break; + case Bytecodes::_caload: + do_aload(T_CHAR); + break; + case Bytecodes::_saload: + do_aload(T_SHORT); + break; + case Bytecodes::_iaload: + do_aload(T_INT); + break; + case Bytecodes::_laload: + do_aload(T_LONG); + break; + case Bytecodes::_faload: + do_aload(T_FLOAT); + break; + case Bytecodes::_daload: + do_aload(T_DOUBLE); + break; + case Bytecodes::_aaload: + do_aload(T_OBJECT); + break; + + case Bytecodes::_istore_0: + case Bytecodes::_lstore_0: + case Bytecodes::_fstore_0: + case Bytecodes::_dstore_0: + case Bytecodes::_astore_0: + set_local(0, pop()); + break; + case Bytecodes::_istore_1: + case Bytecodes::_lstore_1: + case Bytecodes::_fstore_1: + case Bytecodes::_dstore_1: + case Bytecodes::_astore_1: + set_local(1, pop()); + break; + case Bytecodes::_istore_2: + case Bytecodes::_lstore_2: + case Bytecodes::_fstore_2: + case Bytecodes::_dstore_2: + case Bytecodes::_astore_2: + set_local(2, pop()); + break; + case Bytecodes::_istore_3: + case Bytecodes::_lstore_3: + case Bytecodes::_fstore_3: + case Bytecodes::_dstore_3: + case Bytecodes::_astore_3: + set_local(3, pop()); + break; + case Bytecodes::_istore: + case Bytecodes::_lstore: + case Bytecodes::_fstore: + case Bytecodes::_dstore: + case Bytecodes::_astore: + set_local(iter()->get_index(), pop()); + break; + + case Bytecodes::_bastore: + do_astore(T_BYTE); + break; + case Bytecodes::_castore: + do_astore(T_CHAR); + break; + case Bytecodes::_sastore: + do_astore(T_SHORT); + break; + case Bytecodes::_iastore: + do_astore(T_INT); + break; + case Bytecodes::_lastore: + do_astore(T_LONG); + break; + case Bytecodes::_fastore: + do_astore(T_FLOAT); + break; + case Bytecodes::_dastore: + do_astore(T_DOUBLE); + break; + case Bytecodes::_aastore: + do_astore(T_OBJECT); + break; + + case Bytecodes::_pop: + xpop(); + break; + case Bytecodes::_pop2: + xpop(); + xpop(); + break; + case Bytecodes::_swap: + a = xpop(); + b = xpop(); + xpush(a); + xpush(b); + break; + case Bytecodes::_dup: + a = xpop(); + xpush(a); + xpush(a); + break; + case Bytecodes::_dup_x1: + a = xpop(); + b = xpop(); + xpush(a); + xpush(b); + xpush(a); + break; + case Bytecodes::_dup_x2: + a = xpop(); + b = xpop(); + c = xpop(); + xpush(a); + xpush(c); + xpush(b); + xpush(a); + break; + case Bytecodes::_dup2: + a = xpop(); + b = xpop(); + xpush(b); + xpush(a); + xpush(b); + xpush(a); + break; + case Bytecodes::_dup2_x1: + a = xpop(); + b = xpop(); + c = xpop(); + xpush(b); + xpush(a); + xpush(c); + xpush(b); + xpush(a); + break; + case Bytecodes::_dup2_x2: + a = xpop(); + b = xpop(); + c = xpop(); + d = xpop(); + xpush(b); + xpush(a); + xpush(d); + xpush(c); + xpush(b); + xpush(a); + break; + + case Bytecodes::_arraylength: + do_arraylength(); + break; + + case Bytecodes::_getfield: + do_getfield(); + break; + case Bytecodes::_getstatic: + do_getstatic(); + break; + case Bytecodes::_putfield: + do_putfield(); + break; + case Bytecodes::_putstatic: + do_putstatic(); + break; + + case Bytecodes::_iadd: + b = pop(); + a = pop(); + push(SharkValue::create_jint( + builder()->CreateAdd(a->jint_value(), b->jint_value()), false)); + break; + case Bytecodes::_isub: + b = pop(); + a = pop(); + push(SharkValue::create_jint( + builder()->CreateSub(a->jint_value(), b->jint_value()), false)); + break; + case Bytecodes::_imul: + b = pop(); + a = pop(); + push(SharkValue::create_jint( + builder()->CreateMul(a->jint_value(), b->jint_value()), false)); + break; + case Bytecodes::_idiv: + do_idiv(); + break; + case Bytecodes::_irem: + do_irem(); + break; + case Bytecodes::_ineg: + a = pop(); + push(SharkValue::create_jint( + builder()->CreateNeg(a->jint_value()), a->zero_checked())); + break; + case Bytecodes::_ishl: + b = pop(); + a = pop(); + push(SharkValue::create_jint( + builder()->CreateShl( + a->jint_value(), + builder()->CreateAnd( + b->jint_value(), LLVMValue::jint_constant(0x1f))), false)); + break; + case Bytecodes::_ishr: + b = pop(); + a = pop(); + push(SharkValue::create_jint( + builder()->CreateAShr( + a->jint_value(), + builder()->CreateAnd( + b->jint_value(), LLVMValue::jint_constant(0x1f))), false)); + break; + case Bytecodes::_iushr: + b = pop(); + a = pop(); + push(SharkValue::create_jint( + builder()->CreateLShr( + a->jint_value(), + builder()->CreateAnd( + b->jint_value(), LLVMValue::jint_constant(0x1f))), false)); + break; + case Bytecodes::_iand: + b = pop(); + a = pop(); + push(SharkValue::create_jint( + builder()->CreateAnd(a->jint_value(), b->jint_value()), false)); + break; + case Bytecodes::_ior: + b = pop(); + a = pop(); + push(SharkValue::create_jint( + builder()->CreateOr(a->jint_value(), b->jint_value()), + a->zero_checked() && b->zero_checked())); + break; + case Bytecodes::_ixor: + b = pop(); + a = pop(); + push(SharkValue::create_jint( + builder()->CreateXor(a->jint_value(), b->jint_value()), false)); + break; + + case Bytecodes::_ladd: + b = pop(); + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateAdd(a->jlong_value(), b->jlong_value()), false)); + break; + case Bytecodes::_lsub: + b = pop(); + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateSub(a->jlong_value(), b->jlong_value()), false)); + break; + case Bytecodes::_lmul: + b = pop(); + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateMul(a->jlong_value(), b->jlong_value()), false)); + break; + case Bytecodes::_ldiv: + do_ldiv(); + break; + case Bytecodes::_lrem: + do_lrem(); + break; + case Bytecodes::_lneg: + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateNeg(a->jlong_value()), a->zero_checked())); + break; + case Bytecodes::_lshl: + b = pop(); + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateShl( + a->jlong_value(), + builder()->CreateIntCast( + builder()->CreateAnd( + b->jint_value(), LLVMValue::jint_constant(0x3f)), + SharkType::jlong_type(), true)), false)); + break; + case Bytecodes::_lshr: + b = pop(); + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateAShr( + a->jlong_value(), + builder()->CreateIntCast( + builder()->CreateAnd( + b->jint_value(), LLVMValue::jint_constant(0x3f)), + SharkType::jlong_type(), true)), false)); + break; + case Bytecodes::_lushr: + b = pop(); + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateLShr( + a->jlong_value(), + builder()->CreateIntCast( + builder()->CreateAnd( + b->jint_value(), LLVMValue::jint_constant(0x3f)), + SharkType::jlong_type(), true)), false)); + break; + case Bytecodes::_land: + b = pop(); + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateAnd(a->jlong_value(), b->jlong_value()), false)); + break; + case Bytecodes::_lor: + b = pop(); + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateOr(a->jlong_value(), b->jlong_value()), + a->zero_checked() && b->zero_checked())); + break; + case Bytecodes::_lxor: + b = pop(); + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateXor(a->jlong_value(), b->jlong_value()), false)); + break; + + case Bytecodes::_fadd: + b = pop(); + a = pop(); + push(SharkValue::create_jfloat( + builder()->CreateFAdd(a->jfloat_value(), b->jfloat_value()))); + break; + case Bytecodes::_fsub: + b = pop(); + a = pop(); + push(SharkValue::create_jfloat( + builder()->CreateFSub(a->jfloat_value(), b->jfloat_value()))); + break; + case Bytecodes::_fmul: + b = pop(); + a = pop(); + push(SharkValue::create_jfloat( + builder()->CreateFMul(a->jfloat_value(), b->jfloat_value()))); + break; + case Bytecodes::_fdiv: + b = pop(); + a = pop(); + push(SharkValue::create_jfloat( + builder()->CreateFDiv(a->jfloat_value(), b->jfloat_value()))); + break; + case Bytecodes::_frem: + b = pop(); + a = pop(); + push(SharkValue::create_jfloat( + builder()->CreateFRem(a->jfloat_value(), b->jfloat_value()))); + break; + case Bytecodes::_fneg: + a = pop(); + push(SharkValue::create_jfloat( + builder()->CreateFNeg(a->jfloat_value()))); + break; + + case Bytecodes::_dadd: + b = pop(); + a = pop(); + push(SharkValue::create_jdouble( + builder()->CreateFAdd(a->jdouble_value(), b->jdouble_value()))); + break; + case Bytecodes::_dsub: + b = pop(); + a = pop(); + push(SharkValue::create_jdouble( + builder()->CreateFSub(a->jdouble_value(), b->jdouble_value()))); + break; + case Bytecodes::_dmul: + b = pop(); + a = pop(); + push(SharkValue::create_jdouble( + builder()->CreateFMul(a->jdouble_value(), b->jdouble_value()))); + break; + case Bytecodes::_ddiv: + b = pop(); + a = pop(); + push(SharkValue::create_jdouble( + builder()->CreateFDiv(a->jdouble_value(), b->jdouble_value()))); + break; + case Bytecodes::_drem: + b = pop(); + a = pop(); + push(SharkValue::create_jdouble( + builder()->CreateFRem(a->jdouble_value(), b->jdouble_value()))); + break; + case Bytecodes::_dneg: + a = pop(); + push(SharkValue::create_jdouble( + builder()->CreateFNeg(a->jdouble_value()))); + break; + + case Bytecodes::_iinc: + i = iter()->get_index(); + set_local( + i, + SharkValue::create_jint( + builder()->CreateAdd( + LLVMValue::jint_constant(iter()->get_iinc_con()), + local(i)->jint_value()), false)); + break; + + case Bytecodes::_lcmp: + do_lcmp(); + break; + + case Bytecodes::_fcmpl: + do_fcmp(false, false); + break; + case Bytecodes::_fcmpg: + do_fcmp(false, true); + break; + case Bytecodes::_dcmpl: + do_fcmp(true, false); + break; + case Bytecodes::_dcmpg: + do_fcmp(true, true); + break; + + case Bytecodes::_i2l: + a = pop(); + push(SharkValue::create_jlong( + builder()->CreateIntCast( + a->jint_value(), SharkType::jlong_type(), true), a->zero_checked())); + break; + case Bytecodes::_i2f: + push(SharkValue::create_jfloat( + builder()->CreateSIToFP( + pop()->jint_value(), SharkType::jfloat_type()))); + break; + case Bytecodes::_i2d: + push(SharkValue::create_jdouble( + builder()->CreateSIToFP( + pop()->jint_value(), SharkType::jdouble_type()))); + break; + + case Bytecodes::_l2i: + push(SharkValue::create_jint( + builder()->CreateIntCast( + pop()->jlong_value(), SharkType::jint_type(), true), false)); + break; + case Bytecodes::_l2f: + push(SharkValue::create_jfloat( + builder()->CreateSIToFP( + pop()->jlong_value(), SharkType::jfloat_type()))); + break; + case Bytecodes::_l2d: + push(SharkValue::create_jdouble( + builder()->CreateSIToFP( + pop()->jlong_value(), SharkType::jdouble_type()))); + break; + + case Bytecodes::_f2i: + push(SharkValue::create_jint( + builder()->CreateCall( + builder()->f2i(), pop()->jfloat_value()), false)); + break; + case Bytecodes::_f2l: + push(SharkValue::create_jlong( + builder()->CreateCall( + builder()->f2l(), pop()->jfloat_value()), false)); + break; + case Bytecodes::_f2d: + push(SharkValue::create_jdouble( + builder()->CreateFPExt( + pop()->jfloat_value(), SharkType::jdouble_type()))); + break; + + case Bytecodes::_d2i: + push(SharkValue::create_jint( + builder()->CreateCall( + builder()->d2i(), pop()->jdouble_value()), false)); + break; + case Bytecodes::_d2l: + push(SharkValue::create_jlong( + builder()->CreateCall( + builder()->d2l(), pop()->jdouble_value()), false)); + break; + case Bytecodes::_d2f: + push(SharkValue::create_jfloat( + builder()->CreateFPTrunc( + pop()->jdouble_value(), SharkType::jfloat_type()))); + break; + + case Bytecodes::_i2b: + push(SharkValue::create_jint( + builder()->CreateAShr( + builder()->CreateShl( + pop()->jint_value(), + LLVMValue::jint_constant(24)), + LLVMValue::jint_constant(24)), false)); + break; + case Bytecodes::_i2c: + push(SharkValue::create_jint( + builder()->CreateAnd( + pop()->jint_value(), + LLVMValue::jint_constant(0xffff)), false)); + break; + case Bytecodes::_i2s: + push(SharkValue::create_jint( + builder()->CreateAShr( + builder()->CreateShl( + pop()->jint_value(), + LLVMValue::jint_constant(16)), + LLVMValue::jint_constant(16)), false)); + break; + + case Bytecodes::_return: + do_return(T_VOID); + break; + case Bytecodes::_ireturn: + do_return(T_INT); + break; + case Bytecodes::_lreturn: + do_return(T_LONG); + break; + case Bytecodes::_freturn: + do_return(T_FLOAT); + break; + case Bytecodes::_dreturn: + do_return(T_DOUBLE); + break; + case Bytecodes::_areturn: + do_return(T_OBJECT); + break; + + case Bytecodes::_athrow: + do_athrow(); + break; + + case Bytecodes::_goto: + case Bytecodes::_goto_w: + do_goto(); + break; + + case Bytecodes::_jsr: + case Bytecodes::_jsr_w: + do_jsr(); + break; + + case Bytecodes::_ret: + do_ret(); + break; + + case Bytecodes::_ifnull: + do_if(ICmpInst::ICMP_EQ, SharkValue::null(), pop()); + break; + case Bytecodes::_ifnonnull: + do_if(ICmpInst::ICMP_NE, SharkValue::null(), pop()); + break; + case Bytecodes::_if_acmpeq: + b = pop(); + a = pop(); + do_if(ICmpInst::ICMP_EQ, b, a); + break; + case Bytecodes::_if_acmpne: + b = pop(); + a = pop(); + do_if(ICmpInst::ICMP_NE, b, a); + break; + case Bytecodes::_ifeq: + do_if(ICmpInst::ICMP_EQ, SharkValue::jint_constant(0), pop()); + break; + case Bytecodes::_ifne: + do_if(ICmpInst::ICMP_NE, SharkValue::jint_constant(0), pop()); + break; + case Bytecodes::_iflt: + do_if(ICmpInst::ICMP_SLT, SharkValue::jint_constant(0), pop()); + break; + case Bytecodes::_ifle: + do_if(ICmpInst::ICMP_SLE, SharkValue::jint_constant(0), pop()); + break; + case Bytecodes::_ifgt: + do_if(ICmpInst::ICMP_SGT, SharkValue::jint_constant(0), pop()); + break; + case Bytecodes::_ifge: + do_if(ICmpInst::ICMP_SGE, SharkValue::jint_constant(0), pop()); + break; + case Bytecodes::_if_icmpeq: + b = pop(); + a = pop(); + do_if(ICmpInst::ICMP_EQ, b, a); + break; + case Bytecodes::_if_icmpne: + b = pop(); + a = pop(); + do_if(ICmpInst::ICMP_NE, b, a); + break; + case Bytecodes::_if_icmplt: + b = pop(); + a = pop(); + do_if(ICmpInst::ICMP_SLT, b, a); + break; + case Bytecodes::_if_icmple: + b = pop(); + a = pop(); + do_if(ICmpInst::ICMP_SLE, b, a); + break; + case Bytecodes::_if_icmpgt: + b = pop(); + a = pop(); + do_if(ICmpInst::ICMP_SGT, b, a); + break; + case Bytecodes::_if_icmpge: + b = pop(); + a = pop(); + do_if(ICmpInst::ICMP_SGE, b, a); + break; + + case Bytecodes::_tableswitch: + case Bytecodes::_lookupswitch: + do_switch(); + break; + + case Bytecodes::_invokestatic: + case Bytecodes::_invokespecial: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + do_call(); + break; + + case Bytecodes::_instanceof: + // This is a very common construct: + // + // if (object instanceof Klass) { + // something = (Klass) object; + // ... + // } + // + // which gets compiled to something like this: + // + // 28: aload 9 + // 30: instanceof + // 33: ifeq 52 + // 36: aload 9 + // 38: checkcast + // + // Handling both bytecodes at once allows us + // to eliminate the checkcast. + if (iter()->next_bci() < limit && + (iter()->next_bc() == Bytecodes::_ifeq || + iter()->next_bc() == Bytecodes::_ifne) && + (!UseLoopSafepoints || + iter()->next_get_dest() > iter()->next_bci())) { + if (maybe_do_instanceof_if()) { + iter()->next(); + if (SharkTraceBytecodes) + tty->print_cr("%4d: %s", bci(), Bytecodes::name(bc())); + break; + } + } + // fall through + case Bytecodes::_checkcast: + do_instance_check(); + break; + + case Bytecodes::_new: + do_new(); + break; + case Bytecodes::_newarray: + do_newarray(); + break; + case Bytecodes::_anewarray: + do_anewarray(); + break; + case Bytecodes::_multianewarray: + do_multianewarray(); + break; + + case Bytecodes::_monitorenter: + do_monitorenter(); + break; + case Bytecodes::_monitorexit: + do_monitorexit(); + break; + + default: + ShouldNotReachHere(); + } + } +} + +SharkState* SharkBlock::initial_current_state() { + return entry_state()->copy(); +} + +int SharkBlock::switch_default_dest() { + return iter()->get_dest_table(0); +} + +int SharkBlock::switch_table_length() { + switch(bc()) { + case Bytecodes::_tableswitch: + return iter()->get_int_table(2) - iter()->get_int_table(1) + 1; + + case Bytecodes::_lookupswitch: + return iter()->get_int_table(1); + + default: + ShouldNotReachHere(); + } +} + +int SharkBlock::switch_key(int i) { + switch(bc()) { + case Bytecodes::_tableswitch: + return iter()->get_int_table(1) + i; + + case Bytecodes::_lookupswitch: + return iter()->get_int_table(2 + 2 * i); + + default: + ShouldNotReachHere(); + } +} + +int SharkBlock::switch_dest(int i) { + switch(bc()) { + case Bytecodes::_tableswitch: + return iter()->get_dest_table(i + 3); + + case Bytecodes::_lookupswitch: + return iter()->get_dest_table(2 + 2 * i + 1); + + default: + ShouldNotReachHere(); + } +} + +void SharkBlock::do_div_or_rem(bool is_long, bool is_rem) { + SharkValue *sb = pop(); + SharkValue *sa = pop(); + + check_divide_by_zero(sb); + + Value *a, *b, *p, *q; + if (is_long) { + a = sa->jlong_value(); + b = sb->jlong_value(); + p = LLVMValue::jlong_constant(0x8000000000000000LL); + q = LLVMValue::jlong_constant(-1); + } + else { + a = sa->jint_value(); + b = sb->jint_value(); + p = LLVMValue::jint_constant(0x80000000); + q = LLVMValue::jint_constant(-1); + } + + BasicBlock *ip = builder()->GetBlockInsertionPoint(); + BasicBlock *special_case = builder()->CreateBlock(ip, "special_case"); + BasicBlock *general_case = builder()->CreateBlock(ip, "general_case"); + BasicBlock *done = builder()->CreateBlock(ip, "done"); + + builder()->CreateCondBr( + builder()->CreateAnd( + builder()->CreateICmpEQ(a, p), + builder()->CreateICmpEQ(b, q)), + special_case, general_case); + + builder()->SetInsertPoint(special_case); + Value *special_result; + if (is_rem) { + if (is_long) + special_result = LLVMValue::jlong_constant(0); + else + special_result = LLVMValue::jint_constant(0); + } + else { + special_result = a; + } + builder()->CreateBr(done); + + builder()->SetInsertPoint(general_case); + Value *general_result; + if (is_rem) + general_result = builder()->CreateSRem(a, b); + else + general_result = builder()->CreateSDiv(a, b); + builder()->CreateBr(done); + + builder()->SetInsertPoint(done); + PHINode *result; + if (is_long) + result = builder()->CreatePHI(SharkType::jlong_type(), "result"); + else + result = builder()->CreatePHI(SharkType::jint_type(), "result"); + result->addIncoming(special_result, special_case); + result->addIncoming(general_result, general_case); + + if (is_long) + push(SharkValue::create_jlong(result, false)); + else + push(SharkValue::create_jint(result, false)); +} + +void SharkBlock::do_field_access(bool is_get, bool is_field) { + bool will_link; + ciField *field = iter()->get_field(will_link); + assert(will_link, "typeflow responsibility"); + assert(is_field != field->is_static(), "mismatch"); + + // Pop the value off the stack where necessary + SharkValue *value = NULL; + if (!is_get) + value = pop(); + + // Find the object we're accessing, if necessary + Value *object = NULL; + if (is_field) { + SharkValue *value = pop(); + check_null(value); + object = value->generic_value(); + } + if (is_get && field->is_constant()) { + SharkConstant *constant = SharkConstant::for_field(iter()); + if (constant->is_loaded()) + value = constant->value(builder()); + } + if (!is_get || value == NULL) { + if (!is_field) + object = builder()->CreateInlineOop(field->holder()); + + BasicType basic_type = field->type()->basic_type(); + const Type *stack_type = SharkType::to_stackType(basic_type); + const Type *field_type = SharkType::to_arrayType(basic_type); + + Value *addr = builder()->CreateAddressOfStructEntry( + object, in_ByteSize(field->offset_in_bytes()), + PointerType::getUnqual(field_type), + "addr"); + + // Do the access + if (is_get) { + Value *field_value = builder()->CreateLoad(addr); + + if (field_type != stack_type) { + field_value = builder()->CreateIntCast( + field_value, stack_type, basic_type != T_CHAR); + } + + value = SharkValue::create_generic(field->type(), field_value, false); + } + else { + Value *field_value = value->generic_value(); + + if (field_type != stack_type) { + field_value = builder()->CreateIntCast( + field_value, field_type, basic_type != T_CHAR); + } + + builder()->CreateStore(field_value, addr); + + if (!field->type()->is_primitive_type()) + builder()->CreateUpdateBarrierSet(oopDesc::bs(), addr); + + if (field->is_volatile()) + builder()->CreateMemoryBarrier(SharkBuilder::BARRIER_STORELOAD); + } + } + + // Push the value onto the stack where necessary + if (is_get) + push(value); +} + +void SharkBlock::do_lcmp() { + Value *b = pop()->jlong_value(); + Value *a = pop()->jlong_value(); + + BasicBlock *ip = builder()->GetBlockInsertionPoint(); + BasicBlock *ne = builder()->CreateBlock(ip, "lcmp_ne"); + BasicBlock *lt = builder()->CreateBlock(ip, "lcmp_lt"); + BasicBlock *gt = builder()->CreateBlock(ip, "lcmp_gt"); + BasicBlock *done = builder()->CreateBlock(ip, "done"); + + BasicBlock *eq = builder()->GetInsertBlock(); + builder()->CreateCondBr(builder()->CreateICmpEQ(a, b), done, ne); + + builder()->SetInsertPoint(ne); + builder()->CreateCondBr(builder()->CreateICmpSLT(a, b), lt, gt); + + builder()->SetInsertPoint(lt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(gt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(done); + PHINode *result = builder()->CreatePHI(SharkType::jint_type(), "result"); + result->addIncoming(LLVMValue::jint_constant(-1), lt); + result->addIncoming(LLVMValue::jint_constant(0), eq); + result->addIncoming(LLVMValue::jint_constant(1), gt); + + push(SharkValue::create_jint(result, false)); +} + +void SharkBlock::do_fcmp(bool is_double, bool unordered_is_greater) { + Value *a, *b; + if (is_double) { + b = pop()->jdouble_value(); + a = pop()->jdouble_value(); + } + else { + b = pop()->jfloat_value(); + a = pop()->jfloat_value(); + } + + BasicBlock *ip = builder()->GetBlockInsertionPoint(); + BasicBlock *ordered = builder()->CreateBlock(ip, "ordered"); + BasicBlock *ge = builder()->CreateBlock(ip, "fcmp_ge"); + BasicBlock *lt = builder()->CreateBlock(ip, "fcmp_lt"); + BasicBlock *eq = builder()->CreateBlock(ip, "fcmp_eq"); + BasicBlock *gt = builder()->CreateBlock(ip, "fcmp_gt"); + BasicBlock *done = builder()->CreateBlock(ip, "done"); + + builder()->CreateCondBr( + builder()->CreateFCmpUNO(a, b), + unordered_is_greater ? gt : lt, ordered); + + builder()->SetInsertPoint(ordered); + builder()->CreateCondBr(builder()->CreateFCmpULT(a, b), lt, ge); + + builder()->SetInsertPoint(ge); + builder()->CreateCondBr(builder()->CreateFCmpUGT(a, b), gt, eq); + + builder()->SetInsertPoint(lt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(gt); + builder()->CreateBr(done); + + builder()->SetInsertPoint(eq); + builder()->CreateBr(done); + + builder()->SetInsertPoint(done); + PHINode *result = builder()->CreatePHI(SharkType::jint_type(), "result"); + result->addIncoming(LLVMValue::jint_constant(-1), lt); + result->addIncoming(LLVMValue::jint_constant(0), eq); + result->addIncoming(LLVMValue::jint_constant(1), gt); + + push(SharkValue::create_jint(result, false)); +} + +void SharkBlock::emit_IR() { + ShouldNotCallThis(); +} + +SharkState* SharkBlock::entry_state() { + ShouldNotCallThis(); +} + +void SharkBlock::do_zero_check(SharkValue* value) { + ShouldNotCallThis(); +} + +void SharkBlock::maybe_add_backedge_safepoint() { + ShouldNotCallThis(); +} + +bool SharkBlock::has_trap() { + return false; +} + +int SharkBlock::trap_request() { + ShouldNotCallThis(); +} + +int SharkBlock::trap_bci() { + ShouldNotCallThis(); +} + +void SharkBlock::do_trap(int trap_request) { + ShouldNotCallThis(); +} + +void SharkBlock::do_arraylength() { + ShouldNotCallThis(); +} + +void SharkBlock::do_aload(BasicType basic_type) { + ShouldNotCallThis(); +} + +void SharkBlock::do_astore(BasicType basic_type) { + ShouldNotCallThis(); +} + +void SharkBlock::do_return(BasicType type) { + ShouldNotCallThis(); +} + +void SharkBlock::do_athrow() { + ShouldNotCallThis(); +} + +void SharkBlock::do_goto() { + ShouldNotCallThis(); +} + +void SharkBlock::do_jsr() { + ShouldNotCallThis(); +} + +void SharkBlock::do_ret() { + ShouldNotCallThis(); +} + +void SharkBlock::do_if(ICmpInst::Predicate p, SharkValue* b, SharkValue* a) { + ShouldNotCallThis(); +} + +void SharkBlock::do_switch() { + ShouldNotCallThis(); +} + +void SharkBlock::do_call() { + ShouldNotCallThis(); +} + +void SharkBlock::do_instance_check() { + ShouldNotCallThis(); +} + +bool SharkBlock::maybe_do_instanceof_if() { + ShouldNotCallThis(); +} + +void SharkBlock::do_new() { + ShouldNotCallThis(); +} + +void SharkBlock::do_newarray() { + ShouldNotCallThis(); +} + +void SharkBlock::do_anewarray() { + ShouldNotCallThis(); +} + +void SharkBlock::do_multianewarray() { + ShouldNotCallThis(); +} + +void SharkBlock::do_monitorenter() { + ShouldNotCallThis(); +} + +void SharkBlock::do_monitorexit() { + ShouldNotCallThis(); +} diff --git a/hotspot/src/share/vm/shark/sharkBlock.hpp b/hotspot/src/share/vm/shark/sharkBlock.hpp new file mode 100644 index 00000000000..3de506ecdd3 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkBlock.hpp @@ -0,0 +1,281 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkState; + +class SharkBlock : public SharkTargetInvariants { + protected: + SharkBlock(const SharkTargetInvariants* parent) + : SharkTargetInvariants(parent), + _iter(target()), + _current_state(NULL) {} + + SharkBlock(const SharkCompileInvariants* parent, ciMethod* target) + : SharkTargetInvariants(parent, target), + _iter(target), + _current_state(NULL) {} + + private: + ciBytecodeStream _iter; + SharkState* _current_state; + + public: + ciBytecodeStream* iter() { + return &_iter; + } + Bytecodes::Code bc() { + return iter()->cur_bc(); + } + int bci() { + return iter()->cur_bci(); + } + + // Entry state + protected: + virtual SharkState* entry_state(); + + // Current state + private: + SharkState* initial_current_state(); + + public: + SharkState* current_state() { + if (_current_state == NULL) + set_current_state(initial_current_state()); + return _current_state; + } + + protected: + void set_current_state(SharkState* current_state) { + _current_state = current_state; + } + + // Local variables + protected: + SharkValue* local(int index) { + SharkValue *value = current_state()->local(index); + assert(value != NULL, "shouldn't be"); + assert(value->is_one_word() || + (index + 1 < max_locals() && + current_state()->local(index + 1) == NULL), "should be"); + return value; + } + void set_local(int index, SharkValue* value) { + assert(value != NULL, "shouldn't be"); + current_state()->set_local(index, value); + if (value->is_two_word()) + current_state()->set_local(index + 1, NULL); + } + + // Expression stack (raw) + protected: + void xpush(SharkValue* value) { + current_state()->push(value); + } + SharkValue* xpop() { + return current_state()->pop(); + } + SharkValue* xstack(int slot) { + SharkValue *value = current_state()->stack(slot); + assert(value != NULL, "shouldn't be"); + assert(value->is_one_word() || + (slot > 0 && + current_state()->stack(slot - 1) == NULL), "should be"); + return value; + } + int xstack_depth() { + return current_state()->stack_depth(); + } + + // Expression stack (cooked) + protected: + void push(SharkValue* value) { + assert(value != NULL, "shouldn't be"); + xpush(value); + if (value->is_two_word()) + xpush(NULL); + } + SharkValue* pop() { + int size = current_state()->stack(0) == NULL ? 2 : 1; + if (size == 2) + xpop(); + SharkValue *value = xpop(); + assert(value && value->size() == size, "should be"); + return value; + } + SharkValue* pop_result(BasicType type) { + SharkValue *result = pop(); + +#ifdef ASSERT + switch (result->basic_type()) { + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + assert(type == T_INT, "type mismatch"); + break; + + case T_ARRAY: + assert(type == T_OBJECT, "type mismatch"); + break; + + default: + assert(result->basic_type() == type, "type mismatch"); + } +#endif // ASSERT + + return result; + } + + // Code generation + public: + virtual void emit_IR(); + + protected: + void parse_bytecode(int start, int limit); + + // Helpers + protected: + virtual void do_zero_check(SharkValue* value); + + // Zero checking + protected: + void check_null(SharkValue* object) { + zero_check(object); + } + void check_divide_by_zero(SharkValue* value) { + zero_check(value); + } + private: + void zero_check(SharkValue* value) { + if (!value->zero_checked()) + do_zero_check(value); + } + + // Safepoints + protected: + virtual void maybe_add_backedge_safepoint(); + + // Traps + protected: + virtual bool has_trap(); + virtual int trap_request(); + virtual int trap_bci(); + virtual void do_trap(int trap_request); + + // arraylength + protected: + virtual void do_arraylength(); + + // *aload and *astore + protected: + virtual void do_aload(BasicType basic_type); + virtual void do_astore(BasicType basic_type); + + // *div and *rem + private: + void do_idiv() { + do_div_or_rem(false, false); + } + void do_irem() { + do_div_or_rem(false, true); + } + void do_ldiv() { + do_div_or_rem(true, false); + } + void do_lrem() { + do_div_or_rem(true, true); + } + void do_div_or_rem(bool is_long, bool is_rem); + + // get* and put* + private: + void do_getstatic() { + do_field_access(true, false); + } + void do_getfield() { + do_field_access(true, true); + } + void do_putstatic() { + do_field_access(false, false); + } + void do_putfield() { + do_field_access(false, true); + } + void do_field_access(bool is_get, bool is_field); + + // lcmp and [fd]cmp[lg] + private: + void do_lcmp(); + void do_fcmp(bool is_double, bool unordered_is_greater); + + // *return and athrow + protected: + virtual void do_return(BasicType type); + virtual void do_athrow(); + + // goto* + protected: + virtual void do_goto(); + + // jsr* and ret + protected: + virtual void do_jsr(); + virtual void do_ret(); + + // if* + protected: + virtual void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a); + + // *switch + protected: + int switch_default_dest(); + int switch_table_length(); + int switch_key(int i); + int switch_dest(int i); + + virtual void do_switch(); + + // invoke* + protected: + virtual void do_call(); + + // checkcast and instanceof + protected: + virtual void do_instance_check(); + virtual bool maybe_do_instanceof_if(); + + // new and *newarray + protected: + virtual void do_new(); + virtual void do_newarray(); + virtual void do_anewarray(); + virtual void do_multianewarray(); + + // monitorenter and monitorexit + protected: + virtual void do_monitorenter(); + virtual void do_monitorexit(); +}; diff --git a/hotspot/src/share/vm/shark/sharkBuilder.cpp b/hotspot/src/share/vm/shark/sharkBuilder.cpp new file mode 100644 index 00000000000..1fc7c7c3c57 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkBuilder.cpp @@ -0,0 +1,591 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkBuilder.cpp.incl" + +using namespace llvm; + +SharkBuilder::SharkBuilder(SharkCodeBuffer* code_buffer) + : IRBuilder<>(SharkContext::current()), + _code_buffer(code_buffer) { +} + +// Helpers for accessing structures +Value* SharkBuilder::CreateAddressOfStructEntry(Value* base, + ByteSize offset, + const Type* type, + const char* name) { + return CreateBitCast(CreateStructGEP(base, in_bytes(offset)), type, name); +} + +LoadInst* SharkBuilder::CreateValueOfStructEntry(Value* base, + ByteSize offset, + const Type* type, + const char* name) { + return CreateLoad( + CreateAddressOfStructEntry( + base, offset, PointerType::getUnqual(type)), + name); +} + +// Helpers for accessing arrays + +LoadInst* SharkBuilder::CreateArrayLength(Value* arrayoop) { + return CreateValueOfStructEntry( + arrayoop, in_ByteSize(arrayOopDesc::length_offset_in_bytes()), + SharkType::jint_type(), "length"); +} + +Value* SharkBuilder::CreateArrayAddress(Value* arrayoop, + const Type* element_type, + int element_bytes, + ByteSize base_offset, + Value* index, + const char* name) { + Value* offset = CreateIntCast(index, SharkType::intptr_type(), false); + if (element_bytes != 1) + offset = CreateShl( + offset, + LLVMValue::intptr_constant(exact_log2(element_bytes))); + offset = CreateAdd( + LLVMValue::intptr_constant(in_bytes(base_offset)), offset); + + return CreateIntToPtr( + CreateAdd(CreatePtrToInt(arrayoop, SharkType::intptr_type()), offset), + PointerType::getUnqual(element_type), + name); +} + +Value* SharkBuilder::CreateArrayAddress(Value* arrayoop, + BasicType basic_type, + ByteSize base_offset, + Value* index, + const char* name) { + return CreateArrayAddress( + arrayoop, + SharkType::to_arrayType(basic_type), + type2aelembytes(basic_type), + base_offset, index, name); +} + +Value* SharkBuilder::CreateArrayAddress(Value* arrayoop, + BasicType basic_type, + Value* index, + const char* name) { + return CreateArrayAddress( + arrayoop, basic_type, + in_ByteSize(arrayOopDesc::base_offset_in_bytes(basic_type)), + index, name); +} + +// Helpers for creating intrinsics and external functions. + +const Type* SharkBuilder::make_type(char type, bool void_ok) { + switch (type) { + // Primitive types + case 'c': + return SharkType::jbyte_type(); + case 'i': + return SharkType::jint_type(); + case 'l': + return SharkType::jlong_type(); + case 'x': + return SharkType::intptr_type(); + case 'f': + return SharkType::jfloat_type(); + case 'd': + return SharkType::jdouble_type(); + + // Pointers to primitive types + case 'C': + case 'I': + case 'L': + case 'X': + case 'F': + case 'D': + return PointerType::getUnqual(make_type(tolower(type), false)); + + // VM objects + case 'T': + return SharkType::thread_type(); + case 'M': + return PointerType::getUnqual(SharkType::monitor_type()); + case 'O': + return SharkType::oop_type(); + + // Miscellaneous + case 'v': + assert(void_ok, "should be"); + return SharkType::void_type(); + case '1': + return SharkType::bit_type(); + + default: + ShouldNotReachHere(); + } +} + +const FunctionType* SharkBuilder::make_ftype(const char* params, + const char* ret) { + std::vector param_types; + for (const char* c = params; *c; c++) + param_types.push_back(make_type(*c, false)); + + assert(strlen(ret) == 1, "should be"); + const Type *return_type = make_type(*ret, true); + + return FunctionType::get(return_type, param_types, false); +} + +// Create an object representing an intrinsic or external function by +// referencing the symbol by name. This is the LLVM-style approach, +// but it cannot be used on functions within libjvm.so its symbols +// are not exported. Note that you cannot make this work simply by +// exporting the symbols, as some symbols have the same names as +// symbols in the standard libraries (eg, atan2, fabs) and would +// obscure them were they visible. +Value* SharkBuilder::make_function(const char* name, + const char* params, + const char* ret) { + return SharkContext::current().get_external(name, make_ftype(params, ret)); +} + +// Create an object representing an external function by inlining a +// function pointer in the code. This is not the LLVM way, but it's +// the only way to access functions in libjvm.so and functions like +// __kernel_dmb on ARM which is accessed via an absolute address. +Value* SharkBuilder::make_function(address func, + const char* params, + const char* ret) { + return CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) func), + PointerType::getUnqual(make_ftype(params, ret))); +} + +// VM calls + +Value* SharkBuilder::find_exception_handler() { + return make_function( + (address) SharkRuntime::find_exception_handler, "TIi", "i"); +} + +Value* SharkBuilder::monitorenter() { + return make_function((address) SharkRuntime::monitorenter, "TM", "v"); +} + +Value* SharkBuilder::monitorexit() { + return make_function((address) SharkRuntime::monitorexit, "TM", "v"); +} + +Value* SharkBuilder::new_instance() { + return make_function((address) SharkRuntime::new_instance, "Ti", "v"); +} + +Value* SharkBuilder::newarray() { + return make_function((address) SharkRuntime::newarray, "Tii", "v"); +} + +Value* SharkBuilder::anewarray() { + return make_function((address) SharkRuntime::anewarray, "Tii", "v"); +} + +Value* SharkBuilder::multianewarray() { + return make_function((address) SharkRuntime::multianewarray, "TiiI", "v"); +} + +Value* SharkBuilder::register_finalizer() { + return make_function((address) SharkRuntime::register_finalizer, "TO", "v"); +} + +Value* SharkBuilder::safepoint() { + return make_function((address) SafepointSynchronize::block, "T", "v"); +} + +Value* SharkBuilder::throw_ArithmeticException() { + return make_function( + (address) SharkRuntime::throw_ArithmeticException, "TCi", "v"); +} + +Value* SharkBuilder::throw_ArrayIndexOutOfBoundsException() { + return make_function( + (address) SharkRuntime::throw_ArrayIndexOutOfBoundsException, "TCii", "v"); +} + +Value* SharkBuilder::throw_ClassCastException() { + return make_function( + (address) SharkRuntime::throw_ClassCastException, "TCi", "v"); +} + +Value* SharkBuilder::throw_NullPointerException() { + return make_function( + (address) SharkRuntime::throw_NullPointerException, "TCi", "v"); +} + +// High-level non-VM calls + +Value* SharkBuilder::f2i() { + return make_function((address) SharedRuntime::f2i, "f", "i"); +} + +Value* SharkBuilder::f2l() { + return make_function((address) SharedRuntime::f2l, "f", "l"); +} + +Value* SharkBuilder::d2i() { + return make_function((address) SharedRuntime::d2i, "d", "i"); +} + +Value* SharkBuilder::d2l() { + return make_function((address) SharedRuntime::d2l, "d", "l"); +} + +Value* SharkBuilder::is_subtype_of() { + return make_function((address) SharkRuntime::is_subtype_of, "OO", "c"); +} + +Value* SharkBuilder::current_time_millis() { + return make_function((address) os::javaTimeMillis, "", "l"); +} + +Value* SharkBuilder::sin() { + return make_function("llvm.sin.f64", "d", "d"); +} + +Value* SharkBuilder::cos() { + return make_function("llvm.cos.f64", "d", "d"); +} + +Value* SharkBuilder::tan() { + return make_function((address) ::tan, "d", "d"); +} + +Value* SharkBuilder::atan2() { + return make_function((address) ::atan2, "dd", "d"); +} + +Value* SharkBuilder::sqrt() { + return make_function("llvm.sqrt.f64", "d", "d"); +} + +Value* SharkBuilder::log() { + return make_function("llvm.log.f64", "d", "d"); +} + +Value* SharkBuilder::log10() { + return make_function("llvm.log10.f64", "d", "d"); +} + +Value* SharkBuilder::pow() { + return make_function("llvm.pow.f64", "dd", "d"); +} + +Value* SharkBuilder::exp() { + return make_function("llvm.exp.f64", "d", "d"); +} + +Value* SharkBuilder::fabs() { + return make_function((address) ::fabs, "d", "d"); +} + +Value* SharkBuilder::unsafe_field_offset_to_byte_offset() { + extern jlong Unsafe_field_offset_to_byte_offset(jlong field_offset); + return make_function((address) Unsafe_field_offset_to_byte_offset, "l", "l"); +} + +Value* SharkBuilder::osr_migration_end() { + return make_function((address) SharedRuntime::OSR_migration_end, "C", "v"); +} + +// Semi-VM calls + +Value* SharkBuilder::throw_StackOverflowError() { + return make_function((address) ZeroStack::handle_overflow, "T", "v"); +} + +Value* SharkBuilder::uncommon_trap() { + return make_function((address) SharkRuntime::uncommon_trap, "Ti", "i"); +} + +Value* SharkBuilder::deoptimized_entry_point() { + return make_function((address) CppInterpreter::main_loop, "iT", "v"); +} + +// Native-Java transition + +Value* SharkBuilder::check_special_condition_for_native_trans() { + return make_function( + (address) JavaThread::check_special_condition_for_native_trans, + "T", "v"); +} + +// Low-level non-VM calls + +// The ARM-specific code here is to work around unimplemented +// atomic exchange and memory barrier intrinsics in LLVM. +// +// Delegating to external functions for these would normally +// incur a speed penalty, but Linux on ARM is a special case +// in that atomic operations on that platform are handled by +// external functions anyway. It would be *preferable* for +// the calls to be hidden away in LLVM, but it's not hurting +// performance so having the calls here is acceptable. +// +// If you are building Shark on a platform without atomic +// exchange and/or memory barrier intrinsics then it is only +// acceptable to mimic this approach if your platform cannot +// perform these operations without delegating to a function. + +#ifdef ARM +static jint zero_cmpxchg_int(volatile jint *ptr, jint oldval, jint newval) { + return Atomic::cmpxchg(newval, ptr, oldval); +} +#endif // ARM + +Value* SharkBuilder::cmpxchg_int() { + return make_function( +#ifdef ARM + (address) zero_cmpxchg_int, +#else + "llvm.atomic.cmp.swap.i32.p0i32", +#endif // ARM + "Iii", "i"); +} + +#ifdef ARM +static intptr_t zero_cmpxchg_ptr(volatile intptr_t* ptr, + intptr_t oldval, + intptr_t newval) { + return Atomic::cmpxchg_ptr(newval, ptr, oldval); +} +#endif // ARM + +Value* SharkBuilder::cmpxchg_ptr() { + return make_function( +#ifdef ARM + (address) zero_cmpxchg_ptr, +#else + "llvm.atomic.cmp.swap.i" LP64_ONLY("64") NOT_LP64("32") ".p0i" LP64_ONLY("64") NOT_LP64("32"), +#endif // ARM + "Xxx", "x"); +} + +Value* SharkBuilder::frame_address() { + return make_function("llvm.frameaddress", "i", "C"); +} + +Value* SharkBuilder::memory_barrier() { + return make_function( +#ifdef ARM + (address) 0xffff0fa0, // __kernel_dmb +#else + "llvm.memory.barrier", +#endif // ARM + "11111", "v"); +} + +Value* SharkBuilder::memset() { +#if SHARK_LLVM_VERSION >= 28 + // LLVM 2.8 added a fifth isVolatile field for memset + // introduced with LLVM r100304 + return make_function("llvm.memset.i32", "Cciii", "v"); +#else + return make_function("llvm.memset.i32", "Ccii", "v"); +#endif +} + +Value* SharkBuilder::unimplemented() { + return make_function((address) report_unimplemented, "Ci", "v"); +} + +Value* SharkBuilder::should_not_reach_here() { + return make_function((address) report_should_not_reach_here, "Ci", "v"); +} + +Value* SharkBuilder::dump() { + return make_function((address) SharkRuntime::dump, "Cx", "v"); +} + +// Public interface to low-level non-VM calls + +CallInst* SharkBuilder::CreateCmpxchgInt(Value* exchange_value, + Value* dst, + Value* compare_value) { + return CreateCall3(cmpxchg_int(), dst, compare_value, exchange_value); +} + +CallInst* SharkBuilder::CreateCmpxchgPtr(Value* exchange_value, + Value* dst, + Value* compare_value) { + return CreateCall3(cmpxchg_ptr(), dst, compare_value, exchange_value); +} + +CallInst* SharkBuilder::CreateGetFrameAddress() { + return CreateCall(frame_address(), LLVMValue::jint_constant(0)); +} + +CallInst *SharkBuilder::CreateMemoryBarrier(int flags) { + Value *args[] = { + LLVMValue::bit_constant((flags & BARRIER_LOADLOAD) ? 1 : 0), + LLVMValue::bit_constant((flags & BARRIER_LOADSTORE) ? 1 : 0), + LLVMValue::bit_constant((flags & BARRIER_STORELOAD) ? 1 : 0), + LLVMValue::bit_constant((flags & BARRIER_STORESTORE) ? 1 : 0), + LLVMValue::bit_constant(1)}; + + return CreateCall(memory_barrier(), args, args + 5); +} + +CallInst* SharkBuilder::CreateMemset(Value* dst, + Value* value, + Value* len, + Value* align) { +#if SHARK_LLVM_VERSION >= 28 + return CreateCall5(memset(), dst, value, len, align, + LLVMValue::jint_constant(0)); +#else + return CreateCall4(memset(), dst, value, len, align); +#endif +} + +CallInst* SharkBuilder::CreateUnimplemented(const char* file, int line) { + return CreateCall2( + unimplemented(), + CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) file), + PointerType::getUnqual(SharkType::jbyte_type())), + LLVMValue::jint_constant(line)); +} + +CallInst* SharkBuilder::CreateShouldNotReachHere(const char* file, int line) { + return CreateCall2( + should_not_reach_here(), + CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) file), + PointerType::getUnqual(SharkType::jbyte_type())), + LLVMValue::jint_constant(line)); +} + +#ifndef PRODUCT +CallInst* SharkBuilder::CreateDump(Value* value) { + const char *name; + if (value->hasName()) + // XXX this leaks, but it's only debug code + name = strdup(value->getName().str().c_str()); + else + name = "unnamed_value"; + + if (isa(value->getType())) + value = CreatePtrToInt(value, SharkType::intptr_type()); + else if (value->getType()-> +#if SHARK_LLVM_VERSION >= 27 + isIntegerTy() +#else + isInteger() +#endif + ) + value = CreateIntCast(value, SharkType::intptr_type(), false); + else + Unimplemented(); + + return CreateCall2( + dump(), + CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) name), + PointerType::getUnqual(SharkType::jbyte_type())), + value); +} +#endif // PRODUCT + +// HotSpot memory barriers + +void SharkBuilder::CreateUpdateBarrierSet(BarrierSet* bs, Value* field) { + if (bs->kind() != BarrierSet::CardTableModRef) + Unimplemented(); + + CreateStore( + LLVMValue::jbyte_constant(CardTableModRefBS::dirty_card), + CreateIntToPtr( + CreateAdd( + LLVMValue::intptr_constant( + (intptr_t) ((CardTableModRefBS *) bs)->byte_map_base), + CreateLShr( + CreatePtrToInt(field, SharkType::intptr_type()), + LLVMValue::intptr_constant(CardTableModRefBS::card_shift))), + PointerType::getUnqual(SharkType::jbyte_type()))); +} + +// Helpers for accessing the code buffer + +Value* SharkBuilder::code_buffer_address(int offset) { + return CreateAdd( + code_buffer()->base_pc(), + LLVMValue::intptr_constant(offset)); +} + +Value* SharkBuilder::CreateInlineOop(jobject object, const char* name) { + return CreateLoad( + CreateIntToPtr( + code_buffer_address(code_buffer()->inline_oop(object)), + PointerType::getUnqual(SharkType::oop_type())), + name); +} + +Value* SharkBuilder::CreateInlineData(void* data, + size_t size, + const Type* type, + const char* name) { + return CreateIntToPtr( + code_buffer_address(code_buffer()->inline_data(data, size)), + type, + name); +} + +// Helpers for creating basic blocks. + +BasicBlock* SharkBuilder::GetBlockInsertionPoint() const { + BasicBlock *cur = GetInsertBlock(); + + // BasicBlock::Create takes an insertBefore argument, so + // we need to find the block _after_ the current block + Function::iterator iter = cur->getParent()->begin(); + Function::iterator end = cur->getParent()->end(); + while (iter != end) { + iter++; + if (&*iter == cur) { + iter++; + break; + } + } + + if (iter == end) + return NULL; + else + return iter; +} + +BasicBlock* SharkBuilder::CreateBlock(BasicBlock* ip, const char* name) const { + return BasicBlock::Create( + SharkContext::current(), name, GetInsertBlock()->getParent(), ip); +} diff --git a/hotspot/src/share/vm/shark/sharkBuilder.hpp b/hotspot/src/share/vm/shark/sharkBuilder.hpp new file mode 100644 index 00000000000..376a9fe6818 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkBuilder.hpp @@ -0,0 +1,209 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkBuilder : public llvm::IRBuilder<> { + friend class SharkCompileInvariants; + + public: + SharkBuilder(SharkCodeBuffer* code_buffer); + + // The code buffer we are building into. + private: + SharkCodeBuffer* _code_buffer; + + protected: + SharkCodeBuffer* code_buffer() const { + return _code_buffer; + } + + // Helpers for accessing structures. + public: + llvm::Value* CreateAddressOfStructEntry(llvm::Value* base, + ByteSize offset, + const llvm::Type* type, + const char *name = ""); + llvm::LoadInst* CreateValueOfStructEntry(llvm::Value* base, + ByteSize offset, + const llvm::Type* type, + const char *name = ""); + + // Helpers for accessing arrays. + public: + llvm::LoadInst* CreateArrayLength(llvm::Value* arrayoop); + llvm::Value* CreateArrayAddress(llvm::Value* arrayoop, + const llvm::Type* element_type, + int element_bytes, + ByteSize base_offset, + llvm::Value* index, + const char* name = ""); + llvm::Value* CreateArrayAddress(llvm::Value* arrayoop, + BasicType basic_type, + ByteSize base_offset, + llvm::Value* index, + const char* name = ""); + llvm::Value* CreateArrayAddress(llvm::Value* arrayoop, + BasicType basic_type, + llvm::Value* index, + const char* name = ""); + + // Helpers for creating intrinsics and external functions. + private: + static const llvm::Type* make_type(char type, bool void_ok); + static const llvm::FunctionType* make_ftype(const char* params, + const char* ret); + llvm::Value* make_function(const char* name, + const char* params, + const char* ret); + llvm::Value* make_function(address func, + const char* params, + const char* ret); + + // Intrinsics and external functions, part 1: VM calls. + // These are functions declared with JRT_ENTRY and JRT_EXIT, + // macros which flip the thread from _thread_in_Java to + // _thread_in_vm and back. VM calls always safepoint, and can + // therefore throw exceptions. VM calls require of setup and + // teardown, and must be called with SharkTopLevelBlock::call_vm. + public: + llvm::Value* find_exception_handler(); + llvm::Value* monitorenter(); + llvm::Value* monitorexit(); + llvm::Value* new_instance(); + llvm::Value* newarray(); + llvm::Value* anewarray(); + llvm::Value* multianewarray(); + llvm::Value* register_finalizer(); + llvm::Value* safepoint(); + llvm::Value* throw_ArithmeticException(); + llvm::Value* throw_ArrayIndexOutOfBoundsException(); + llvm::Value* throw_ClassCastException(); + llvm::Value* throw_NullPointerException(); + + // Intrinsics and external functions, part 2: High-level non-VM calls. + // These are called like normal functions. The stack is not set + // up for walking so they must not safepoint or throw exceptions, + // or call anything that might. + public: + llvm::Value* f2i(); + llvm::Value* f2l(); + llvm::Value* d2i(); + llvm::Value* d2l(); + llvm::Value* is_subtype_of(); + llvm::Value* current_time_millis(); + llvm::Value* sin(); + llvm::Value* cos(); + llvm::Value* tan(); + llvm::Value* atan2(); + llvm::Value* sqrt(); + llvm::Value* log(); + llvm::Value* log10(); + llvm::Value* pow(); + llvm::Value* exp(); + llvm::Value* fabs(); + llvm::Value* unsafe_field_offset_to_byte_offset(); + llvm::Value* osr_migration_end(); + + // Intrinsics and external functions, part 3: semi-VM calls. + // These are special cases that do VM call stuff but are invoked + // as though they were normal calls. This is acceptable so long + // as the method that calls them returns to its immediately that + // the semi VM call returns. + public: + llvm::Value* throw_StackOverflowError(); + llvm::Value* uncommon_trap(); + llvm::Value* deoptimized_entry_point(); + + // Intrinsics and external functions, part 4: Native-Java transition. + // This is a special case in that it is invoked during a thread + // state transition. The stack must be set up for walking, and it + // may throw exceptions, but the state is _thread_in_native_trans. + public: + llvm::Value* check_special_condition_for_native_trans(); + + // Intrinsics and external functions, part 5: Low-level non-VM calls. + // These have the same caveats as the high-level non-VM calls + // above. They are not accessed directly; rather, you should + // access them via the various Create* methods below. + private: + llvm::Value* cmpxchg_int(); + llvm::Value* cmpxchg_ptr(); + llvm::Value* frame_address(); + llvm::Value* memory_barrier(); + llvm::Value* memset(); + llvm::Value* unimplemented(); + llvm::Value* should_not_reach_here(); + llvm::Value* dump(); + + // Public interface to low-level non-VM calls. + public: + llvm::CallInst* CreateCmpxchgInt(llvm::Value* exchange_value, + llvm::Value* dst, + llvm::Value* compare_value); + llvm::CallInst* CreateCmpxchgPtr(llvm::Value* exchange_value, + llvm::Value* dst, + llvm::Value* compare_value); + llvm::CallInst* CreateGetFrameAddress(); + llvm::CallInst* CreateMemoryBarrier(int flags); + llvm::CallInst* CreateMemset(llvm::Value* dst, + llvm::Value* value, + llvm::Value* len, + llvm::Value* align); + llvm::CallInst* CreateUnimplemented(const char* file, int line); + llvm::CallInst* CreateShouldNotReachHere(const char* file, int line); + NOT_PRODUCT(llvm::CallInst* CreateDump(llvm::Value* value)); + + // Flags for CreateMemoryBarrier. + public: + enum BarrierFlags { + BARRIER_LOADLOAD = 1, + BARRIER_LOADSTORE = 2, + BARRIER_STORELOAD = 4, + BARRIER_STORESTORE = 8 + }; + + // HotSpot memory barriers + public: + void CreateUpdateBarrierSet(BarrierSet* bs, llvm::Value* field); + + // Helpers for accessing the code buffer. + public: + llvm::Value* code_buffer_address(int offset); + llvm::Value* CreateInlineOop(jobject object, const char* name = ""); + llvm::Value* CreateInlineOop(ciObject* object, const char* name = "") { + return CreateInlineOop(object->constant_encoding(), name); + } + llvm::Value* CreateInlineData(void* data, + size_t size, + const llvm::Type* type, + const char* name = ""); + + // Helpers for creating basic blocks. + // NB don't use unless SharkFunction::CreateBlock is unavailable. + // XXX these are hacky and should be removed. + public: + llvm::BasicBlock* GetBlockInsertionPoint() const; + llvm::BasicBlock* CreateBlock(llvm::BasicBlock* ip, + const char* name="") const; +}; diff --git a/hotspot/src/share/vm/shark/sharkCacheDecache.cpp b/hotspot/src/share/vm/shark/sharkCacheDecache.cpp new file mode 100644 index 00000000000..b9d1c67b802 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkCacheDecache.cpp @@ -0,0 +1,259 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkCacheDecache.cpp.incl" + +using namespace llvm; + +void SharkDecacher::start_frame() { + // Start recording the debug information + _pc_offset = code_buffer()->create_unique_offset(); + _oopmap = new OopMap( + oopmap_slot_munge(stack()->oopmap_frame_size()), + oopmap_slot_munge(arg_size())); + debug_info()->add_safepoint(pc_offset(), oopmap()); +} + +void SharkDecacher::start_stack(int stack_depth) { + // Create the array we'll record our stack slots in + _exparray = new GrowableArray(stack_depth); + + // Set the stack pointer + stack()->CreateStoreStackPointer( + builder()->CreatePtrToInt( + stack()->slot_addr( + stack()->stack_slots_offset() + max_stack() - stack_depth), + SharkType::intptr_type())); +} + +void SharkDecacher::process_stack_slot(int index, + SharkValue** addr, + int offset) { + SharkValue *value = *addr; + + // Write the value to the frame if necessary + if (stack_slot_needs_write(index, value)) { + write_value_to_frame( + SharkType::to_stackType(value->basic_type()), + value->generic_value(), + adjusted_offset(value, offset)); + } + + // Record the value in the oopmap if necessary + if (stack_slot_needs_oopmap(index, value)) { + oopmap()->set_oop(slot2reg(offset)); + } + + // Record the value in the debuginfo if necessary + if (stack_slot_needs_debuginfo(index, value)) { + exparray()->append(slot2lv(offset, stack_location_type(index, addr))); + } +} + +void SharkDecacher::start_monitors(int num_monitors) { + // Create the array we'll record our monitors in + _monarray = new GrowableArray(num_monitors); +} + +void SharkDecacher::process_monitor(int index, int box_offset, int obj_offset) { + oopmap()->set_oop(slot2reg(obj_offset)); + + monarray()->append(new MonitorValue( + slot2lv (obj_offset, Location::oop), + slot2loc(box_offset, Location::normal))); +} + +void SharkDecacher::process_oop_tmp_slot(Value** value, int offset) { + // Decache the temporary oop slot + if (*value) { + write_value_to_frame( + SharkType::oop_type(), + *value, + offset); + + oopmap()->set_oop(slot2reg(offset)); + } +} + +void SharkDecacher::process_method_slot(Value** value, int offset) { + // Decache the method pointer + write_value_to_frame( + SharkType::methodOop_type(), + *value, + offset); + + oopmap()->set_oop(slot2reg(offset)); +} + +void SharkDecacher::process_pc_slot(int offset) { + // Record the PC + builder()->CreateStore( + builder()->code_buffer_address(pc_offset()), + stack()->slot_addr(offset)); +} + +void SharkDecacher::start_locals() { + // Create the array we'll record our local variables in + _locarray = new GrowableArray(max_locals());} + +void SharkDecacher::process_local_slot(int index, + SharkValue** addr, + int offset) { + SharkValue *value = *addr; + + // Write the value to the frame if necessary + if (local_slot_needs_write(index, value)) { + write_value_to_frame( + SharkType::to_stackType(value->basic_type()), + value->generic_value(), + adjusted_offset(value, offset)); + } + + // Record the value in the oopmap if necessary + if (local_slot_needs_oopmap(index, value)) { + oopmap()->set_oop(slot2reg(offset)); + } + + // Record the value in the debuginfo if necessary + if (local_slot_needs_debuginfo(index, value)) { + locarray()->append(slot2lv(offset, local_location_type(index, addr))); + } +} + +void SharkDecacher::end_frame() { + // Record the scope + debug_info()->describe_scope( + pc_offset(), + target(), + bci(), + true, + false, + false, + debug_info()->create_scope_values(locarray()), + debug_info()->create_scope_values(exparray()), + debug_info()->create_monitor_values(monarray())); + + // Finish recording the debug information + debug_info()->end_safepoint(pc_offset()); +} + +void SharkCacher::process_stack_slot(int index, + SharkValue** addr, + int offset) { + SharkValue *value = *addr; + + // Read the value from the frame if necessary + if (stack_slot_needs_read(index, value)) { + *addr = SharkValue::create_generic( + value->type(), + read_value_from_frame( + SharkType::to_stackType(value->basic_type()), + adjusted_offset(value, offset)), + value->zero_checked()); + } +} + +void SharkOSREntryCacher::process_monitor(int index, + int box_offset, + int obj_offset) { + // Copy the monitor from the OSR buffer to the frame + int src_offset = max_locals() + index * 2; + builder()->CreateStore( + builder()->CreateLoad( + CreateAddressOfOSRBufEntry(src_offset, SharkType::intptr_type())), + stack()->slot_addr(box_offset, SharkType::intptr_type())); + builder()->CreateStore( + builder()->CreateLoad( + CreateAddressOfOSRBufEntry(src_offset + 1, SharkType::oop_type())), + stack()->slot_addr(obj_offset, SharkType::oop_type())); +} + +void SharkCacher::process_oop_tmp_slot(Value** value, int offset) { + // Cache the temporary oop + if (*value) + *value = read_value_from_frame(SharkType::oop_type(), offset); +} + +void SharkCacher::process_method_slot(Value** value, int offset) { + // Cache the method pointer + *value = read_value_from_frame(SharkType::methodOop_type(), offset); +} + +void SharkFunctionEntryCacher::process_method_slot(Value** value, int offset) { + // "Cache" the method pointer + *value = method(); +} + +void SharkCacher::process_local_slot(int index, + SharkValue** addr, + int offset) { + SharkValue *value = *addr; + + // Read the value from the frame if necessary + if (local_slot_needs_read(index, value)) { + *addr = SharkValue::create_generic( + value->type(), + read_value_from_frame( + SharkType::to_stackType(value->basic_type()), + adjusted_offset(value, offset)), + value->zero_checked()); + } +} + +Value* SharkOSREntryCacher::CreateAddressOfOSRBufEntry(int offset, + const Type* type) { + Value *result = builder()->CreateStructGEP(osr_buf(), offset); + if (type != SharkType::intptr_type()) + result = builder()->CreateBitCast(result, PointerType::getUnqual(type)); + return result; +} + +void SharkOSREntryCacher::process_local_slot(int index, + SharkValue** addr, + int offset) { + SharkValue *value = *addr; + + // Read the value from the OSR buffer if necessary + if (local_slot_needs_read(index, value)) { + *addr = SharkValue::create_generic( + value->type(), + builder()->CreateLoad( + CreateAddressOfOSRBufEntry( + adjusted_offset(value, max_locals() - 1 - index), + SharkType::to_stackType(value->basic_type()))), + value->zero_checked()); + } +} + +void SharkDecacher::write_value_to_frame(const Type* type, + Value* value, + int offset) { + builder()->CreateStore(value, stack()->slot_addr(offset, type)); +} + +Value* SharkCacher::read_value_from_frame(const Type* type, int offset) { + return builder()->CreateLoad(stack()->slot_addr(offset, type)); +} diff --git a/hotspot/src/share/vm/shark/sharkCacheDecache.hpp b/hotspot/src/share/vm/shark/sharkCacheDecache.hpp new file mode 100644 index 00000000000..9368746566b --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkCacheDecache.hpp @@ -0,0 +1,417 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// Class hierarchy: +// - SharkStateScanner +// - SharkCacherDecacher +// - SharkDecacher +// - SharkJavaCallDecacher +// - SharkVMCallDecacher +// - SharkTrapDecacher +// - SharkCacher +// - SharkJavaCallCacher +// - SharkVMCallCacher +// - SharkFunctionEntryCacher +// - SharkNormalEntryCacher +// - SharkOSREntryCacher + +class SharkCacherDecacher : public SharkStateScanner { + protected: + SharkCacherDecacher(SharkFunction* function) + : SharkStateScanner(function) {} + + // Helper + protected: + static int adjusted_offset(SharkValue* value, int offset) { + if (value->is_two_word()) + offset--; + return offset; + } +}; + +class SharkDecacher : public SharkCacherDecacher { + protected: + SharkDecacher(SharkFunction* function, int bci) + : SharkCacherDecacher(function), _bci(bci) {} + + private: + int _bci; + + protected: + int bci() const { + return _bci; + } + + private: + int _pc_offset; + OopMap* _oopmap; + GrowableArray* _exparray; + GrowableArray* _monarray; + GrowableArray* _locarray; + + private: + int pc_offset() const { + return _pc_offset; + } + OopMap* oopmap() const { + return _oopmap; + } + GrowableArray* exparray() const { + return _exparray; + } + GrowableArray* monarray() const { + return _monarray; + } + GrowableArray* locarray() const { + return _locarray; + } + + // Callbacks + protected: + void start_frame(); + + void start_stack(int stack_depth); + void process_stack_slot(int index, SharkValue** value, int offset); + + void start_monitors(int num_monitors); + void process_monitor(int index, int box_offset, int obj_offset); + + void process_oop_tmp_slot(llvm::Value** value, int offset); + void process_method_slot(llvm::Value** value, int offset); + void process_pc_slot(int offset); + + void start_locals(); + void process_local_slot(int index, SharkValue** value, int offset); + + void end_frame(); + + // oopmap and debuginfo helpers + private: + static int oopmap_slot_munge(int offset) { + return SharkStack::oopmap_slot_munge(offset); + } + static VMReg slot2reg(int offset) { + return SharkStack::slot2reg(offset); + } + static Location slot2loc(int offset, Location::Type type) { + return Location::new_stk_loc(type, offset * wordSize); + } + static LocationValue* slot2lv(int offset, Location::Type type) { + return new LocationValue(slot2loc(offset, type)); + } + static Location::Type location_type(SharkValue** addr, bool maybe_two_word) { + // low addresses this end + // Type 32-bit 64-bit + // ---------------------------------------------------- + // stack[0] local[3] jobject oop oop + // stack[1] local[2] NULL normal lng + // stack[2] local[1] jlong normal invalid + // stack[3] local[0] jint normal normal + // + // high addresses this end + + SharkValue *value = *addr; + if (value) { + if (value->is_jobject()) + return Location::oop; +#ifdef _LP64 + if (value->is_two_word()) + return Location::invalid; +#endif // _LP64 + return Location::normal; + } + else { + if (maybe_two_word) { + value = *(addr - 1); + if (value && value->is_two_word()) { +#ifdef _LP64 + if (value->is_jlong()) + return Location::lng; + if (value->is_jdouble()) + return Location::dbl; + ShouldNotReachHere(); +#else + return Location::normal; +#endif // _LP64 + } + } + return Location::invalid; + } + } + + // Stack slot helpers + protected: + virtual bool stack_slot_needs_write(int index, SharkValue* value) = 0; + virtual bool stack_slot_needs_oopmap(int index, SharkValue* value) = 0; + virtual bool stack_slot_needs_debuginfo(int index, SharkValue* value) = 0; + + static Location::Type stack_location_type(int index, SharkValue** addr) { + return location_type(addr, *addr == NULL); + } + + // Local slot helpers + protected: + virtual bool local_slot_needs_write(int index, SharkValue* value) = 0; + virtual bool local_slot_needs_oopmap(int index, SharkValue* value) = 0; + virtual bool local_slot_needs_debuginfo(int index, SharkValue* value) = 0; + + static Location::Type local_location_type(int index, SharkValue** addr) { + return location_type(addr, index > 0); + } + + // Writer helper + protected: + void write_value_to_frame(const llvm::Type* type, + llvm::Value* value, + int offset); +}; + +class SharkJavaCallDecacher : public SharkDecacher { + public: + SharkJavaCallDecacher(SharkFunction* function, int bci, ciMethod* callee) + : SharkDecacher(function, bci), _callee(callee) {} + + private: + ciMethod* _callee; + + protected: + ciMethod* callee() const { + return _callee; + } + + // Stack slot helpers + protected: + bool stack_slot_needs_write(int index, SharkValue* value) { + return value && (index < callee()->arg_size() || value->is_jobject()); + } + bool stack_slot_needs_oopmap(int index, SharkValue* value) { + return value && value->is_jobject() && index >= callee()->arg_size(); + } + bool stack_slot_needs_debuginfo(int index, SharkValue* value) { + return index >= callee()->arg_size(); + } + + // Local slot helpers + protected: + bool local_slot_needs_write(int index, SharkValue* value) { + return value && value->is_jobject(); + } + bool local_slot_needs_oopmap(int index, SharkValue* value) { + return value && value->is_jobject(); + } + bool local_slot_needs_debuginfo(int index, SharkValue* value) { + return true; + } +}; + +class SharkVMCallDecacher : public SharkDecacher { + public: + SharkVMCallDecacher(SharkFunction* function, int bci) + : SharkDecacher(function, bci) {} + + // Stack slot helpers + protected: + bool stack_slot_needs_write(int index, SharkValue* value) { + return value && value->is_jobject(); + } + bool stack_slot_needs_oopmap(int index, SharkValue* value) { + return value && value->is_jobject(); + } + bool stack_slot_needs_debuginfo(int index, SharkValue* value) { + return true; + } + + // Local slot helpers + protected: + bool local_slot_needs_write(int index, SharkValue* value) { + return value && value->is_jobject(); + } + bool local_slot_needs_oopmap(int index, SharkValue* value) { + return value && value->is_jobject(); + } + bool local_slot_needs_debuginfo(int index, SharkValue* value) { + return true; + } +}; + +class SharkTrapDecacher : public SharkDecacher { + public: + SharkTrapDecacher(SharkFunction* function, int bci) + : SharkDecacher(function, bci) {} + + // Stack slot helpers + protected: + bool stack_slot_needs_write(int index, SharkValue* value) { + return value != NULL; + } + bool stack_slot_needs_oopmap(int index, SharkValue* value) { + return value && value->is_jobject(); + } + bool stack_slot_needs_debuginfo(int index, SharkValue* value) { + return true; + } + + // Local slot helpers + protected: + bool local_slot_needs_write(int index, SharkValue* value) { + return value != NULL; + } + bool local_slot_needs_oopmap(int index, SharkValue* value) { + return value && value->is_jobject(); + } + bool local_slot_needs_debuginfo(int index, SharkValue* value) { + return true; + } +}; + +class SharkCacher : public SharkCacherDecacher { + protected: + SharkCacher(SharkFunction* function) + : SharkCacherDecacher(function) {} + + // Callbacks + protected: + void process_stack_slot(int index, SharkValue** value, int offset); + + void process_oop_tmp_slot(llvm::Value** value, int offset); + virtual void process_method_slot(llvm::Value** value, int offset); + + virtual void process_local_slot(int index, SharkValue** value, int offset); + + // Stack slot helper + protected: + virtual bool stack_slot_needs_read(int index, SharkValue* value) = 0; + + // Local slot helper + protected: + virtual bool local_slot_needs_read(int index, SharkValue* value) { + return value && value->is_jobject(); + } + + // Writer helper + protected: + llvm::Value* read_value_from_frame(const llvm::Type* type, int offset); +}; + +class SharkJavaCallCacher : public SharkCacher { + public: + SharkJavaCallCacher(SharkFunction* function, ciMethod* callee) + : SharkCacher(function), _callee(callee) {} + + private: + ciMethod* _callee; + + protected: + ciMethod* callee() const { + return _callee; + } + + // Stack slot helper + protected: + bool stack_slot_needs_read(int index, SharkValue* value) { + return value && (index < callee()->return_type()->size() || + value->is_jobject()); + } +}; + +class SharkVMCallCacher : public SharkCacher { + public: + SharkVMCallCacher(SharkFunction* function) + : SharkCacher(function) {} + + // Stack slot helper + protected: + bool stack_slot_needs_read(int index, SharkValue* value) { + return value && value->is_jobject(); + } +}; + +class SharkFunctionEntryCacher : public SharkCacher { + public: + SharkFunctionEntryCacher(SharkFunction* function, llvm::Value* method) + : SharkCacher(function), _method(method) {} + + private: + llvm::Value* _method; + + private: + llvm::Value* method() const { + return _method; + } + + // Method slot callback + protected: + void process_method_slot(llvm::Value** value, int offset); + + // Stack slot helper + protected: + bool stack_slot_needs_read(int index, SharkValue* value) { + ShouldNotReachHere(); // entry block shouldn't have stack + } + + // Local slot helper + protected: + bool local_slot_needs_read(int index, SharkValue* value) { + return value != NULL; + } +}; + +class SharkNormalEntryCacher : public SharkFunctionEntryCacher { + public: + SharkNormalEntryCacher(SharkFunction* function, llvm::Value* method) + : SharkFunctionEntryCacher(function, method) {} +}; + +class SharkOSREntryCacher : public SharkFunctionEntryCacher { + public: + SharkOSREntryCacher(SharkFunction* function, + llvm::Value* method, + llvm::Value* osr_buf) + : SharkFunctionEntryCacher(function, method), + _osr_buf( + builder()->CreateBitCast( + osr_buf, + llvm::PointerType::getUnqual( + llvm::ArrayType::get( + SharkType::intptr_type(), + max_locals() + max_monitors() * 2)))) {} + + private: + llvm::Value* _osr_buf; + + private: + llvm::Value* osr_buf() const { + return _osr_buf; + } + + // Callbacks + protected: + void process_monitor(int index, int box_offset, int obj_offset); + void process_local_slot(int index, SharkValue** value, int offset); + + // Helper + private: + llvm::Value* CreateAddressOfOSRBufEntry(int offset, const llvm::Type* type); +}; diff --git a/hotspot/src/share/vm/shark/sharkCodeBuffer.hpp b/hotspot/src/share/vm/shark/sharkCodeBuffer.hpp new file mode 100644 index 00000000000..6ead2c3ba39 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkCodeBuffer.hpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkCodeBuffer : public StackObj { + public: + SharkCodeBuffer(MacroAssembler* masm) + : _masm(masm), _base_pc(NULL) {} + + private: + MacroAssembler* _masm; + llvm::Value* _base_pc; + + private: + MacroAssembler* masm() const { + return _masm; + } + + public: + llvm::Value* base_pc() const { + return _base_pc; + } + void set_base_pc(llvm::Value* base_pc) { + assert(_base_pc == NULL, "only do this once"); + _base_pc = base_pc; + } + + // Allocate some space in the buffer and return its address. + // This buffer will have been relocated by the time the method + // is installed, so you can't inline the result in code. + public: + void* malloc(size_t size) const { + masm()->align(BytesPerWord); + void *result = masm()->pc(); + masm()->advance(size); + return result; + } + + // Create a unique offset in the buffer. + public: + int create_unique_offset() const { + int offset = masm()->offset(); + masm()->advance(1); + return offset; + } + + // Inline an oop into the buffer and return its offset. + public: + int inline_oop(jobject object) const { + masm()->align(BytesPerWord); + int offset = masm()->offset(); + masm()->store_oop(object); + return offset; + } + + // Inline a block of non-oop data into the buffer and return its offset. + public: + int inline_data(void *src, size_t size) const { + masm()->align(BytesPerWord); + int offset = masm()->offset(); + void *dst = masm()->pc(); + masm()->advance(size); + memcpy(dst, src, size); + return offset; + } +}; diff --git a/hotspot/src/share/vm/shark/sharkCompiler.cpp b/hotspot/src/share/vm/shark/sharkCompiler.cpp new file mode 100644 index 00000000000..d20e3167fa4 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkCompiler.cpp @@ -0,0 +1,340 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkCompiler.cpp.incl" + +#include + +using namespace llvm; + +#if SHARK_LLVM_VERSION >= 27 +namespace { + cl::opt + MCPU("mcpu"); + + cl::list + MAttrs("mattr", + cl::CommaSeparated); +} +#endif + +SharkCompiler::SharkCompiler() + : AbstractCompiler() { + // Create the lock to protect the memory manager and execution engine + _execution_engine_lock = new Monitor(Mutex::leaf, "SharkExecutionEngineLock"); + MutexLocker locker(execution_engine_lock()); + + // Make LLVM safe for multithreading + if (!llvm_start_multithreaded()) + fatal("llvm_start_multithreaded() failed"); + + // Initialize the native target + InitializeNativeTarget(); + + // Create the two contexts which we'll use + _normal_context = new SharkContext("normal"); + _native_context = new SharkContext("native"); + + // Create the memory manager + _memory_manager = new SharkMemoryManager(); + +#if SHARK_LLVM_VERSION >= 27 + // Finetune LLVM for the current host CPU. + StringMap Features; + bool gotCpuFeatures = llvm::sys::getHostCPUFeatures(Features); + std::string cpu("-mcpu=" + llvm::sys::getHostCPUName()); + + std::vector args; + args.push_back(""); // program name + args.push_back(cpu.c_str()); + + std::string mattr("-mattr="); + if(gotCpuFeatures){ + for(StringMap::iterator I = Features.begin(), + E = Features.end(); I != E; ++I){ + if(I->second){ + std::string attr(I->first()); + mattr+="+"+attr+","; + } + } + args.push_back(mattr.c_str()); + } + + args.push_back(0); // terminator + cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]); + + // Create the JIT + std::string ErrorMsg; + + EngineBuilder builder(_normal_context->module()); + builder.setMCPU(MCPU); + builder.setMAttrs(MAttrs); + builder.setJITMemoryManager(memory_manager()); + builder.setEngineKind(EngineKind::JIT); + builder.setErrorStr(&ErrorMsg); + _execution_engine = builder.create(); + + if (!execution_engine()) { + if (!ErrorMsg.empty()) + printf("Error while creating Shark JIT: %s\n",ErrorMsg.c_str()); + else + printf("Unknown error while creating Shark JIT\n"); + exit(1); + } + + execution_engine()->addModule( + _native_context->module()); +#else + _execution_engine = ExecutionEngine::createJIT( + _normal_context->module_provider(), + NULL, memory_manager(), CodeGenOpt::Default); + execution_engine()->addModuleProvider( + _native_context->module_provider()); +#endif + + // All done + mark_initialized(); +} + +void SharkCompiler::initialize() { + ShouldNotCallThis(); +} + +void SharkCompiler::compile_method(ciEnv* env, + ciMethod* target, + int entry_bci) { + assert(is_initialized(), "should be"); + ResourceMark rm; + const char *name = methodname( + target->holder()->name()->as_utf8(), target->name()->as_utf8()); + + // Do the typeflow analysis + ciTypeFlow *flow; + if (entry_bci == InvocationEntryBci) + flow = target->get_flow_analysis(); + else + flow = target->get_osr_flow_analysis(entry_bci); + if (flow->failing()) + return; + if (SharkPrintTypeflowOf != NULL) { + if (!fnmatch(SharkPrintTypeflowOf, name, 0)) + flow->print_on(tty); + } + + // Create the recorders + Arena arena; + env->set_oop_recorder(new OopRecorder(&arena)); + OopMapSet oopmaps; + env->set_debug_info(new DebugInformationRecorder(env->oop_recorder())); + env->debug_info()->set_oopmaps(&oopmaps); + env->set_dependencies(new Dependencies(env)); + + // Create the code buffer and builder + CodeBuffer hscb("Shark", 256 * K, 64 * K); + hscb.initialize_oop_recorder(env->oop_recorder()); + MacroAssembler *masm = new MacroAssembler(&hscb); + SharkCodeBuffer cb(masm); + SharkBuilder builder(&cb); + + // Emit the entry point + SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); + + // Build the LLVM IR for the method + Function *function = SharkFunction::build(env, &builder, flow, name); + + // Generate native code. It's unpleasant that we have to drop into + // the VM to do this -- it blocks safepoints -- but I can't see any + // other way to handle the locking. + { + ThreadInVMfromNative tiv(JavaThread::current()); + generate_native_code(entry, function, name); + } + + // Install the method into the VM + CodeOffsets offsets; + offsets.set_value(CodeOffsets::Deopt, 0); + offsets.set_value(CodeOffsets::Exceptions, 0); + offsets.set_value(CodeOffsets::Verified_Entry, + target->is_static() ? 0 : wordSize); + + ExceptionHandlerTable handler_table; + ImplicitExceptionTable inc_table; + + env->register_method(target, + entry_bci, + &offsets, + 0, + &hscb, + 0, + &oopmaps, + &handler_table, + &inc_table, + this, + env->comp_level(), + false, + false); +} + +nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm, + methodHandle target, + BasicType* arg_types, + BasicType return_type) { + assert(is_initialized(), "should be"); + ResourceMark rm; + const char *name = methodname( + target->klass_name()->as_utf8(), target->name()->as_utf8()); + + // Create the code buffer and builder + SharkCodeBuffer cb(masm); + SharkBuilder builder(&cb); + + // Emit the entry point + SharkEntry *entry = (SharkEntry *) cb.malloc(sizeof(SharkEntry)); + + // Build the LLVM IR for the method + SharkNativeWrapper *wrapper = SharkNativeWrapper::build( + &builder, target, name, arg_types, return_type); + + // Generate native code + generate_native_code(entry, wrapper->function(), name); + + // Return the nmethod for installation in the VM + return nmethod::new_native_nmethod(target, + masm->code(), + 0, + 0, + wrapper->frame_size(), + wrapper->receiver_offset(), + wrapper->lock_offset(), + wrapper->oop_maps()); +} + +void SharkCompiler::generate_native_code(SharkEntry* entry, + Function* function, + const char* name) { + // Print the LLVM bitcode, if requested + if (SharkPrintBitcodeOf != NULL) { + if (!fnmatch(SharkPrintBitcodeOf, name, 0)) + function->dump(); + } + + // Compile to native code + address code = NULL; + context()->add_function(function); + { + MutexLocker locker(execution_engine_lock()); + free_queued_methods(); + + if (SharkPrintAsmOf != NULL) { +#if SHARK_LLVM_VERSION >= 27 +#ifndef NDEBUG + if (!fnmatch(SharkPrintAsmOf, name, 0)) { + llvm::SetCurrentDebugType(X86_ONLY("x86-emitter") NOT_X86("jit")); + llvm::DebugFlag = true; + } + else { + llvm::SetCurrentDebugType(""); + llvm::DebugFlag = false; + } +#endif // !NDEBUG +#else + // NB you need to patch LLVM with http://tinyurl.com/yf3baln for this + std::vector args; + args.push_back(""); // program name + if (!fnmatch(SharkPrintAsmOf, name, 0)) + args.push_back("-debug-only=x86-emitter"); + else + args.push_back("-debug-only=none"); + args.push_back(0); // terminator + cl::ParseCommandLineOptions(args.size() - 1, (char **) &args[0]); +#endif // SHARK_LLVM_VERSION + } + memory_manager()->set_entry_for_function(function, entry); + code = (address) execution_engine()->getPointerToFunction(function); + } + entry->set_entry_point(code); + entry->set_function(function); + entry->set_context(context()); + address code_start = entry->code_start(); + address code_limit = entry->code_limit(); + + // Register generated code for profiling, etc + if (JvmtiExport::should_post_dynamic_code_generated()) + JvmtiExport::post_dynamic_code_generated(name, code_start, code_limit); + + // Print debug information, if requested + if (SharkTraceInstalls) { + tty->print_cr( + " [%p-%p): %s (%d bytes code)", + code_start, code_limit, name, code_limit - code_start); + } +} + +void SharkCompiler::free_compiled_method(address code) { + // This method may only be called when the VM is at a safepoint. + // All _thread_in_vm threads will be waiting for the safepoint to + // finish with the exception of the VM thread, so we can consider + // ourself the owner of the execution engine lock even though we + // can't actually acquire it at this time. + assert(Thread::current()->is_VM_thread(), "must be called by VM thread"); + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + + SharkEntry *entry = (SharkEntry *) code; + entry->context()->push_to_free_queue(entry->function()); +} + +void SharkCompiler::free_queued_methods() { + // The free queue is protected by the execution engine lock + assert(execution_engine_lock()->owned_by_self(), "should be"); + + while (true) { + Function *function = context()->pop_from_free_queue(); + if (function == NULL) + break; + + execution_engine()->freeMachineCodeForFunction(function); + function->eraseFromParent(); + } +} + +const char* SharkCompiler::methodname(const char* klass, const char* method) { + char *buf = NEW_RESOURCE_ARRAY(char, strlen(klass) + 2 + strlen(method) + 1); + + char *dst = buf; + for (const char *c = klass; *c; c++) { + if (*c == '/') + *(dst++) = '.'; + else + *(dst++) = *c; + } + *(dst++) = ':'; + *(dst++) = ':'; + for (const char *c = method; *c; c++) { + *(dst++) = *c; + } + *(dst++) = '\0'; + return buf; +} diff --git a/hotspot/src/share/vm/shark/sharkCompiler.hpp b/hotspot/src/share/vm/shark/sharkCompiler.hpp new file mode 100644 index 00000000000..ddac631527b --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkCompiler.hpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkContext; + +class SharkCompiler : public AbstractCompiler { + public: + // Creation + SharkCompiler(); + + // Name of this compiler + const char *name() { return "shark"; } + + // Missing feature tests + bool supports_native() { return true; } + bool supports_osr() { return true; } + + // Customization + bool needs_adapters() { return false; } + bool needs_stubs() { return false; } + + // Initialization + void initialize(); + + // Compile a normal (bytecode) method and install it in the VM + void compile_method(ciEnv* env, ciMethod* target, int entry_bci); + + // Generate a wrapper for a native (JNI) method + nmethod* generate_native_wrapper(MacroAssembler* masm, + methodHandle target, + BasicType* arg_types, + BasicType return_type); + + // Free compiled methods (and native wrappers) + void free_compiled_method(address code); + + // Each thread generating IR needs its own context. The normal + // context is used for bytecode methods, and is protected from + // multiple simultaneous accesses by being restricted to the + // compiler thread. The native context is used for JNI methods, + // and is protected from multiple simultaneous accesses by the + // adapter handler library lock. + private: + SharkContext* _normal_context; + SharkContext* _native_context; + + public: + SharkContext* context() const { + if (JavaThread::current()->is_Compiler_thread()) { + return _normal_context; + } + else { + assert(AdapterHandlerLibrary_lock->owned_by_self(), "should be"); + return _native_context; + } + } + + // The LLVM execution engine is the JIT we use to generate native + // code. It is thread safe, but we need to protect it with a lock + // of our own because otherwise LLVM's lock and HotSpot's locks + // interleave and deadlock. The SharkMemoryManager is not thread + // safe, and is protected by the same lock as the execution engine. + private: + Monitor* _execution_engine_lock; + SharkMemoryManager* _memory_manager; + llvm::ExecutionEngine* _execution_engine; + + private: + Monitor* execution_engine_lock() const { + return _execution_engine_lock; + } + SharkMemoryManager* memory_manager() const { + assert(execution_engine_lock()->owned_by_self(), "should be"); + return _memory_manager; + } + llvm::ExecutionEngine* execution_engine() const { + assert(execution_engine_lock()->owned_by_self(), "should be"); + return _execution_engine; + } + + // Global access + public: + static SharkCompiler* compiler() { + AbstractCompiler *compiler = + CompileBroker::compiler(CompLevel_fast_compile); + assert(compiler->is_shark() && compiler->is_initialized(), "should be"); + return (SharkCompiler *) compiler; + } + + // Helpers + private: + static const char* methodname(const char* klass, const char* method); + void generate_native_code(SharkEntry* entry, + llvm::Function* function, + const char* name); + void free_queued_methods(); +}; diff --git a/hotspot/src/share/vm/shark/sharkConstant.cpp b/hotspot/src/share/vm/shark/sharkConstant.cpp new file mode 100644 index 00000000000..439632bd8e3 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkConstant.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkConstant.cpp.incl" + +using namespace llvm; + +SharkConstant* SharkConstant::for_ldc(ciBytecodeStream *iter) { + ciConstant constant = iter->get_constant(); + ciType *type = NULL; + if (constant.basic_type() == T_OBJECT) { + ciEnv *env = ciEnv::current(); + if (constant.as_object()->is_klass()) + type = env->Class_klass(); + else + type = env->String_klass(); + } + return new SharkConstant(constant, type); +} + +SharkConstant* SharkConstant::for_field(ciBytecodeStream *iter) { + bool will_link; + ciField *field = iter->get_field(will_link); + assert(will_link, "typeflow responsibility"); + + return new SharkConstant(field->constant_value(), field->type()); +} + +SharkConstant::SharkConstant(ciConstant constant, ciType *type) { + SharkValue *value = NULL; + + switch (constant.basic_type()) { + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: + value = SharkValue::jint_constant(constant.as_int()); + break; + + case T_LONG: + value = SharkValue::jlong_constant(constant.as_long()); + break; + + case T_FLOAT: + value = SharkValue::jfloat_constant(constant.as_float()); + break; + + case T_DOUBLE: + value = SharkValue::jdouble_constant(constant.as_double()); + break; + + case T_OBJECT: + case T_ARRAY: + break; + + case T_ILLEGAL: + // out of memory + _is_loaded = false; + return; + + default: + tty->print_cr("Unhandled type %s", type2name(constant.basic_type())); + ShouldNotReachHere(); + } + + // Handle primitive types. We create SharkValues for these + // now; doing so doesn't emit any code, and it allows us to + // delegate a bunch of stuff to the SharkValue code. + if (value) { + _value = value; + _is_loaded = true; + _is_nonzero = value->zero_checked(); + _is_two_word = value->is_two_word(); + return; + } + + // Handle reference types. This is tricky because some + // ciObjects are psuedo-objects that refer to oops which + // have yet to be created. We need to spot the unloaded + // objects (which differ between ldc* and get*, thanks!) + ciObject *object = constant.as_object(); + assert(type != NULL, "shouldn't be"); + if (object->is_klass()) { + // The constant returned for a klass is the ciKlass + // for the entry, but we want the java_mirror. + ciKlass *klass = object->as_klass(); + if (!klass->is_loaded()) { + _is_loaded = false; + return; + } + object = klass->java_mirror(); + } + if (object->is_null_object() || !object->can_be_constant()) { + _is_loaded = false; + return; + } + + _value = NULL; + _object = object; + _type = type; + _is_loaded = true; + _is_nonzero = true; + _is_two_word = false; +} diff --git a/hotspot/src/share/vm/shark/sharkConstant.hpp b/hotspot/src/share/vm/shark/sharkConstant.hpp new file mode 100644 index 00000000000..83b7374269e --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkConstant.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkConstant : public ResourceObj { + public: + static SharkConstant* for_ldc(ciBytecodeStream* iter); + static SharkConstant* for_field(ciBytecodeStream* iter); + + private: + SharkConstant(ciConstant constant, ciType* type); + + private: + SharkValue* _value; + ciObject* _object; + ciType* _type; + bool _is_loaded; + bool _is_nonzero; + bool _is_two_word; + + public: + bool is_loaded() const { + return _is_loaded; + } + bool is_nonzero() const { + assert(is_loaded(), "should be"); + return _is_nonzero; + } + bool is_two_word() const { + assert(is_loaded(), "should be"); + return _is_two_word; + } + + public: + SharkValue* value(SharkBuilder* builder) { + assert(is_loaded(), "should be"); + if (_value == NULL) { + _value = SharkValue::create_generic( + _type, builder->CreateInlineOop(_object), _is_nonzero); + } + return _value; + } +}; diff --git a/hotspot/src/share/vm/shark/sharkContext.cpp b/hotspot/src/share/vm/shark/sharkContext.cpp new file mode 100644 index 00000000000..052199fcb82 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkContext.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkContext.cpp.incl" + +using namespace llvm; + +SharkContext::SharkContext(const char* name) + : LLVMContext(), + _free_queue(NULL) { + // Create a module to build our functions into + _module = new Module(name, *this); + + // Create basic types + _void_type = Type::getVoidTy(*this); + _bit_type = Type::getInt1Ty(*this); + _jbyte_type = Type::getInt8Ty(*this); + _jshort_type = Type::getInt16Ty(*this); + _jint_type = Type::getInt32Ty(*this); + _jlong_type = Type::getInt64Ty(*this); + _jfloat_type = Type::getFloatTy(*this); + _jdouble_type = Type::getDoubleTy(*this); + + // Create compound types + _itableOffsetEntry_type = PointerType::getUnqual( + ArrayType::get(jbyte_type(), itableOffsetEntry::size() * wordSize)); + + _klass_type = PointerType::getUnqual( + ArrayType::get(jbyte_type(), sizeof(Klass))); + + _jniEnv_type = PointerType::getUnqual( + ArrayType::get(jbyte_type(), sizeof(JNIEnv))); + + _jniHandleBlock_type = PointerType::getUnqual( + ArrayType::get(jbyte_type(), sizeof(JNIHandleBlock))); + + _methodOop_type = PointerType::getUnqual( + ArrayType::get(jbyte_type(), sizeof(methodOopDesc))); + + _monitor_type = ArrayType::get( + jbyte_type(), frame::interpreter_frame_monitor_size() * wordSize); + + _oop_type = PointerType::getUnqual( + ArrayType::get(jbyte_type(), sizeof(oopDesc))); + + _thread_type = PointerType::getUnqual( + ArrayType::get(jbyte_type(), sizeof(JavaThread))); + + _zeroStack_type = PointerType::getUnqual( + ArrayType::get(jbyte_type(), sizeof(ZeroStack))); + + std::vector params; + params.push_back(methodOop_type()); + params.push_back(intptr_type()); + params.push_back(thread_type()); + _entry_point_type = FunctionType::get(jint_type(), params, false); + + params.clear(); + params.push_back(methodOop_type()); + params.push_back(PointerType::getUnqual(jbyte_type())); + params.push_back(intptr_type()); + params.push_back(thread_type()); + _osr_entry_point_type = FunctionType::get(jint_type(), params, false); + + // Create mappings + for (int i = 0; i < T_CONFLICT; i++) { + switch (i) { + case T_BOOLEAN: + _to_stackType[i] = jint_type(); + _to_arrayType[i] = jbyte_type(); + break; + + case T_BYTE: + _to_stackType[i] = jint_type(); + _to_arrayType[i] = jbyte_type(); + break; + + case T_CHAR: + _to_stackType[i] = jint_type(); + _to_arrayType[i] = jshort_type(); + break; + + case T_SHORT: + _to_stackType[i] = jint_type(); + _to_arrayType[i] = jshort_type(); + break; + + case T_INT: + _to_stackType[i] = jint_type(); + _to_arrayType[i] = jint_type(); + break; + + case T_LONG: + _to_stackType[i] = jlong_type(); + _to_arrayType[i] = jlong_type(); + break; + + case T_FLOAT: + _to_stackType[i] = jfloat_type(); + _to_arrayType[i] = jfloat_type(); + break; + + case T_DOUBLE: + _to_stackType[i] = jdouble_type(); + _to_arrayType[i] = jdouble_type(); + break; + + case T_OBJECT: + case T_ARRAY: + _to_stackType[i] = oop_type(); + _to_arrayType[i] = oop_type(); + break; + + case T_ADDRESS: + _to_stackType[i] = intptr_type(); + _to_arrayType[i] = NULL; + break; + + default: + _to_stackType[i] = NULL; + _to_arrayType[i] = NULL; + } + } +} + +class SharkFreeQueueItem : public CHeapObj { + public: + SharkFreeQueueItem(llvm::Function* function, SharkFreeQueueItem *next) + : _function(function), _next(next) {} + + private: + llvm::Function* _function; + SharkFreeQueueItem* _next; + + public: + llvm::Function* function() const { + return _function; + } + SharkFreeQueueItem* next() const { + return _next; + } +}; + +void SharkContext::push_to_free_queue(Function* function) { + _free_queue = new SharkFreeQueueItem(function, _free_queue); +} + +Function* SharkContext::pop_from_free_queue() { + if (_free_queue == NULL) + return NULL; + + SharkFreeQueueItem *item = _free_queue; + Function *function = item->function(); + _free_queue = item->next(); + delete item; + return function; +} diff --git a/hotspot/src/share/vm/shark/sharkContext.hpp b/hotspot/src/share/vm/shark/sharkContext.hpp new file mode 100644 index 00000000000..15f294943e6 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkContext.hpp @@ -0,0 +1,187 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// The LLVMContext class allows multiple instances of LLVM to operate +// independently of each other in a multithreaded context. We extend +// this here to store things in Shark that are LLVMContext-specific. + +class SharkFreeQueueItem; + +class SharkContext : public llvm::LLVMContext { + public: + SharkContext(const char* name); + + private: + llvm::Module* _module; + +#if SHARK_LLVM_VERSION >= 27 + public: +#else + private: +#endif + llvm::Module* module() const { + return _module; + } + + // Get this thread's SharkContext + public: + static SharkContext& current() { + return *SharkCompiler::compiler()->context(); + } + + // Module accessors + public: +#if SHARK_LLVM_VERSION < 27 + llvm::ModuleProvider* module_provider() const { + return new llvm::ExistingModuleProvider(module()); + } +#endif + void add_function(llvm::Function* function) const { + module()->getFunctionList().push_back(function); + } + llvm::Constant* get_external(const char* name, + const llvm::FunctionType* sig) { + return module()->getOrInsertFunction(name, sig); + } + + // Basic types + private: + const llvm::Type* _void_type; + const llvm::IntegerType* _bit_type; + const llvm::IntegerType* _jbyte_type; + const llvm::IntegerType* _jshort_type; + const llvm::IntegerType* _jint_type; + const llvm::IntegerType* _jlong_type; + const llvm::Type* _jfloat_type; + const llvm::Type* _jdouble_type; + + public: + const llvm::Type* void_type() const { + return _void_type; + } + const llvm::IntegerType* bit_type() const { + return _bit_type; + } + const llvm::IntegerType* jbyte_type() const { + return _jbyte_type; + } + const llvm::IntegerType* jshort_type() const { + return _jshort_type; + } + const llvm::IntegerType* jint_type() const { + return _jint_type; + } + const llvm::IntegerType* jlong_type() const { + return _jlong_type; + } + const llvm::Type* jfloat_type() const { + return _jfloat_type; + } + const llvm::Type* jdouble_type() const { + return _jdouble_type; + } + const llvm::IntegerType* intptr_type() const { + return LP64_ONLY(jlong_type()) NOT_LP64(jint_type()); + } + + // Compound types + private: + const llvm::PointerType* _itableOffsetEntry_type; + const llvm::PointerType* _jniEnv_type; + const llvm::PointerType* _jniHandleBlock_type; + const llvm::PointerType* _klass_type; + const llvm::PointerType* _methodOop_type; + const llvm::ArrayType* _monitor_type; + const llvm::PointerType* _oop_type; + const llvm::PointerType* _thread_type; + const llvm::PointerType* _zeroStack_type; + const llvm::FunctionType* _entry_point_type; + const llvm::FunctionType* _osr_entry_point_type; + + public: + const llvm::PointerType* itableOffsetEntry_type() const { + return _itableOffsetEntry_type; + } + const llvm::PointerType* jniEnv_type() const { + return _jniEnv_type; + } + const llvm::PointerType* jniHandleBlock_type() const { + return _jniHandleBlock_type; + } + const llvm::PointerType* klass_type() const { + return _klass_type; + } + const llvm::PointerType* methodOop_type() const { + return _methodOop_type; + } + const llvm::ArrayType* monitor_type() const { + return _monitor_type; + } + const llvm::PointerType* oop_type() const { + return _oop_type; + } + const llvm::PointerType* thread_type() const { + return _thread_type; + } + const llvm::PointerType* zeroStack_type() const { + return _zeroStack_type; + } + const llvm::FunctionType* entry_point_type() const { + return _entry_point_type; + } + const llvm::FunctionType* osr_entry_point_type() const { + return _osr_entry_point_type; + } + + // Mappings + private: + const llvm::Type* _to_stackType[T_CONFLICT]; + const llvm::Type* _to_arrayType[T_CONFLICT]; + + private: + const llvm::Type* map_type(const llvm::Type* const* table, + BasicType type) const { + assert(type >= 0 && type < T_CONFLICT, "unhandled type"); + const llvm::Type* result = table[type]; + assert(type != NULL, "unhandled type"); + return result; + } + + public: + const llvm::Type* to_stackType(BasicType type) const { + return map_type(_to_stackType, type); + } + const llvm::Type* to_arrayType(BasicType type) const { + return map_type(_to_arrayType, type); + } + + // Functions queued for freeing + private: + SharkFreeQueueItem* _free_queue; + + public: + void push_to_free_queue(llvm::Function* function); + llvm::Function* pop_from_free_queue(); +}; diff --git a/hotspot/src/share/vm/shark/sharkEntry.hpp b/hotspot/src/share/vm/shark/sharkEntry.hpp new file mode 100644 index 00000000000..dc2226028f8 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkEntry.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkContext; + +class SharkEntry : public ZeroEntry { + private: + address _code_limit; + SharkContext* _context; + llvm::Function* _function; + + public: + address code_start() const { + return entry_point(); + } + address code_limit() const { + return _code_limit; + } + SharkContext* context() const { + return _context; + } + llvm::Function* function() const { + return _function; + } + + public: + void set_code_limit(address code_limit) { + _code_limit = code_limit; + } + void set_context(SharkContext* context) { + _context = context; + } + void set_function(llvm::Function* function) { + _function = function; + } +}; diff --git a/hotspot/src/share/vm/shark/sharkFunction.cpp b/hotspot/src/share/vm/shark/sharkFunction.cpp new file mode 100644 index 00000000000..46f8d91c6d0 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkFunction.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkFunction.cpp.incl" + +using namespace llvm; + +void SharkFunction::initialize(const char *name) { + // Create the function + _function = Function::Create( + entry_point_type(), + GlobalVariable::InternalLinkage, + name); + + // Get our arguments + Function::arg_iterator ai = function()->arg_begin(); + Argument *method = ai++; + method->setName("method"); + Argument *osr_buf = NULL; + if (is_osr()) { + osr_buf = ai++; + osr_buf->setName("osr_buf"); + } + Argument *base_pc = ai++; + base_pc->setName("base_pc"); + code_buffer()->set_base_pc(base_pc); + Argument *thread = ai++; + thread->setName("thread"); + set_thread(thread); + + // Create the list of blocks + set_block_insertion_point(NULL); + _blocks = NEW_RESOURCE_ARRAY(SharkTopLevelBlock*, block_count()); + for (int i = 0; i < block_count(); i++) { + ciTypeFlow::Block *b = flow()->pre_order_at(i); + + // Work around a bug in pre_order_at() that does not return + // the correct pre-ordering. If pre_order_at() were correct + // this line could simply be: + // _blocks[i] = new SharkTopLevelBlock(this, b); + _blocks[b->pre_order()] = new SharkTopLevelBlock(this, b); + } + + // Walk the tree from the start block to determine which + // blocks are entered and which blocks require phis + SharkTopLevelBlock *start_block = block(flow()->start_block_num()); + assert(start_block->start() == flow()->start_bci(), "blocks out of order"); + start_block->enter(); + + // Initialize all entered blocks + for (int i = 0; i < block_count(); i++) { + if (block(i)->entered()) + block(i)->initialize(); + } + + // Create and push our stack frame + set_block_insertion_point(&function()->front()); + builder()->SetInsertPoint(CreateBlock()); + _stack = SharkStack::CreateBuildAndPushFrame(this, method); + + // Create the entry state + SharkState *entry_state; + if (is_osr()) { + entry_state = new SharkOSREntryState(start_block, method, osr_buf); + + // Free the OSR buffer + builder()->CreateCall(builder()->osr_migration_end(), osr_buf); + } + else { + entry_state = new SharkNormalEntryState(start_block, method); + + // Lock if necessary + if (is_synchronized()) { + SharkTopLevelBlock *locker = + new SharkTopLevelBlock(this, start_block->ciblock()); + locker->add_incoming(entry_state); + + set_block_insertion_point(start_block->entry_block()); + locker->acquire_method_lock(); + + entry_state = locker->current_state(); + } + } + + // Transition into the method proper + start_block->add_incoming(entry_state); + builder()->CreateBr(start_block->entry_block()); + + // Parse the blocks + for (int i = 0; i < block_count(); i++) { + if (!block(i)->entered()) + continue; + + if (i + 1 < block_count()) + set_block_insertion_point(block(i + 1)->entry_block()); + else + set_block_insertion_point(NULL); + + block(i)->emit_IR(); + } + do_deferred_zero_checks(); +} + +class DeferredZeroCheck : public SharkTargetInvariants { + public: + DeferredZeroCheck(SharkTopLevelBlock* block, SharkValue* value) + : SharkTargetInvariants(block), + _block(block), + _value(value), + _bci(block->bci()), + _state(block->current_state()->copy()), + _check_block(builder()->GetInsertBlock()), + _continue_block(function()->CreateBlock("not_zero")) { + builder()->SetInsertPoint(continue_block()); + } + + private: + SharkTopLevelBlock* _block; + SharkValue* _value; + int _bci; + SharkState* _state; + BasicBlock* _check_block; + BasicBlock* _continue_block; + + public: + SharkTopLevelBlock* block() const { + return _block; + } + SharkValue* value() const { + return _value; + } + int bci() const { + return _bci; + } + SharkState* state() const { + return _state; + } + BasicBlock* check_block() const { + return _check_block; + } + BasicBlock* continue_block() const { + return _continue_block; + } + + public: + SharkFunction* function() const { + return block()->function(); + } + + public: + void process() const { + builder()->SetInsertPoint(check_block()); + block()->do_deferred_zero_check(value(), bci(), state(), continue_block()); + } +}; + +void SharkFunction::add_deferred_zero_check(SharkTopLevelBlock* block, + SharkValue* value) { + deferred_zero_checks()->append(new DeferredZeroCheck(block, value)); +} + +void SharkFunction::do_deferred_zero_checks() { + for (int i = 0; i < deferred_zero_checks()->length(); i++) + deferred_zero_checks()->at(i)->process(); +} diff --git a/hotspot/src/share/vm/shark/sharkFunction.hpp b/hotspot/src/share/vm/shark/sharkFunction.hpp new file mode 100644 index 00000000000..bb4c3b66cc3 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkFunction.hpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkTopLevelBlock; +class DeferredZeroCheck; + +class SharkFunction : public SharkTargetInvariants { + friend class SharkStackWithNormalFrame; + + public: + static llvm::Function* build(ciEnv* env, + SharkBuilder* builder, + ciTypeFlow* flow, + const char* name) { + SharkFunction function(env, builder, flow, name); + return function.function(); + } + + private: + SharkFunction(ciEnv* env, + SharkBuilder* builder, + ciTypeFlow* flow, + const char* name) + : SharkTargetInvariants(env, builder, flow) { initialize(name); } + + private: + void initialize(const char* name); + + private: + llvm::Function* _function; + SharkTopLevelBlock** _blocks; + GrowableArray _deferred_zero_checks; + SharkStack* _stack; + + public: + llvm::Function* function() const { + return _function; + } + int block_count() const { + return flow()->block_count(); + } + SharkTopLevelBlock* block(int i) const { + assert(i < block_count(), "should be"); + return _blocks[i]; + } + GrowableArray* deferred_zero_checks() { + return &_deferred_zero_checks; + } + SharkStack* stack() const { + return _stack; + } + + // On-stack replacement + private: + bool is_osr() const { + return flow()->is_osr_flow(); + } + const llvm::FunctionType* entry_point_type() const { + if (is_osr()) + return SharkType::osr_entry_point_type(); + else + return SharkType::entry_point_type(); + } + + // Block management + private: + llvm::BasicBlock* _block_insertion_point; + + void set_block_insertion_point(llvm::BasicBlock* block_insertion_point) { + _block_insertion_point = block_insertion_point; + } + llvm::BasicBlock* block_insertion_point() const { + return _block_insertion_point; + } + + public: + llvm::BasicBlock* CreateBlock(const char* name = "") const { + return llvm::BasicBlock::Create( + SharkContext::current(), name, function(), block_insertion_point()); + } + + // Deferred zero checks + public: + void add_deferred_zero_check(SharkTopLevelBlock* block, + SharkValue* value); + + private: + void do_deferred_zero_checks(); +}; diff --git a/hotspot/src/share/vm/shark/sharkInliner.cpp b/hotspot/src/share/vm/shark/sharkInliner.cpp new file mode 100644 index 00000000000..a7599e3fe81 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkInliner.cpp @@ -0,0 +1,749 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkInliner.cpp.incl" + +using namespace llvm; + +class SharkInlineBlock : public SharkBlock { + public: + SharkInlineBlock(ciMethod* target, SharkState* state) + : SharkBlock(state, target), + _outer_state(state), + _entry_state(new SharkState(this)) { + for (int i = target->max_locals() - 1; i >= 0; i--) { + SharkValue *value = NULL; + if (i < target->arg_size()) + value = outer_state()->pop(); + entry_state()->set_local(i, value); + } + } + + private: + SharkState* _outer_state; + SharkState* _entry_state; + + private: + SharkState* outer_state() { + return _outer_state; + } + SharkState* entry_state() { + return _entry_state; + } + + public: + void emit_IR() { + parse_bytecode(0, target()->code_size()); + } + + private: + void do_return(BasicType type) { + if (type != T_VOID) { + SharkValue *result = pop_result(type); + outer_state()->push(result); + if (result->is_two_word()) + outer_state()->push(NULL); + } + } +}; + +class SharkInlinerHelper : public StackObj { + public: + SharkInlinerHelper(ciMethod* target, SharkState* entry_state) + : _target(target), + _entry_state(entry_state), + _iter(target) {} + + private: + ciBytecodeStream _iter; + SharkState* _entry_state; + ciMethod* _target; + + public: + ciBytecodeStream* iter() { + return &_iter; + } + SharkState* entry_state() const { + return _entry_state; + } + ciMethod* target() const { + return _target; + } + + public: + Bytecodes::Code bc() { + return iter()->cur_bc(); + } + int max_locals() const { + return target()->max_locals(); + } + int max_stack() const { + return target()->max_stack(); + } + + // Inlinability check + public: + bool is_inlinable(); + + private: + void initialize_for_check(); + + bool do_getstatic() { + return do_field_access(true, false); + } + bool do_getfield() { + return do_field_access(true, true); + } + bool do_putfield() { + return do_field_access(false, true); + } + bool do_field_access(bool is_get, bool is_field); + + // Local variables for inlinability check + private: + bool* _locals; + + public: + bool* local_addr(int index) const { + assert(index >= 0 && index < max_locals(), "bad local variable index"); + return &_locals[index]; + } + bool local(int index) const { + return *local_addr(index); + } + void set_local(int index, bool value) { + *local_addr(index) = value; + } + + // Expression stack for inlinability check + private: + bool* _stack; + bool* _sp; + + public: + int stack_depth() const { + return _sp - _stack; + } + bool* stack_addr(int slot) const { + assert(slot >= 0 && slot < stack_depth(), "bad stack slot"); + return &_sp[-(slot + 1)]; + } + void push(bool value) { + assert(stack_depth() < max_stack(), "stack overrun"); + *(_sp++) = value; + } + bool pop() { + assert(stack_depth() > 0, "stack underrun"); + return *(--_sp); + } + + // Methods for two-word locals + public: + void push_pair_local(int index) { + push(local(index)); + push(local(index + 1)); + } + void pop_pair_local(int index) { + set_local(index + 1, pop()); + set_local(index, pop()); + } + + // Code generation + public: + void do_inline() { + (new SharkInlineBlock(target(), entry_state()))->emit_IR(); + } +}; + +// Quick checks so we can bail out before doing too much +bool SharkInliner::may_be_inlinable(ciMethod *target) { + // We can't inline native methods + if (target->is_native()) + return false; + + // Not much point inlining abstract ones, and in any + // case we'd need a stack frame to throw the exception + if (target->is_abstract()) + return false; + + // Don't inline anything huge + if (target->code_size() > SharkMaxInlineSize) + return false; + + // Monitors aren't allowed without a frame to put them in + if (target->is_synchronized() || target->has_monitor_bytecodes()) + return false; + + // We don't do control flow + if (target->has_exception_handlers() || target->has_jsrs()) + return false; + + // Don't try to inline constructors, as they must + // eventually call Object. which we can't inline. + // Note that this catches too, but why would + // we be compiling that? + if (target->is_initializer()) + return false; + + // Mustn't inline Object. + // Should be caught by the above, but just in case... + if (target->intrinsic_id() == vmIntrinsics::_Object_init) + return false; + + return true; +} + +// Full-on detailed check, for methods that pass the quick checks +// Inlined methods have no stack frame, so we can't do anything +// that would require one. This means no safepoints (and hence +// no loops) and no VM calls. No VM calls means, amongst other +// things, that no exceptions can be created, which means no null +// checks or divide-by-zero checks are allowed. The lack of null +// checks in particular would eliminate practically everything, +// but we can get around that restriction by relying on the zero- +// check eliminator to strip the checks. To do that, we need to +// walk through the method, tracking which values are and are not +// zero-checked. +bool SharkInlinerHelper::is_inlinable() { + ResourceMark rm; + initialize_for_check(); + + SharkConstant *sc; + bool a, b, c, d; + + iter()->reset_to_bci(0); + while (iter()->next() != ciBytecodeStream::EOBC()) { + switch (bc()) { + case Bytecodes::_nop: + break; + + case Bytecodes::_aconst_null: + push(false); + break; + + case Bytecodes::_iconst_0: + push(false); + break; + case Bytecodes::_iconst_m1: + case Bytecodes::_iconst_1: + case Bytecodes::_iconst_2: + case Bytecodes::_iconst_3: + case Bytecodes::_iconst_4: + case Bytecodes::_iconst_5: + push(true); + break; + + case Bytecodes::_lconst_0: + push(false); + push(false); + break; + case Bytecodes::_lconst_1: + push(true); + push(false); + break; + + case Bytecodes::_fconst_0: + case Bytecodes::_fconst_1: + case Bytecodes::_fconst_2: + push(false); + break; + + case Bytecodes::_dconst_0: + case Bytecodes::_dconst_1: + push(false); + push(false); + break; + + case Bytecodes::_bipush: + push(iter()->get_constant_u1() != 0); + break; + case Bytecodes::_sipush: + push(iter()->get_constant_u2() != 0); + break; + + case Bytecodes::_ldc: + case Bytecodes::_ldc_w: + case Bytecodes::_ldc2_w: + sc = SharkConstant::for_ldc(iter()); + if (!sc->is_loaded()) + return false; + push(sc->is_nonzero()); + if (sc->is_two_word()) + push(false); + break; + + case Bytecodes::_iload_0: + case Bytecodes::_fload_0: + case Bytecodes::_aload_0: + push(local(0)); + break; + case Bytecodes::_lload_0: + case Bytecodes::_dload_0: + push_pair_local(0); + break; + + case Bytecodes::_iload_1: + case Bytecodes::_fload_1: + case Bytecodes::_aload_1: + push(local(1)); + break; + case Bytecodes::_lload_1: + case Bytecodes::_dload_1: + push_pair_local(1); + break; + + case Bytecodes::_iload_2: + case Bytecodes::_fload_2: + case Bytecodes::_aload_2: + push(local(2)); + break; + case Bytecodes::_lload_2: + case Bytecodes::_dload_2: + push_pair_local(2); + break; + + case Bytecodes::_iload_3: + case Bytecodes::_fload_3: + case Bytecodes::_aload_3: + push(local(3)); + break; + case Bytecodes::_lload_3: + case Bytecodes::_dload_3: + push_pair_local(3); + break; + + case Bytecodes::_iload: + case Bytecodes::_fload: + case Bytecodes::_aload: + push(local(iter()->get_index())); + break; + case Bytecodes::_lload: + case Bytecodes::_dload: + push_pair_local(iter()->get_index()); + break; + + case Bytecodes::_istore_0: + case Bytecodes::_fstore_0: + case Bytecodes::_astore_0: + set_local(0, pop()); + break; + case Bytecodes::_lstore_0: + case Bytecodes::_dstore_0: + pop_pair_local(0); + break; + + case Bytecodes::_istore_1: + case Bytecodes::_fstore_1: + case Bytecodes::_astore_1: + set_local(1, pop()); + break; + case Bytecodes::_lstore_1: + case Bytecodes::_dstore_1: + pop_pair_local(1); + break; + + case Bytecodes::_istore_2: + case Bytecodes::_fstore_2: + case Bytecodes::_astore_2: + set_local(2, pop()); + break; + case Bytecodes::_lstore_2: + case Bytecodes::_dstore_2: + pop_pair_local(2); + break; + + case Bytecodes::_istore_3: + case Bytecodes::_fstore_3: + case Bytecodes::_astore_3: + set_local(3, pop()); + break; + case Bytecodes::_lstore_3: + case Bytecodes::_dstore_3: + pop_pair_local(3); + break; + + case Bytecodes::_istore: + case Bytecodes::_fstore: + case Bytecodes::_astore: + set_local(iter()->get_index(), pop()); + break; + case Bytecodes::_lstore: + case Bytecodes::_dstore: + pop_pair_local(iter()->get_index()); + break; + + case Bytecodes::_pop: + pop(); + break; + case Bytecodes::_pop2: + pop(); + pop(); + break; + case Bytecodes::_swap: + a = pop(); + b = pop(); + push(a); + push(b); + break; + case Bytecodes::_dup: + a = pop(); + push(a); + push(a); + break; + case Bytecodes::_dup_x1: + a = pop(); + b = pop(); + push(a); + push(b); + push(a); + break; + case Bytecodes::_dup_x2: + a = pop(); + b = pop(); + c = pop(); + push(a); + push(c); + push(b); + push(a); + break; + case Bytecodes::_dup2: + a = pop(); + b = pop(); + push(b); + push(a); + push(b); + push(a); + break; + case Bytecodes::_dup2_x1: + a = pop(); + b = pop(); + c = pop(); + push(b); + push(a); + push(c); + push(b); + push(a); + break; + case Bytecodes::_dup2_x2: + a = pop(); + b = pop(); + c = pop(); + d = pop(); + push(b); + push(a); + push(d); + push(c); + push(b); + push(a); + break; + + case Bytecodes::_getfield: + if (!do_getfield()) + return false; + break; + case Bytecodes::_getstatic: + if (!do_getstatic()) + return false; + break; + case Bytecodes::_putfield: + if (!do_putfield()) + return false; + break; + + case Bytecodes::_iadd: + case Bytecodes::_isub: + case Bytecodes::_imul: + case Bytecodes::_iand: + case Bytecodes::_ixor: + case Bytecodes::_ishl: + case Bytecodes::_ishr: + case Bytecodes::_iushr: + pop(); + pop(); + push(false); + break; + case Bytecodes::_ior: + a = pop(); + b = pop(); + push(a && b); + break; + case Bytecodes::_idiv: + case Bytecodes::_irem: + if (!pop()) + return false; + pop(); + push(false); + break; + case Bytecodes::_ineg: + break; + + case Bytecodes::_ladd: + case Bytecodes::_lsub: + case Bytecodes::_lmul: + case Bytecodes::_land: + case Bytecodes::_lxor: + pop(); + pop(); + pop(); + pop(); + push(false); + push(false); + break; + case Bytecodes::_lor: + a = pop(); + b = pop(); + push(a && b); + break; + case Bytecodes::_ldiv: + case Bytecodes::_lrem: + pop(); + if (!pop()) + return false; + pop(); + pop(); + push(false); + push(false); + break; + case Bytecodes::_lneg: + break; + case Bytecodes::_lshl: + case Bytecodes::_lshr: + case Bytecodes::_lushr: + pop(); + pop(); + pop(); + push(false); + push(false); + break; + + case Bytecodes::_fadd: + case Bytecodes::_fsub: + case Bytecodes::_fmul: + case Bytecodes::_fdiv: + case Bytecodes::_frem: + pop(); + pop(); + push(false); + break; + case Bytecodes::_fneg: + break; + + case Bytecodes::_dadd: + case Bytecodes::_dsub: + case Bytecodes::_dmul: + case Bytecodes::_ddiv: + case Bytecodes::_drem: + pop(); + pop(); + pop(); + pop(); + push(false); + push(false); + break; + case Bytecodes::_dneg: + break; + + case Bytecodes::_iinc: + set_local(iter()->get_index(), false); + break; + + case Bytecodes::_lcmp: + pop(); + pop(); + pop(); + pop(); + push(false); + break; + + case Bytecodes::_fcmpl: + case Bytecodes::_fcmpg: + pop(); + pop(); + push(false); + break; + + case Bytecodes::_dcmpl: + case Bytecodes::_dcmpg: + pop(); + pop(); + pop(); + pop(); + push(false); + break; + + case Bytecodes::_i2l: + push(false); + break; + case Bytecodes::_i2f: + pop(); + push(false); + break; + case Bytecodes::_i2d: + pop(); + push(false); + push(false); + break; + + case Bytecodes::_l2i: + case Bytecodes::_l2f: + pop(); + pop(); + push(false); + break; + case Bytecodes::_l2d: + pop(); + pop(); + push(false); + push(false); + break; + + case Bytecodes::_f2i: + pop(); + push(false); + break; + case Bytecodes::_f2l: + case Bytecodes::_f2d: + pop(); + push(false); + push(false); + break; + + case Bytecodes::_d2i: + case Bytecodes::_d2f: + pop(); + pop(); + push(false); + break; + case Bytecodes::_d2l: + pop(); + pop(); + push(false); + push(false); + break; + + case Bytecodes::_i2b: + case Bytecodes::_i2c: + case Bytecodes::_i2s: + pop(); + push(false); + break; + + case Bytecodes::_return: + case Bytecodes::_ireturn: + case Bytecodes::_lreturn: + case Bytecodes::_freturn: + case Bytecodes::_dreturn: + case Bytecodes::_areturn: + break; + + default: + return false; + } + } + + return true; +} + +void SharkInlinerHelper::initialize_for_check() { + _locals = NEW_RESOURCE_ARRAY(bool, max_locals()); + _stack = NEW_RESOURCE_ARRAY(bool, max_stack()); + + memset(_locals, 0, max_locals() * sizeof(bool)); + for (int i = 0; i < target()->arg_size(); i++) { + SharkValue *arg = entry_state()->stack(target()->arg_size() - 1 - i); + if (arg && arg->zero_checked()) + set_local(i, true); + } + + _sp = _stack; +} + +bool SharkInlinerHelper::do_field_access(bool is_get, bool is_field) { + assert(is_get || is_field, "can't inline putstatic"); + + // If the holder isn't linked then there isn't a lot we can do + if (!target()->holder()->is_linked()) + return false; + + // Get the field + bool will_link; + ciField *field = iter()->get_field(will_link); + if (!will_link) + return false; + + // If the field is mismatched then an exception needs throwing + if (is_field == field->is_static()) + return false; + + // Pop the value off the stack if necessary + if (!is_get) { + pop(); + if (field->type()->is_two_word()) + pop(); + } + + // Pop and null-check the receiver if necessary + if (is_field) { + if (!pop()) + return false; + } + + // Push the result if necessary + if (is_get) { + bool result_pushed = false; + if (field->is_constant()) { + SharkConstant *sc = SharkConstant::for_field(iter()); + if (sc->is_loaded()) { + push(sc->is_nonzero()); + result_pushed = true; + } + } + + if (!result_pushed) + push(false); + + if (field->type()->is_two_word()) + push(false); + } + + return true; +} + +bool SharkInliner::attempt_inline(ciMethod *target, SharkState *state) { + if (SharkIntrinsics::is_intrinsic(target)) { + SharkIntrinsics::inline_intrinsic(target, state); + return true; + } + + if (may_be_inlinable(target)) { + SharkInlinerHelper inliner(target, state); + if (inliner.is_inlinable()) { + inliner.do_inline(); + return true; + } + } + return false; +} diff --git a/hotspot/src/share/vm/shark/sharkInliner.hpp b/hotspot/src/share/vm/shark/sharkInliner.hpp new file mode 100644 index 00000000000..ee37eb71543 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkInliner.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkInliner : public AllStatic { + public: + static bool attempt_inline(ciMethod* target, SharkState* state); + + private: + static bool may_be_inlinable(ciMethod* target); +}; diff --git a/hotspot/src/share/vm/shark/sharkIntrinsics.cpp b/hotspot/src/share/vm/shark/sharkIntrinsics.cpp new file mode 100644 index 00000000000..1ad042b2de3 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkIntrinsics.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkIntrinsics.cpp.incl" + +using namespace llvm; + +bool SharkIntrinsics::is_intrinsic(ciMethod *target) { + switch (target->intrinsic_id()) { + case vmIntrinsics::_none: + return false; + + // java.lang.Math + case vmIntrinsics::_min: + case vmIntrinsics::_max: + case vmIntrinsics::_dabs: + case vmIntrinsics::_dsin: + case vmIntrinsics::_dcos: + case vmIntrinsics::_dtan: + case vmIntrinsics::_datan2: + case vmIntrinsics::_dsqrt: + case vmIntrinsics::_dlog: + case vmIntrinsics::_dlog10: + case vmIntrinsics::_dpow: + case vmIntrinsics::_dexp: + return true; + + // java.lang.Object + case vmIntrinsics::_getClass: + return true; + + // java.lang.System + case vmIntrinsics::_currentTimeMillis: + return true; + + // java.lang.Thread + case vmIntrinsics::_currentThread: + return true; + + // sun.misc.Unsafe + case vmIntrinsics::_compareAndSwapInt: + return true; + + default: + if (SharkPerformanceWarnings) { + warning( + "unhandled intrinsic vmIntrinsic::%s", + vmIntrinsics::name_at(target->intrinsic_id())); + } + } + return false; +} + +void SharkIntrinsics::inline_intrinsic(ciMethod *target, SharkState *state) { + SharkIntrinsics intrinsic(state, target); + intrinsic.do_intrinsic(); +} + +void SharkIntrinsics::do_intrinsic() { + switch (target()->intrinsic_id()) { + // java.lang.Math + case vmIntrinsics::_min: + do_Math_minmax(llvm::ICmpInst::ICMP_SLE); + break; + case vmIntrinsics::_max: + do_Math_minmax(llvm::ICmpInst::ICMP_SGE); + break; + case vmIntrinsics::_dabs: + do_Math_1to1(builder()->fabs()); + break; + case vmIntrinsics::_dsin: + do_Math_1to1(builder()->sin()); + break; + case vmIntrinsics::_dcos: + do_Math_1to1(builder()->cos()); + break; + case vmIntrinsics::_dtan: + do_Math_1to1(builder()->tan()); + break; + case vmIntrinsics::_datan2: + do_Math_2to1(builder()->atan2()); + break; + case vmIntrinsics::_dsqrt: + do_Math_1to1(builder()->sqrt()); + break; + case vmIntrinsics::_dlog: + do_Math_1to1(builder()->log()); + break; + case vmIntrinsics::_dlog10: + do_Math_1to1(builder()->log10()); + break; + case vmIntrinsics::_dpow: + do_Math_2to1(builder()->pow()); + break; + case vmIntrinsics::_dexp: + do_Math_1to1(builder()->exp()); + break; + + // java.lang.Object + case vmIntrinsics::_getClass: + do_Object_getClass(); + break; + + // java.lang.System + case vmIntrinsics::_currentTimeMillis: + do_System_currentTimeMillis(); + break; + + // java.lang.Thread + case vmIntrinsics::_currentThread: + do_Thread_currentThread(); + break; + + // sun.misc.Unsafe + case vmIntrinsics::_compareAndSwapInt: + do_Unsafe_compareAndSwapInt(); + break; + + default: + ShouldNotReachHere(); + } +} + +void SharkIntrinsics::do_Math_minmax(ICmpInst::Predicate p) { + // Pop the arguments + SharkValue *sb = state()->pop(); + SharkValue *sa = state()->pop(); + Value *a = sa->jint_value(); + Value *b = sb->jint_value(); + + // Perform the test + BasicBlock *ip = builder()->GetBlockInsertionPoint(); + BasicBlock *return_a = builder()->CreateBlock(ip, "return_a"); + BasicBlock *return_b = builder()->CreateBlock(ip, "return_b"); + BasicBlock *done = builder()->CreateBlock(ip, "done"); + + builder()->CreateCondBr(builder()->CreateICmp(p, a, b), return_a, return_b); + + builder()->SetInsertPoint(return_a); + builder()->CreateBr(done); + + builder()->SetInsertPoint(return_b); + builder()->CreateBr(done); + + builder()->SetInsertPoint(done); + PHINode *phi = builder()->CreatePHI(a->getType(), "result"); + phi->addIncoming(a, return_a); + phi->addIncoming(b, return_b); + + // Push the result + state()->push( + SharkValue::create_jint( + phi, + sa->zero_checked() && sb->zero_checked())); +} + +void SharkIntrinsics::do_Math_1to1(Value *function) { + SharkValue *empty = state()->pop(); + assert(empty == NULL, "should be"); + state()->push( + SharkValue::create_jdouble( + builder()->CreateCall( + function, state()->pop()->jdouble_value()))); + state()->push(NULL); +} + +void SharkIntrinsics::do_Math_2to1(Value *function) { + SharkValue *empty = state()->pop(); + assert(empty == NULL, "should be"); + Value *y = state()->pop()->jdouble_value(); + empty = state()->pop(); + assert(empty == NULL, "should be"); + Value *x = state()->pop()->jdouble_value(); + + state()->push( + SharkValue::create_jdouble( + builder()->CreateCall2(function, x, y))); + state()->push(NULL); +} + +void SharkIntrinsics::do_Object_getClass() { + Value *klass = builder()->CreateValueOfStructEntry( + state()->pop()->jobject_value(), + in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::oop_type(), + "klass"); + + Value *klass_part = builder()->CreateAddressOfStructEntry( + klass, + in_ByteSize(klassOopDesc::klass_part_offset_in_bytes()), + SharkType::klass_type(), + "klass_part"); + + state()->push( + SharkValue::create_jobject( + builder()->CreateValueOfStructEntry( + klass_part, + in_ByteSize(Klass::java_mirror_offset_in_bytes()), + SharkType::oop_type(), + "java_mirror"), + true)); +} + +void SharkIntrinsics::do_System_currentTimeMillis() { + state()->push( + SharkValue::create_jlong( + builder()->CreateCall(builder()->current_time_millis()), + false)); + state()->push(NULL); +} + +void SharkIntrinsics::do_Thread_currentThread() { + state()->push( + SharkValue::create_jobject( + builder()->CreateValueOfStructEntry( + thread(), JavaThread::threadObj_offset(), + SharkType::oop_type(), + "threadObj"), + true)); +} + +void SharkIntrinsics::do_Unsafe_compareAndSwapInt() { + // Pop the arguments + Value *x = state()->pop()->jint_value(); + Value *e = state()->pop()->jint_value(); + SharkValue *empty = state()->pop(); + assert(empty == NULL, "should be"); + Value *offset = state()->pop()->jlong_value(); + Value *object = state()->pop()->jobject_value(); + Value *unsafe = state()->pop()->jobject_value(); + + // Convert the offset + offset = builder()->CreateCall( + builder()->unsafe_field_offset_to_byte_offset(), + offset); + + // Locate the field + Value *addr = builder()->CreateIntToPtr( + builder()->CreateAdd( + builder()->CreatePtrToInt(object, SharkType::intptr_type()), + builder()->CreateIntCast(offset, SharkType::intptr_type(), true)), + PointerType::getUnqual(SharkType::jint_type()), + "addr"); + + // Perform the operation + Value *result = builder()->CreateCmpxchgInt(x, addr, e); + + // Push the result + state()->push( + SharkValue::create_jint( + builder()->CreateIntCast( + builder()->CreateICmpEQ(result, e), SharkType::jint_type(), true), + false)); +} diff --git a/hotspot/src/share/vm/shark/sharkIntrinsics.hpp b/hotspot/src/share/vm/shark/sharkIntrinsics.hpp new file mode 100644 index 00000000000..a9f337b6ba7 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkIntrinsics.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkIntrinsics : public SharkTargetInvariants { + public: + static bool is_intrinsic(ciMethod* target); + static void inline_intrinsic(ciMethod* target, SharkState* state); + + private: + SharkIntrinsics(SharkState* state, ciMethod* target) + : SharkTargetInvariants(state, target), _state(state) {} + + private: + SharkState* _state; + + private: + SharkState* state() const { + return _state; + } + + private: + void do_intrinsic(); + + private: + void do_Math_minmax(llvm::ICmpInst::Predicate p); + void do_Math_1to1(llvm::Value* function); + void do_Math_2to1(llvm::Value* function); + void do_Object_getClass(); + void do_System_currentTimeMillis(); + void do_Thread_currentThread(); + void do_Unsafe_compareAndSwapInt(); +}; diff --git a/hotspot/src/share/vm/shark/sharkInvariants.cpp b/hotspot/src/share/vm/shark/sharkInvariants.cpp new file mode 100644 index 00000000000..93ddc64e43f --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkInvariants.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkInvariants.cpp.incl" + +int SharkTargetInvariants::count_monitors() { + int result = 0; + if (is_synchronized() || target()->has_monitor_bytecodes()) { + for (int i = 0; i < flow()->block_count(); i++) { + result = MAX2(result, flow()->pre_order_at(i)->monitor_count()); + } + } + return result; +} diff --git a/hotspot/src/share/vm/shark/sharkInvariants.hpp b/hotspot/src/share/vm/shark/sharkInvariants.hpp new file mode 100644 index 00000000000..787aedf5f7c --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkInvariants.hpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// Base classes used to track various values through the compilation. +// SharkCompileInvariants is used to track values which remain the +// same for the top-level method and any inlined methods it may have +// (ie for the whole compilation). SharkTargetInvariants is used to +// track values which differ between methods. + +class SharkCompileInvariants : public ResourceObj { + protected: + SharkCompileInvariants(ciEnv* env, SharkBuilder* builder) + : _env(env), + _builder(builder), + _thread(NULL) {} + + SharkCompileInvariants(const SharkCompileInvariants* parent) + : _env(parent->_env), + _builder(parent->_builder), + _thread(parent->_thread) {} + + private: + ciEnv* _env; + SharkBuilder* _builder; + llvm::Value* _thread; + + // Top-level broker for HotSpot's Compiler Interface. + // + // Its main purpose is to allow the various CI classes to access + // oops in the VM without having to worry about safepointing. In + // addition to this it acts as a holder for various recorders and + // memory allocators. + // + // Accessing this directly is kind of ugly, so it's private. Add + // new accessors below if you need something from it. + private: + ciEnv* env() const { + assert(_env != NULL, "env not available"); + return _env; + } + + // The SharkBuilder that is used to build LLVM IR. + protected: + SharkBuilder* builder() const { + return _builder; + } + + // Pointer to this thread's JavaThread object. This is not + // available until a short way into SharkFunction creation + // so a setter is required. Assertions are used to enforce + // invariance. + protected: + llvm::Value* thread() const { + assert(_thread != NULL, "thread not available"); + return _thread; + } + void set_thread(llvm::Value* thread) { + assert(_thread == NULL, "thread already set"); + _thread = thread; + } + + // Objects that handle various aspects of the compilation. + protected: + DebugInformationRecorder* debug_info() const { + return env()->debug_info(); + } + Dependencies* dependencies() const { + return env()->dependencies(); + } + SharkCodeBuffer* code_buffer() const { + return builder()->code_buffer(); + } + + // Commonly used classes + protected: + ciInstanceKlass* java_lang_Object_klass() const { + return env()->Object_klass(); + } + ciInstanceKlass* java_lang_Throwable_klass() const { + return env()->Throwable_klass(); + } +}; + +class SharkTargetInvariants : public SharkCompileInvariants { + protected: + SharkTargetInvariants(ciEnv* env, SharkBuilder* builder, ciTypeFlow* flow) + : SharkCompileInvariants(env, builder), + _target(flow->method()), + _flow(flow), + _max_monitors(count_monitors()) {} + + SharkTargetInvariants(const SharkCompileInvariants* parent, ciMethod* target) + : SharkCompileInvariants(parent), + _target(target), + _flow(NULL), + _max_monitors(count_monitors()) {} + + SharkTargetInvariants(const SharkTargetInvariants* parent) + : SharkCompileInvariants(parent), + _target(parent->_target), + _flow(parent->_flow), + _max_monitors(parent->_max_monitors) {} + + private: + int count_monitors(); + + private: + ciMethod* _target; + ciTypeFlow* _flow; + int _max_monitors; + + // The method being compiled. + protected: + ciMethod* target() const { + return _target; + } + + // Typeflow analysis of the method being compiled. + protected: + ciTypeFlow* flow() const { + assert(_flow != NULL, "typeflow not available"); + return _flow; + } + + // Properties of the method. + protected: + int max_locals() const { + return target()->max_locals(); + } + int max_stack() const { + return target()->max_stack(); + } + int max_monitors() const { + return _max_monitors; + } + int arg_size() const { + return target()->arg_size(); + } + bool is_static() const { + return target()->is_static(); + } + bool is_synchronized() const { + return target()->is_synchronized(); + } +}; diff --git a/hotspot/src/share/vm/shark/sharkMemoryManager.cpp b/hotspot/src/share/vm/shark/sharkMemoryManager.cpp new file mode 100644 index 00000000000..37334a4e8af --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkMemoryManager.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkMemoryManager.cpp.incl" + +using namespace llvm; + +void SharkMemoryManager::AllocateGOT() { + mm()->AllocateGOT(); +} + +unsigned char* SharkMemoryManager::getGOTBase() const { + return mm()->getGOTBase(); +} + +unsigned char* SharkMemoryManager::allocateStub(const GlobalValue* F, + unsigned StubSize, + unsigned Alignment) { + return mm()->allocateStub(F, StubSize, Alignment); +} + +unsigned char* SharkMemoryManager::startFunctionBody(const Function* F, + uintptr_t& ActualSize) { + return mm()->startFunctionBody(F, ActualSize); +} + +void SharkMemoryManager::endFunctionBody(const Function* F, + unsigned char* FunctionStart, + unsigned char* FunctionEnd) { + mm()->endFunctionBody(F, FunctionStart, FunctionEnd); + + SharkEntry *entry = get_entry_for_function(F); + if (entry != NULL) + entry->set_code_limit(FunctionEnd); +} + +unsigned char* SharkMemoryManager::startExceptionTable(const Function* F, + uintptr_t& ActualSize) { + return mm()->startExceptionTable(F, ActualSize); +} + +void SharkMemoryManager::endExceptionTable(const Function* F, + unsigned char* TableStart, + unsigned char* TableEnd, + unsigned char* FrameRegister) { + mm()->endExceptionTable(F, TableStart, TableEnd, FrameRegister); +} + +void SharkMemoryManager::setMemoryWritable() { + mm()->setMemoryWritable(); +} + +void SharkMemoryManager::setMemoryExecutable() { + mm()->setMemoryExecutable(); +} + +#if SHARK_LLVM_VERSION >= 27 +void SharkMemoryManager::deallocateExceptionTable(void *ptr) { + mm()->deallocateExceptionTable(ptr); +} + +void SharkMemoryManager::deallocateFunctionBody(void *ptr) { + mm()->deallocateFunctionBody(ptr); +} +#else +void SharkMemoryManager::deallocateMemForFunction(const Function* F) { + return mm()->deallocateMemForFunction(F); +} +#endif + +uint8_t* SharkMemoryManager::allocateGlobal(uintptr_t Size, + unsigned int Alignment) { + return mm()->allocateGlobal(Size, Alignment); +} + +#if SHARK_LLVM_VERSION < 27 +void* SharkMemoryManager::getDlsymTable() const { + return mm()->getDlsymTable(); +} + +void SharkMemoryManager::SetDlsymTable(void *ptr) { + mm()->SetDlsymTable(ptr); +} +#endif + +void SharkMemoryManager::setPoisonMemory(bool poison) { + mm()->setPoisonMemory(poison); +} + +unsigned char *SharkMemoryManager::allocateSpace(intptr_t Size, + unsigned int Alignment) { + return mm()->allocateSpace(Size, Alignment); +} diff --git a/hotspot/src/share/vm/shark/sharkMemoryManager.hpp b/hotspot/src/share/vm/shark/sharkMemoryManager.hpp new file mode 100644 index 00000000000..c2884d0b17b --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkMemoryManager.hpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// SharkMemoryManager wraps the LLVM JIT Memory Manager. We could use +// this to run our own memory allocation policies, but for now all we +// use it for is figuring out where the resulting native code ended up. + +class SharkMemoryManager : public llvm::JITMemoryManager { + public: + SharkMemoryManager() + : _mm(llvm::JITMemoryManager::CreateDefaultMemManager()) {} + + private: + llvm::JITMemoryManager* _mm; + + private: + llvm::JITMemoryManager* mm() const { + return _mm; + } + + private: + std::map _entry_map; + + public: + void set_entry_for_function(const llvm::Function* function, + SharkEntry* entry) { + _entry_map[function] = entry; + } + SharkEntry* get_entry_for_function(const llvm::Function* function) { + return _entry_map[function]; + } + + public: + void AllocateGOT(); + unsigned char* getGOTBase() const; + unsigned char* allocateStub(const llvm::GlobalValue* F, + unsigned StubSize, + unsigned Alignment); + unsigned char* startFunctionBody(const llvm::Function* F, + uintptr_t& ActualSize); + void endFunctionBody(const llvm::Function* F, + unsigned char* FunctionStart, + unsigned char* FunctionEnd); + unsigned char* startExceptionTable(const llvm::Function* F, + uintptr_t& ActualSize); + void endExceptionTable(const llvm::Function* F, + unsigned char* TableStart, + unsigned char* TableEnd, + unsigned char* FrameRegister); +#if SHARK_LLVM_VERSION < 27 + void* getDlsymTable() const; + void SetDlsymTable(void *ptr); +#endif + void setPoisonMemory(bool); + uint8_t* allocateGlobal(uintptr_t, unsigned int); + void setMemoryWritable(); + void setMemoryExecutable(); +#if SHARK_LLVM_VERSION >= 27 + void deallocateExceptionTable(void *ptr); + void deallocateFunctionBody(void *ptr); +#else + void deallocateMemForFunction(const llvm::Function* F); +#endif + unsigned char *allocateSpace(intptr_t Size, + unsigned int Alignment); +}; diff --git a/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp b/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp new file mode 100644 index 00000000000..b46ad80025e --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkNativeWrapper.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkNativeWrapper.cpp.incl" + +using namespace llvm; + +void SharkNativeWrapper::initialize(const char *name) { + // Create the function + _function = Function::Create( + SharkType::entry_point_type(), + GlobalVariable::InternalLinkage, + name); + + // Get our arguments + Function::arg_iterator ai = function()->arg_begin(); + Argument *method = ai++; + method->setName("method"); + Argument *base_pc = ai++; + base_pc->setName("base_pc"); + code_buffer()->set_base_pc(base_pc); + Argument *thread = ai++; + thread->setName("thread"); + set_thread(thread); + + // Create and push our stack frame + builder()->SetInsertPoint(CreateBlock()); + _stack = SharkStack::CreateBuildAndPushFrame(this, method); + NOT_PRODUCT(method = NULL); + + // Create the oopmap. We use the one oopmap for every call site in + // the wrapper, which results in the odd mild inefficiency but is a + // damn sight easier to code. + OopMap *oopmap = new OopMap( + SharkStack::oopmap_slot_munge(stack()->oopmap_frame_size()), + SharkStack::oopmap_slot_munge(arg_size())); + oopmap->set_oop(SharkStack::slot2reg(stack()->method_slot_offset())); + + // Set up the oop_tmp slot if required: + // - For static methods we use it to handlize the class argument + // for the call, and to protect the same during slow path locks + // (if synchronized). + // - For methods returning oops, we use it to protect the return + // value across safepoints or slow path unlocking. + if (is_static() || is_returning_oop()) { + _oop_tmp_slot = stack()->slot_addr( + stack()->oop_tmp_slot_offset(), + SharkType::oop_type(), + "oop_tmp_slot"); + + oopmap->set_oop(SharkStack::slot2reg(stack()->oop_tmp_slot_offset())); + } + + // Set up the monitor slot, for synchronized methods + if (is_synchronized()) { + Unimplemented(); + _lock_slot_offset = 23; + } + + // Start building the argument list + std::vector param_types; + std::vector param_values; + const PointerType *box_type = PointerType::getUnqual(SharkType::oop_type()); + + // First argument is the JNIEnv + param_types.push_back(SharkType::jniEnv_type()); + param_values.push_back( + builder()->CreateAddressOfStructEntry( + thread, + JavaThread::jni_environment_offset(), + SharkType::jniEnv_type(), + "jni_environment")); + + // For static methods, the second argument is the class + if (is_static()) { + builder()->CreateStore( + builder()->CreateInlineOop( + JNIHandles::make_local( + target()->method_holder()->klass_part()->java_mirror())), + oop_tmp_slot()); + + param_types.push_back(box_type); + param_values.push_back(oop_tmp_slot()); + + _receiver_slot_offset = stack()->oop_tmp_slot_offset(); + } + else if (is_returning_oop()) { + // The oop_tmp slot is registered in the oopmap, + // so we need to clear it. This is one of the + // mild inefficiencies I mentioned earlier. + builder()->CreateStore(LLVMValue::null(), oop_tmp_slot()); + } + + // Parse the arguments + for (int i = 0; i < arg_size(); i++) { + int slot_offset = stack()->locals_slots_offset() + arg_size() - 1 - i; + int adjusted_offset = slot_offset; + BasicBlock *null, *not_null, *merge; + Value *box; + PHINode *phi; + + switch (arg_type(i)) { + case T_VOID: + break; + + case T_OBJECT: + case T_ARRAY: + null = CreateBlock("null"); + not_null = CreateBlock("not_null"); + merge = CreateBlock("merge"); + + box = stack()->slot_addr(slot_offset, SharkType::oop_type()); + builder()->CreateCondBr( + builder()->CreateICmp( + ICmpInst::ICMP_EQ, + builder()->CreateLoad(box), + LLVMValue::null()), + null, not_null); + + builder()->SetInsertPoint(null); + builder()->CreateBr(merge); + + builder()->SetInsertPoint(not_null); + builder()->CreateBr(merge); + + builder()->SetInsertPoint(merge); + phi = builder()->CreatePHI(box_type, "boxed_object"); + phi->addIncoming(ConstantPointerNull::get(box_type), null); + phi->addIncoming(box, not_null); + box = phi; + + param_types.push_back(box_type); + param_values.push_back(box); + + oopmap->set_oop(SharkStack::slot2reg(slot_offset)); + + if (i == 0 && !is_static()) + _receiver_slot_offset = slot_offset; + + break; + + case T_LONG: + case T_DOUBLE: + adjusted_offset--; + // fall through + + default: + const Type *param_type = SharkType::to_stackType(arg_type(i)); + + param_types.push_back(param_type); + param_values.push_back( + builder()->CreateLoad(stack()->slot_addr(adjusted_offset, param_type))); + } + } + + // The oopmap is now complete, and everything is written + // into the frame except the PC. + int pc_offset = code_buffer()->create_unique_offset(); + + _oop_maps = new OopMapSet(); + oop_maps()->add_gc_map(pc_offset, oopmap); + + builder()->CreateStore( + builder()->code_buffer_address(pc_offset), + stack()->slot_addr(stack()->pc_slot_offset())); + + // Set up the Java frame anchor + stack()->CreateSetLastJavaFrame(); + + // Lock if necessary + if (is_synchronized()) + Unimplemented(); + + // Change the thread state to _thread_in_native + CreateSetThreadState(_thread_in_native); + + // Make the call + BasicType result_type = target()->result_type(); + const Type* return_type; + if (result_type == T_VOID) + return_type = SharkType::void_type(); + else if (is_returning_oop()) + return_type = box_type; + else + return_type = SharkType::to_arrayType(result_type); + Value* native_function = builder()->CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) target()->native_function()), + PointerType::getUnqual( + FunctionType::get(return_type, param_types, false))); + Value *result = builder()->CreateCall( + native_function, param_values.begin(), param_values.end()); + + // Start the transition back to _thread_in_Java + CreateSetThreadState(_thread_in_native_trans); + + // Make sure new state is visible in the GC thread + if (os::is_MP()) { + if (UseMembar) + builder()->CreateMemoryBarrier(SharkBuilder::BARRIER_STORELOAD); + else + CreateWriteMemorySerializePage(); + } + + // Handle safepoint operations, pending suspend requests, + // and pending asynchronous exceptions. + BasicBlock *check_thread = CreateBlock("check_thread"); + BasicBlock *do_safepoint = CreateBlock("do_safepoint"); + BasicBlock *safepointed = CreateBlock("safepointed"); + + Value *global_state = builder()->CreateLoad( + builder()->CreateIntToPtr( + LLVMValue::intptr_constant( + (intptr_t) SafepointSynchronize::address_of_state()), + PointerType::getUnqual(SharkType::jint_type())), + "global_state"); + + builder()->CreateCondBr( + builder()->CreateICmpNE( + global_state, + LLVMValue::jint_constant(SafepointSynchronize::_not_synchronized)), + do_safepoint, check_thread); + + builder()->SetInsertPoint(check_thread); + Value *thread_state = builder()->CreateValueOfStructEntry( + thread, + JavaThread::suspend_flags_offset(), + SharkType::jint_type(), + "thread_state"); + + builder()->CreateCondBr( + builder()->CreateICmpNE( + thread_state, + LLVMValue::jint_constant(0)), + do_safepoint, safepointed); + + builder()->SetInsertPoint(do_safepoint); + builder()->CreateCall( + builder()->check_special_condition_for_native_trans(), thread); + builder()->CreateBr(safepointed); + + // Finally we can change the thread state to _thread_in_Java + builder()->SetInsertPoint(safepointed); + CreateSetThreadState(_thread_in_Java); + + // Clear the frame anchor + stack()->CreateResetLastJavaFrame(); + + // If there is a pending exception then we can just unwind and + // return. It seems totally wrong that unlocking is skipped here + // but apparently the template interpreter does this so we do too. + BasicBlock *exception = CreateBlock("exception"); + BasicBlock *no_exception = CreateBlock("no_exception"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ( + CreateLoadPendingException(), + LLVMValue::null()), + no_exception, exception); + + builder()->SetInsertPoint(exception); + CreateResetHandleBlock(); + stack()->CreatePopFrame(0); + builder()->CreateRet(LLVMValue::jint_constant(0)); + + builder()->SetInsertPoint(no_exception); + + // If the result was an oop then unbox it before + // releasing the handle it might be protected by + if (is_returning_oop()) { + BasicBlock *null = builder()->GetInsertBlock(); + BasicBlock *not_null = CreateBlock("not_null"); + BasicBlock *merge = CreateBlock("merge"); + + builder()->CreateCondBr( + builder()->CreateICmpNE(result, ConstantPointerNull::get(box_type)), + not_null, merge); + + builder()->SetInsertPoint(not_null); + Value *unboxed_result = builder()->CreateLoad(result); + builder()->CreateBr(merge); + + builder()->SetInsertPoint(merge); + PHINode *phi = builder()->CreatePHI(SharkType::oop_type(), "result"); + phi->addIncoming(LLVMValue::null(), null); + phi->addIncoming(unboxed_result, not_null); + result = phi; + } + + // Reset handle block + CreateResetHandleBlock(); + + // Unlock if necessary. + if (is_synchronized()) + Unimplemented(); + + // Unwind and return + Value *result_addr = stack()->CreatePopFrame(type2size[result_type]); + if (result_type != T_VOID) { + bool needs_cast = false; + bool is_signed = false; + switch (result_type) { + case T_BOOLEAN: + result = builder()->CreateICmpNE(result, LLVMValue::jbyte_constant(0)); + needs_cast = true; + break; + + case T_CHAR: + needs_cast = true; + break; + + case T_BYTE: + case T_SHORT: + needs_cast = true; + is_signed = true; + break; + } + if (needs_cast) { + result = builder()->CreateIntCast( + result, SharkType::to_stackType(result_type), is_signed); + } + + builder()->CreateStore( + result, + builder()->CreateIntToPtr( + result_addr, + PointerType::getUnqual(SharkType::to_stackType(result_type)))); + } + builder()->CreateRet(LLVMValue::jint_constant(0)); +} diff --git a/hotspot/src/share/vm/shark/sharkNativeWrapper.hpp b/hotspot/src/share/vm/shark/sharkNativeWrapper.hpp new file mode 100644 index 00000000000..6e324fe2ea3 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkNativeWrapper.hpp @@ -0,0 +1,182 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkNativeWrapper : public SharkCompileInvariants { + friend class SharkStackWithNativeFrame; + + public: + static SharkNativeWrapper* build(SharkBuilder* builder, + methodHandle target, + const char* name, + BasicType* arg_types, + BasicType return_type) { + return new SharkNativeWrapper(builder, + target, + name, + arg_types, + return_type); + } + + private: + SharkNativeWrapper(SharkBuilder* builder, + methodHandle target, + const char* name, + BasicType* arg_types, + BasicType return_type) + : SharkCompileInvariants(NULL, builder), + _target(target), + _arg_types(arg_types), + _return_type(return_type), + _lock_slot_offset(0) { initialize(name); } + + private: + void initialize(const char* name); + + private: + methodHandle _target; + BasicType* _arg_types; + BasicType _return_type; + llvm::Function* _function; + SharkStack* _stack; + llvm::Value* _oop_tmp_slot; + OopMapSet* _oop_maps; + int _receiver_slot_offset; + int _lock_slot_offset; + + // The method being compiled. + protected: + methodHandle target() const { + return _target; + } + + // Properties of the method. + protected: + int arg_size() const { + return target()->size_of_parameters(); + } + BasicType arg_type(int i) const { + return _arg_types[i]; + } + BasicType return_type() const { + return _return_type; + } + bool is_static() const { + return target()->is_static(); + } + bool is_synchronized() const { + return target()->is_synchronized(); + } + bool is_returning_oop() const { + return target()->is_returning_oop(); + } + + // The LLVM function we are building. + public: + llvm::Function* function() const { + return _function; + } + + // The Zero stack and our frame on it. + protected: + SharkStack* stack() const { + return _stack; + } + + // Temporary oop storage. + protected: + llvm::Value* oop_tmp_slot() const { + assert(is_static() || is_returning_oop(), "should be"); + return _oop_tmp_slot; + } + + // Information required by nmethod::new_native_nmethod(). + public: + int frame_size() const { + return stack()->oopmap_frame_size(); + } + ByteSize receiver_offset() const { + return in_ByteSize(_receiver_slot_offset * wordSize); + } + ByteSize lock_offset() const { + return in_ByteSize(_lock_slot_offset * wordSize); + } + OopMapSet* oop_maps() const { + return _oop_maps; + } + + // Helpers. + private: + llvm::BasicBlock* CreateBlock(const char* name = "") const { + return llvm::BasicBlock::Create(SharkContext::current(), name, function()); + } + llvm::Value* thread_state_address() const { + return builder()->CreateAddressOfStructEntry( + thread(), JavaThread::thread_state_offset(), + llvm::PointerType::getUnqual(SharkType::jint_type()), + "thread_state_address"); + } + llvm::Value* pending_exception_address() const { + return builder()->CreateAddressOfStructEntry( + thread(), Thread::pending_exception_offset(), + llvm::PointerType::getUnqual(SharkType::oop_type()), + "pending_exception_address"); + } + void CreateSetThreadState(JavaThreadState state) const { + builder()->CreateStore( + LLVMValue::jint_constant(state), thread_state_address()); + } + void CreateWriteMemorySerializePage() const { + builder()->CreateStore( + LLVMValue::jint_constant(1), + builder()->CreateIntToPtr( + builder()->CreateAdd( + LLVMValue::intptr_constant( + (intptr_t) os::get_memory_serialize_page()), + builder()->CreateAnd( + builder()->CreateLShr( + builder()->CreatePtrToInt(thread(), SharkType::intptr_type()), + LLVMValue::intptr_constant(os::get_serialize_page_shift_count())), + LLVMValue::intptr_constant(os::get_serialize_page_mask()))), + llvm::PointerType::getUnqual(SharkType::jint_type()))); + } + void CreateResetHandleBlock() const { + llvm::Value *active_handles = builder()->CreateValueOfStructEntry( + thread(), + JavaThread::active_handles_offset(), + SharkType::jniHandleBlock_type(), + "active_handles"); + builder()->CreateStore( + LLVMValue::intptr_constant(0), + builder()->CreateAddressOfStructEntry( + active_handles, + in_ByteSize(JNIHandleBlock::top_offset_in_bytes()), + llvm::PointerType::getUnqual(SharkType::intptr_type()), + "top")); + } + llvm::LoadInst* CreateLoadPendingException() const { + return builder()->CreateLoad( + pending_exception_address(), "pending_exception"); + } +}; diff --git a/hotspot/src/share/vm/shark/sharkRuntime.cpp b/hotspot/src/share/vm/shark/sharkRuntime.cpp new file mode 100644 index 00000000000..6e8c1714e08 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkRuntime.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkRuntime.cpp.incl" + +using namespace llvm; + +JRT_ENTRY(int, SharkRuntime::find_exception_handler(JavaThread* thread, + int* indexes, + int num_indexes)) + constantPoolHandle pool(thread, method(thread)->constants()); + KlassHandle exc_klass(thread, ((oop) tos_at(thread, 0))->klass()); + + for (int i = 0; i < num_indexes; i++) { + klassOop tmp = pool->klass_at(indexes[i], CHECK_0); + KlassHandle chk_klass(thread, tmp); + + if (exc_klass() == chk_klass()) + return i; + + if (exc_klass()->klass_part()->is_subtype_of(chk_klass())) + return i; + } + + return -1; +JRT_END + +JRT_ENTRY(void, SharkRuntime::monitorenter(JavaThread* thread, + BasicObjectLock* lock)) + if (PrintBiasedLockingStatistics) + Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); + + Handle object(thread, lock->obj()); + assert(Universe::heap()->is_in_reserved_or_null(object()), "should be"); + if (UseBiasedLocking) { + // Retry fast entry if bias is revoked to avoid unnecessary inflation + ObjectSynchronizer::fast_enter(object, lock->lock(), true, CHECK); + } else { + ObjectSynchronizer::slow_enter(object, lock->lock(), CHECK); + } + assert(Universe::heap()->is_in_reserved_or_null(lock->obj()), "should be"); +JRT_END + +JRT_ENTRY(void, SharkRuntime::monitorexit(JavaThread* thread, + BasicObjectLock* lock)) + Handle object(thread, lock->obj()); + assert(Universe::heap()->is_in_reserved_or_null(object()), "should be"); + if (lock == NULL || object()->is_unlocked()) { + THROW(vmSymbols::java_lang_IllegalMonitorStateException()); + } + ObjectSynchronizer::slow_exit(object(), lock->lock(), thread); +JRT_END + +JRT_ENTRY(void, SharkRuntime::new_instance(JavaThread* thread, int index)) + klassOop k_oop = method(thread)->constants()->klass_at(index, CHECK); + instanceKlassHandle klass(THREAD, k_oop); + + // Make sure we are not instantiating an abstract klass + klass->check_valid_for_instantiation(true, CHECK); + + // Make sure klass is initialized + klass->initialize(CHECK); + + // At this point the class may not be fully initialized + // because of recursive initialization. If it is fully + // initialized & has_finalized is not set, we rewrite + // it into its fast version (Note: no locking is needed + // here since this is an atomic byte write and can be + // done more than once). + // + // Note: In case of classes with has_finalized we don't + // rewrite since that saves us an extra check in + // the fast version which then would call the + // slow version anyway (and do a call back into + // Java). + // If we have a breakpoint, then we don't rewrite + // because the _breakpoint bytecode would be lost. + oop obj = klass->allocate_instance(CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, SharkRuntime::newarray(JavaThread* thread, + BasicType type, + int size)) + oop obj = oopFactory::new_typeArray(type, size, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, SharkRuntime::anewarray(JavaThread* thread, + int index, + int size)) + klassOop klass = method(thread)->constants()->klass_at(index, CHECK); + objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, SharkRuntime::multianewarray(JavaThread* thread, + int index, + int ndims, + int* dims)) + klassOop klass = method(thread)->constants()->klass_at(index, CHECK); + oop obj = arrayKlass::cast(klass)->multi_allocate(ndims, dims, CHECK); + thread->set_vm_result(obj); +JRT_END + +JRT_ENTRY(void, SharkRuntime::register_finalizer(JavaThread* thread, + oop object)) + assert(object->is_oop(), "should be"); + assert(object->klass()->klass_part()->has_finalizer(), "should have"); + instanceKlass::register_finalizer(instanceOop(object), CHECK); +JRT_END + +JRT_ENTRY(void, SharkRuntime::throw_ArithmeticException(JavaThread* thread, + const char* file, + int line)) + Exceptions::_throw_msg( + thread, file, line, + vmSymbols::java_lang_ArithmeticException(), + ""); +JRT_END + +JRT_ENTRY(void, SharkRuntime::throw_ArrayIndexOutOfBoundsException( + JavaThread* thread, + const char* file, + int line, + int index)) + char msg[jintAsStringSize]; + snprintf(msg, sizeof(msg), "%d", index); + Exceptions::_throw_msg( + thread, file, line, + vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), + msg); +JRT_END + +JRT_ENTRY(void, SharkRuntime::throw_ClassCastException(JavaThread* thread, + const char* file, + int line)) + Exceptions::_throw_msg( + thread, file, line, + vmSymbols::java_lang_ClassCastException(), + ""); +JRT_END + +JRT_ENTRY(void, SharkRuntime::throw_NullPointerException(JavaThread* thread, + const char* file, + int line)) + Exceptions::_throw_msg( + thread, file, line, + vmSymbols::java_lang_NullPointerException(), + ""); +JRT_END + +// Non-VM calls +// Nothing in these must ever GC! + +void SharkRuntime::dump(const char *name, intptr_t value) { + oop valueOop = (oop) value; + tty->print("%s = ", name); + if (valueOop->is_oop(true)) + valueOop->print_on(tty); + else if (value >= ' ' && value <= '~') + tty->print("'%c' (%d)", value, value); + else + tty->print("%p", value); + tty->print_cr(""); +} + +bool SharkRuntime::is_subtype_of(klassOop check_klass, klassOop object_klass) { + return object_klass->klass_part()->is_subtype_of(check_klass); +} + +int SharkRuntime::uncommon_trap(JavaThread* thread, int trap_request) { + Thread *THREAD = thread; + + // In C2, uncommon_trap_blob creates a frame, so all the various + // deoptimization functions expect to find the frame of the method + // being deopted one frame down on the stack. We create a dummy + // frame to mirror this. + FakeStubFrame *stubframe = FakeStubFrame::build(CHECK_0); + thread->push_zero_frame(stubframe); + + // Initiate the trap + thread->set_last_Java_frame(); + Deoptimization::UnrollBlock *urb = + Deoptimization::uncommon_trap(thread, trap_request); + thread->reset_last_Java_frame(); + + // Pop our dummy frame and the frame being deoptimized + thread->pop_zero_frame(); + thread->pop_zero_frame(); + + // Push skeleton frames + int number_of_frames = urb->number_of_frames(); + for (int i = 0; i < number_of_frames; i++) { + intptr_t size = urb->frame_sizes()[i]; + InterpreterFrame *frame = InterpreterFrame::build(size, CHECK_0); + thread->push_zero_frame(frame); + } + + // Push another dummy frame + stubframe = FakeStubFrame::build(CHECK_0); + thread->push_zero_frame(stubframe); + + // Fill in the skeleton frames + thread->set_last_Java_frame(); + Deoptimization::unpack_frames(thread, Deoptimization::Unpack_uncommon_trap); + thread->reset_last_Java_frame(); + + // Pop our dummy frame + thread->pop_zero_frame(); + + // Fall back into the interpreter + return number_of_frames; +} + +FakeStubFrame* FakeStubFrame::build(TRAPS) { + ZeroStack *stack = ((JavaThread *) THREAD)->zero_stack(); + stack->overflow_check(header_words, CHECK_NULL); + + stack->push(0); // next_frame, filled in later + intptr_t *fp = stack->sp(); + assert(fp - stack->sp() == next_frame_off, "should be"); + + stack->push(FAKE_STUB_FRAME); + assert(fp - stack->sp() == frame_type_off, "should be"); + + return (FakeStubFrame *) fp; +} diff --git a/hotspot/src/share/vm/shark/sharkRuntime.hpp b/hotspot/src/share/vm/shark/sharkRuntime.hpp new file mode 100644 index 00000000000..5467187b392 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkRuntime.hpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkRuntime : public AllStatic { + // VM calls + public: + static int find_exception_handler(JavaThread* thread, + int* indexes, + int num_indexes); + + static void monitorenter(JavaThread* thread, BasicObjectLock* lock); + static void monitorexit(JavaThread* thread, BasicObjectLock* lock); + + static void new_instance(JavaThread* thread, int index); + static void newarray(JavaThread* thread, BasicType type, int size); + static void anewarray(JavaThread* thread, int index, int size); + static void multianewarray(JavaThread* thread, + int index, + int ndims, + int* dims); + + static void register_finalizer(JavaThread* thread, oop object); + + static void throw_ArithmeticException(JavaThread* thread, + const char* file, + int line); + static void throw_ArrayIndexOutOfBoundsException(JavaThread* thread, + const char* file, + int line, + int index); + static void throw_ClassCastException(JavaThread* thread, + const char* file, + int line); + static void throw_NullPointerException(JavaThread* thread, + const char* file, + int line); + + // Helpers for VM calls + private: + static const SharkFrame* last_frame(JavaThread *thread) { + return thread->last_frame().zero_sharkframe(); + } + static methodOop method(JavaThread *thread) { + return last_frame(thread)->method(); + } + static address bcp(JavaThread *thread, int bci) { + return method(thread)->code_base() + bci; + } + static int two_byte_index(JavaThread *thread, int bci) { + return Bytes::get_Java_u2(bcp(thread, bci) + 1); + } + static intptr_t tos_at(JavaThread *thread, int offset) { + return *(thread->zero_stack()->sp() + offset); + } + + // Non-VM calls + public: + static void dump(const char *name, intptr_t value); + static bool is_subtype_of(klassOop check_klass, klassOop object_klass); + static int uncommon_trap(JavaThread* thread, int trap_request); +}; diff --git a/hotspot/src/share/vm/shark/sharkStack.cpp b/hotspot/src/share/vm/shark/sharkStack.cpp new file mode 100644 index 00000000000..69058e59b1d --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkStack.cpp @@ -0,0 +1,263 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkStack.cpp.incl" + +using namespace llvm; + +void SharkStack::initialize(Value* method) { + bool setup_sp_and_method = (method != NULL); + + int locals_words = max_locals(); + int extra_locals = locals_words - arg_size(); + int header_words = SharkFrame::header_words; + int monitor_words = max_monitors()*frame::interpreter_frame_monitor_size(); + int stack_words = max_stack(); + int frame_words = header_words + monitor_words + stack_words; + + _extended_frame_size = frame_words + locals_words; + + // Update the stack pointer + Value *stack_pointer = builder()->CreateSub( + CreateLoadStackPointer(), + LLVMValue::intptr_constant((frame_words + extra_locals) * wordSize)); + CreateStackOverflowCheck(stack_pointer); + if (setup_sp_and_method) + CreateStoreStackPointer(stack_pointer); + + // Create the frame + _frame = builder()->CreateIntToPtr( + stack_pointer, + PointerType::getUnqual( + ArrayType::get(SharkType::intptr_type(), extended_frame_size())), + "frame"); + int offset = 0; + + // Expression stack + _stack_slots_offset = offset; + offset += stack_words; + + // Monitors + _monitors_slots_offset = offset; + offset += monitor_words; + + // Temporary oop slot + _oop_tmp_slot_offset = offset++; + + // Method pointer + _method_slot_offset = offset++; + if (setup_sp_and_method) { + builder()->CreateStore( + method, slot_addr(method_slot_offset(), SharkType::methodOop_type())); + } + + // Unextended SP + builder()->CreateStore(stack_pointer, slot_addr(offset++)); + + // PC + _pc_slot_offset = offset++; + + // Frame header + builder()->CreateStore( + LLVMValue::intptr_constant(ZeroFrame::SHARK_FRAME), slot_addr(offset++)); + Value *fp = slot_addr(offset++); + + // Local variables + _locals_slots_offset = offset; + offset += locals_words; + + // Push the frame + assert(offset == extended_frame_size(), "should do"); + builder()->CreateStore(CreateLoadFramePointer(), fp); + CreateStoreFramePointer( + builder()->CreatePtrToInt(fp, SharkType::intptr_type())); +} + +// This function should match ZeroStack::overflow_check +void SharkStack::CreateStackOverflowCheck(Value* sp) { + BasicBlock *zero_ok = CreateBlock("zero_stack_ok"); + BasicBlock *overflow = CreateBlock("stack_overflow"); + BasicBlock *abi_ok = CreateBlock("abi_stack_ok"); + + // Check the Zero stack + builder()->CreateCondBr( + builder()->CreateICmpULT(sp, stack_base()), + overflow, zero_ok); + + // Check the ABI stack + builder()->SetInsertPoint(zero_ok); + Value *stack_top = builder()->CreateSub( + builder()->CreateValueOfStructEntry( + thread(), + Thread::stack_base_offset(), + SharkType::intptr_type(), + "abi_base"), + builder()->CreateValueOfStructEntry( + thread(), + Thread::stack_size_offset(), + SharkType::intptr_type(), + "abi_size")); + Value *free_stack = builder()->CreateSub( + builder()->CreatePtrToInt( + builder()->CreateGetFrameAddress(), + SharkType::intptr_type(), + "abi_sp"), + stack_top); + builder()->CreateCondBr( + builder()->CreateICmpULT( + free_stack, + LLVMValue::intptr_constant(StackShadowPages * os::vm_page_size())), + overflow, abi_ok); + + // Handle overflows + builder()->SetInsertPoint(overflow); + builder()->CreateCall(builder()->throw_StackOverflowError(), thread()); + builder()->CreateRet(LLVMValue::jint_constant(0)); + + builder()->SetInsertPoint(abi_ok); +} + +Value* SharkStack::CreatePopFrame(int result_slots) { + assert(result_slots >= 0 && result_slots <= 2, "should be"); + int locals_to_pop = max_locals() - result_slots; + + Value *fp = CreateLoadFramePointer(); + Value *sp = builder()->CreateAdd( + fp, + LLVMValue::intptr_constant((1 + locals_to_pop) * wordSize)); + + CreateStoreStackPointer(sp); + CreateStoreFramePointer( + builder()->CreateLoad( + builder()->CreateIntToPtr( + fp, PointerType::getUnqual(SharkType::intptr_type())))); + + return sp; +} + +Value* SharkStack::slot_addr(int offset, + const Type* type, + const char* name) const { + bool needs_cast = type && type != SharkType::intptr_type(); + + Value* result = builder()->CreateStructGEP( + _frame, offset, needs_cast ? "" : name); + + if (needs_cast) { + result = builder()->CreateBitCast( + result, PointerType::getUnqual(type), name); + } + return result; +} + +// The bits that differentiate stacks with normal and native frames on top + +SharkStack* SharkStack::CreateBuildAndPushFrame(SharkFunction* function, + Value* method) { + return new SharkStackWithNormalFrame(function, method); +} +SharkStack* SharkStack::CreateBuildAndPushFrame(SharkNativeWrapper* wrapper, + Value* method) { + return new SharkStackWithNativeFrame(wrapper, method); +} + +SharkStackWithNormalFrame::SharkStackWithNormalFrame(SharkFunction* function, + Value* method) + : SharkStack(function), _function(function) { + // For normal frames, the stack pointer and the method slot will + // be set during each decache, so it is not necessary to do them + // at the time the frame is created. However, we set them for + // non-PRODUCT builds to make crash dumps easier to understand. + initialize(PRODUCT_ONLY(NULL) NOT_PRODUCT(method)); +} +SharkStackWithNativeFrame::SharkStackWithNativeFrame(SharkNativeWrapper* wrp, + Value* method) + : SharkStack(wrp), _wrapper(wrp) { + initialize(method); +} + +int SharkStackWithNormalFrame::arg_size() const { + return function()->arg_size(); +} +int SharkStackWithNativeFrame::arg_size() const { + return wrapper()->arg_size(); +} + +int SharkStackWithNormalFrame::max_locals() const { + return function()->max_locals(); +} +int SharkStackWithNativeFrame::max_locals() const { + return wrapper()->arg_size(); +} + +int SharkStackWithNormalFrame::max_stack() const { + return function()->max_stack(); +} +int SharkStackWithNativeFrame::max_stack() const { + return 0; +} + +int SharkStackWithNormalFrame::max_monitors() const { + return function()->max_monitors(); +} +int SharkStackWithNativeFrame::max_monitors() const { + return wrapper()->is_synchronized() ? 1 : 0; +} + +BasicBlock* SharkStackWithNormalFrame::CreateBlock(const char* name) const { + return function()->CreateBlock(name); +} +BasicBlock* SharkStackWithNativeFrame::CreateBlock(const char* name) const { + return wrapper()->CreateBlock(name); +} + +address SharkStackWithNormalFrame::interpreter_entry_point() const { + return (address) CppInterpreter::normal_entry; +} +address SharkStackWithNativeFrame::interpreter_entry_point() const { + return (address) CppInterpreter::native_entry; +} + +#ifndef PRODUCT +void SharkStack::CreateAssertLastJavaSPIsNull() const { +#ifdef ASSERT + BasicBlock *fail = CreateBlock("assert_failed"); + BasicBlock *pass = CreateBlock("assert_ok"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ( + builder()->CreateLoad(last_Java_sp_addr()), + LLVMValue::intptr_constant(0)), + pass, fail); + + builder()->SetInsertPoint(fail); + builder()->CreateShouldNotReachHere(__FILE__, __LINE__); + builder()->CreateUnreachable(); + + builder()->SetInsertPoint(pass); +#endif // ASSERT +} +#endif // !PRODUCT diff --git a/hotspot/src/share/vm/shark/sharkStack.hpp b/hotspot/src/share/vm/shark/sharkStack.hpp new file mode 100644 index 00000000000..e31b0a3f17f --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkStack.hpp @@ -0,0 +1,290 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkFunction; +class SharkNativeWrapper; +class SharkStackWithNormalFrame; +class SharkStackWithNativeFrame; + +class SharkStack : public SharkCompileInvariants { + public: + static SharkStack* CreateBuildAndPushFrame( + SharkFunction* function, llvm::Value* method); + static SharkStack* CreateBuildAndPushFrame( + SharkNativeWrapper* wrapper, llvm::Value* method); + + protected: + SharkStack(const SharkCompileInvariants* parent) + : SharkCompileInvariants(parent) {} + + protected: + void initialize(llvm::Value* method); + + protected: + void CreateStackOverflowCheck(llvm::Value* sp); + + // Properties of the method being compiled + protected: + virtual int arg_size() const = 0; + virtual int max_locals() const = 0; + virtual int max_stack() const = 0; + virtual int max_monitors() const = 0; + + // BasicBlock creation + protected: + virtual llvm::BasicBlock* CreateBlock(const char* name = "") const = 0; + + // Interpreter entry point for bailouts + protected: + virtual address interpreter_entry_point() const = 0; + + // Interface with the Zero stack + private: + llvm::Value* zero_stack() const { + return builder()->CreateAddressOfStructEntry( + thread(), + JavaThread::zero_stack_offset(), + SharkType::zeroStack_type(), + "zero_stack"); + } + llvm::Value* stack_base() const { + return builder()->CreateValueOfStructEntry( + zero_stack(), + ZeroStack::base_offset(), + SharkType::intptr_type(), + "stack_base"); + } + llvm::Value* stack_pointer_addr() const { + return builder()->CreateAddressOfStructEntry( + zero_stack(), + ZeroStack::sp_offset(), + llvm::PointerType::getUnqual(SharkType::intptr_type()), + "stack_pointer_addr"); + } + llvm::Value* frame_pointer_addr() const { + return builder()->CreateAddressOfStructEntry( + thread(), + JavaThread::top_zero_frame_offset(), + llvm::PointerType::getUnqual(SharkType::intptr_type()), + "frame_pointer_addr"); + } + + public: + llvm::LoadInst* CreateLoadStackPointer(const char *name = "") { + return builder()->CreateLoad(stack_pointer_addr(), name); + } + llvm::StoreInst* CreateStoreStackPointer(llvm::Value* value) { + return builder()->CreateStore(value, stack_pointer_addr()); + } + llvm::LoadInst* CreateLoadFramePointer(const char *name = "") { + return builder()->CreateLoad(frame_pointer_addr(), name); + } + llvm::StoreInst* CreateStoreFramePointer(llvm::Value* value) { + return builder()->CreateStore(value, frame_pointer_addr()); + } + llvm::Value* CreatePopFrame(int result_slots); + + // Interface with the frame anchor + private: + llvm::Value* last_Java_sp_addr() const { + return builder()->CreateAddressOfStructEntry( + thread(), + JavaThread::last_Java_sp_offset(), + llvm::PointerType::getUnqual(SharkType::intptr_type()), + "last_Java_sp_addr"); + } + llvm::Value* last_Java_fp_addr() const { + return builder()->CreateAddressOfStructEntry( + thread(), + JavaThread::last_Java_fp_offset(), + llvm::PointerType::getUnqual(SharkType::intptr_type()), + "last_Java_fp_addr"); + } + + public: + void CreateSetLastJavaFrame() { + // Note that whenever _last_Java_sp != NULL other anchor fields + // must be valid. The profiler apparently depends on this. + NOT_PRODUCT(CreateAssertLastJavaSPIsNull()); + builder()->CreateStore(CreateLoadFramePointer(), last_Java_fp_addr()); + // XXX There's last_Java_pc as well, but I don't think anything uses it + // Also XXX: should we fence here? Zero doesn't... + builder()->CreateStore(CreateLoadStackPointer(), last_Java_sp_addr()); + // Also also XXX: we could probably cache the sp (and the fp we know??) + } + void CreateResetLastJavaFrame() { + builder()->CreateStore(LLVMValue::intptr_constant(0), last_Java_sp_addr()); + } + + private: + void CreateAssertLastJavaSPIsNull() const PRODUCT_RETURN; + + // Our method's frame + private: + llvm::Value* _frame; + int _extended_frame_size; + int _stack_slots_offset; + + public: + int extended_frame_size() const { + return _extended_frame_size; + } + int oopmap_frame_size() const { + return extended_frame_size() - arg_size(); + } + + // Offsets of things in the frame + private: + int _monitors_slots_offset; + int _oop_tmp_slot_offset; + int _method_slot_offset; + int _pc_slot_offset; + int _locals_slots_offset; + + public: + int stack_slots_offset() const { + return _stack_slots_offset; + } + int oop_tmp_slot_offset() const { + return _oop_tmp_slot_offset; + } + int method_slot_offset() const { + return _method_slot_offset; + } + int pc_slot_offset() const { + return _pc_slot_offset; + } + int locals_slots_offset() const { + return _locals_slots_offset; + } + int monitor_offset(int index) const { + assert(index >= 0 && index < max_monitors(), "invalid monitor index"); + return _monitors_slots_offset + + (max_monitors() - 1 - index) * frame::interpreter_frame_monitor_size(); + } + int monitor_object_offset(int index) const { + return monitor_offset(index) + + (BasicObjectLock::obj_offset_in_bytes() >> LogBytesPerWord); + } + int monitor_header_offset(int index) const { + return monitor_offset(index) + + ((BasicObjectLock::lock_offset_in_bytes() + + BasicLock::displaced_header_offset_in_bytes()) >> LogBytesPerWord); + } + + // Addresses of things in the frame + public: + llvm::Value* slot_addr(int offset, + const llvm::Type* type = NULL, + const char* name = "") const; + + llvm::Value* monitor_addr(int index) const { + return slot_addr( + monitor_offset(index), + SharkType::monitor_type(), + "monitor"); + } + llvm::Value* monitor_object_addr(int index) const { + return slot_addr( + monitor_object_offset(index), + SharkType::oop_type(), + "object_addr"); + } + llvm::Value* monitor_header_addr(int index) const { + return slot_addr( + monitor_header_offset(index), + SharkType::intptr_type(), + "displaced_header_addr"); + } + + // oopmap helpers + public: + static int oopmap_slot_munge(int offset) { + return offset << (LogBytesPerWord - LogBytesPerInt); + } + static VMReg slot2reg(int offset) { + return VMRegImpl::stack2reg(oopmap_slot_munge(offset)); + } +}; + +class SharkStackWithNormalFrame : public SharkStack { + friend class SharkStack; + + protected: + SharkStackWithNormalFrame(SharkFunction* function, llvm::Value* method); + + private: + SharkFunction* _function; + + private: + SharkFunction* function() const { + return _function; + } + + // Properties of the method being compiled + private: + int arg_size() const; + int max_locals() const; + int max_stack() const; + int max_monitors() const; + + // BasicBlock creation + private: + llvm::BasicBlock* CreateBlock(const char* name = "") const; + + // Interpreter entry point for bailouts + private: + address interpreter_entry_point() const; +}; + +class SharkStackWithNativeFrame : public SharkStack { + friend class SharkStack; + + protected: + SharkStackWithNativeFrame(SharkNativeWrapper* wrapper, llvm::Value* method); + + private: + SharkNativeWrapper* _wrapper; + + private: + SharkNativeWrapper* wrapper() const { + return _wrapper; + } + + // Properties of the method being compiled + private: + int arg_size() const; + int max_locals() const; + int max_stack() const; + int max_monitors() const; + + // BasicBlock creation + private: + llvm::BasicBlock* CreateBlock(const char* name = "") const; + + // Interpreter entry point for bailouts + private: + address interpreter_entry_point() const; +}; diff --git a/hotspot/src/share/vm/shark/sharkState.cpp b/hotspot/src/share/vm/shark/sharkState.cpp new file mode 100644 index 00000000000..fd6283d0f4e --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkState.cpp @@ -0,0 +1,389 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkState.cpp.incl" + +using namespace llvm; + +void SharkState::initialize(const SharkState *state) { + _locals = NEW_RESOURCE_ARRAY(SharkValue*, max_locals()); + _stack = NEW_RESOURCE_ARRAY(SharkValue*, max_stack()); + + NOT_PRODUCT(memset(_locals, 23, max_locals() * sizeof(SharkValue *))); + NOT_PRODUCT(memset(_stack, 23, max_stack() * sizeof(SharkValue *))); + _sp = _stack; + + if (state) { + for (int i = 0; i < max_locals(); i++) { + SharkValue *value = state->local(i); + if (value) + value = value->clone(); + set_local(i, value); + } + + for (int i = state->stack_depth() - 1; i >= 0; i--) { + SharkValue *value = state->stack(i); + if (value) + value = value->clone(); + push(value); + } + } + + set_num_monitors(state ? state->num_monitors() : 0); +} + +bool SharkState::equal_to(SharkState *other) { + if (target() != other->target()) + return false; + + if (method() != other->method()) + return false; + + if (oop_tmp() != other->oop_tmp()) + return false; + + if (max_locals() != other->max_locals()) + return false; + + if (stack_depth() != other->stack_depth()) + return false; + + if (num_monitors() != other->num_monitors()) + return false; + + if (has_safepointed() != other->has_safepointed()) + return false; + + // Local variables + for (int i = 0; i < max_locals(); i++) { + SharkValue *value = local(i); + SharkValue *other_value = other->local(i); + + if (value == NULL) { + if (other_value != NULL) + return false; + } + else { + if (other_value == NULL) + return false; + + if (!value->equal_to(other_value)) + return false; + } + } + + // Expression stack + for (int i = 0; i < stack_depth(); i++) { + SharkValue *value = stack(i); + SharkValue *other_value = other->stack(i); + + if (value == NULL) { + if (other_value != NULL) + return false; + } + else { + if (other_value == NULL) + return false; + + if (!value->equal_to(other_value)) + return false; + } + } + + return true; +} + +void SharkState::merge(SharkState* other, + BasicBlock* other_block, + BasicBlock* this_block) { + // Method + Value *this_method = this->method(); + Value *other_method = other->method(); + if (this_method != other_method) { + PHINode *phi = builder()->CreatePHI(SharkType::methodOop_type(), "method"); + phi->addIncoming(this_method, this_block); + phi->addIncoming(other_method, other_block); + set_method(phi); + } + + // Temporary oop slot + Value *this_oop_tmp = this->oop_tmp(); + Value *other_oop_tmp = other->oop_tmp(); + if (this_oop_tmp != other_oop_tmp) { + assert(this_oop_tmp && other_oop_tmp, "can't merge NULL with non-NULL"); + PHINode *phi = builder()->CreatePHI(SharkType::oop_type(), "oop_tmp"); + phi->addIncoming(this_oop_tmp, this_block); + phi->addIncoming(other_oop_tmp, other_block); + set_oop_tmp(phi); + } + + // Monitors + assert(this->num_monitors() == other->num_monitors(), "should be"); + + // Local variables + assert(this->max_locals() == other->max_locals(), "should be"); + for (int i = 0; i < max_locals(); i++) { + SharkValue *this_value = this->local(i); + SharkValue *other_value = other->local(i); + assert((this_value == NULL) == (other_value == NULL), "should be"); + if (this_value != NULL) { + char name[18]; + snprintf(name, sizeof(name), "local_%d_", i); + set_local(i, this_value->merge( + builder(), other_value, other_block, this_block, name)); + } + } + + // Expression stack + assert(this->stack_depth() == other->stack_depth(), "should be"); + for (int i = 0; i < stack_depth(); i++) { + SharkValue *this_value = this->stack(i); + SharkValue *other_value = other->stack(i); + assert((this_value == NULL) == (other_value == NULL), "should be"); + if (this_value != NULL) { + char name[18]; + snprintf(name, sizeof(name), "stack_%d_", i); + set_stack(i, this_value->merge( + builder(), other_value, other_block, this_block, name)); + } + } + + // Safepointed status + set_has_safepointed(this->has_safepointed() && other->has_safepointed()); +} + +void SharkState::replace_all(SharkValue* old_value, SharkValue* new_value) { + // Local variables + for (int i = 0; i < max_locals(); i++) { + if (local(i) == old_value) + set_local(i, new_value); + } + + // Expression stack + for (int i = 0; i < stack_depth(); i++) { + if (stack(i) == old_value) + set_stack(i, new_value); + } +} + +SharkNormalEntryState::SharkNormalEntryState(SharkTopLevelBlock* block, + Value* method) + : SharkState(block) { + assert(!block->stack_depth_at_entry(), "entry block shouldn't have stack"); + + // Local variables + for (int i = 0; i < max_locals(); i++) { + ciType *type = block->local_type_at_entry(i); + + SharkValue *value = NULL; + switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: + if (i >= arg_size()) { + ShouldNotReachHere(); + } + value = SharkValue::create_generic(type, NULL, i == 0 && !is_static()); + break; + + case ciTypeFlow::StateVector::T_NULL: + value = SharkValue::null(); + break; + + case ciTypeFlow::StateVector::T_BOTTOM: + break; + + case ciTypeFlow::StateVector::T_LONG2: + case ciTypeFlow::StateVector::T_DOUBLE2: + break; + + default: + ShouldNotReachHere(); + } + set_local(i, value); + } + SharkNormalEntryCacher(block->function(), method).scan(this); +} + +SharkOSREntryState::SharkOSREntryState(SharkTopLevelBlock* block, + Value* method, + Value* osr_buf) + : SharkState(block) { + assert(!block->stack_depth_at_entry(), "entry block shouldn't have stack"); + set_num_monitors(block->ciblock()->monitor_count()); + + // Local variables + for (int i = 0; i < max_locals(); i++) { + ciType *type = block->local_type_at_entry(i); + + SharkValue *value = NULL; + switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: + value = SharkValue::create_generic(type, NULL, false); + break; + + case ciTypeFlow::StateVector::T_NULL: + value = SharkValue::null(); + break; + + case ciTypeFlow::StateVector::T_BOTTOM: + break; + + case ciTypeFlow::StateVector::T_LONG2: + case ciTypeFlow::StateVector::T_DOUBLE2: + break; + + default: + ShouldNotReachHere(); + } + set_local(i, value); + } + SharkOSREntryCacher(block->function(), method, osr_buf).scan(this); +} + +SharkPHIState::SharkPHIState(SharkTopLevelBlock* block) + : SharkState(block), _block(block) { + BasicBlock *saved_insert_point = builder()->GetInsertBlock(); + builder()->SetInsertPoint(block->entry_block()); + char name[18]; + + // Method + set_method(builder()->CreatePHI(SharkType::methodOop_type(), "method")); + + // Local variables + for (int i = 0; i < max_locals(); i++) { + ciType *type = block->local_type_at_entry(i); + if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { + // XXX we could do all kinds of clever stuff here + type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? + } + + SharkValue *value = NULL; + switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: + snprintf(name, sizeof(name), "local_%d_", i); + value = SharkValue::create_phi( + type, builder()->CreatePHI(SharkType::to_stackType(type), name)); + break; + + case T_ADDRESS: + value = SharkValue::address_constant(type->as_return_address()->bci()); + break; + + case ciTypeFlow::StateVector::T_BOTTOM: + break; + + case ciTypeFlow::StateVector::T_LONG2: + case ciTypeFlow::StateVector::T_DOUBLE2: + break; + + default: + ShouldNotReachHere(); + } + set_local(i, value); + } + + // Expression stack + for (int i = 0; i < block->stack_depth_at_entry(); i++) { + ciType *type = block->stack_type_at_entry(i); + if (type->basic_type() == (BasicType) ciTypeFlow::StateVector::T_NULL) { + // XXX we could do all kinds of clever stuff here + type = ciType::make(T_OBJECT); // XXX what about T_ARRAY? + } + + SharkValue *value = NULL; + switch (type->basic_type()) { + case T_INT: + case T_LONG: + case T_FLOAT: + case T_DOUBLE: + case T_OBJECT: + case T_ARRAY: + snprintf(name, sizeof(name), "stack_%d_", i); + value = SharkValue::create_phi( + type, builder()->CreatePHI(SharkType::to_stackType(type), name)); + break; + + case T_ADDRESS: + value = SharkValue::address_constant(type->as_return_address()->bci()); + break; + + case ciTypeFlow::StateVector::T_LONG2: + case ciTypeFlow::StateVector::T_DOUBLE2: + break; + + default: + ShouldNotReachHere(); + } + push(value); + } + + // Monitors + set_num_monitors(block->ciblock()->monitor_count()); + + builder()->SetInsertPoint(saved_insert_point); +} + +void SharkPHIState::add_incoming(SharkState* incoming_state) { + BasicBlock *predecessor = builder()->GetInsertBlock(); + + // Method + ((PHINode *) method())->addIncoming(incoming_state->method(), predecessor); + + // Local variables + for (int i = 0; i < max_locals(); i++) { + if (local(i) != NULL) + local(i)->addIncoming(incoming_state->local(i), predecessor); + } + + // Expression stack + int stack_depth = block()->stack_depth_at_entry(); + assert(stack_depth == incoming_state->stack_depth(), "should be"); + for (int i = 0; i < stack_depth; i++) { + assert((stack(i) == NULL) == (incoming_state->stack(i) == NULL), "oops"); + if (stack(i)) + stack(i)->addIncoming(incoming_state->stack(i), predecessor); + } + + // Monitors + assert(num_monitors() == incoming_state->num_monitors(), "should be"); + + // Temporary oop slot + assert(oop_tmp() == incoming_state->oop_tmp(), "should be"); +} diff --git a/hotspot/src/share/vm/shark/sharkState.hpp b/hotspot/src/share/vm/shark/sharkState.hpp new file mode 100644 index 00000000000..85d8ea70c49 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkState.hpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkState : public SharkTargetInvariants { + public: + SharkState(const SharkTargetInvariants* parent) + : SharkTargetInvariants(parent), + _method(NULL), + _oop_tmp(NULL), + _has_safepointed(false) { initialize(NULL); } + + SharkState(const SharkState* state) + : SharkTargetInvariants(state), + _method(state->_method), + _oop_tmp(state->_oop_tmp), + _has_safepointed(state->_has_safepointed) { initialize(state); } + + private: + void initialize(const SharkState* state); + + private: + llvm::Value* _method; + SharkValue** _locals; + SharkValue** _stack; + SharkValue** _sp; + int _num_monitors; + llvm::Value* _oop_tmp; + bool _has_safepointed; + + // Method + public: + llvm::Value** method_addr() { + return &_method; + } + llvm::Value* method() const { + return _method; + } + protected: + void set_method(llvm::Value* method) { + _method = method; + } + + // Local variables + public: + SharkValue** local_addr(int index) const { + assert(index >= 0 && index < max_locals(), "bad local variable index"); + return &_locals[index]; + } + SharkValue* local(int index) const { + return *local_addr(index); + } + void set_local(int index, SharkValue* value) { + *local_addr(index) = value; + } + + // Expression stack + public: + SharkValue** stack_addr(int slot) const { + assert(slot >= 0 && slot < stack_depth(), "bad stack slot"); + return &_sp[-(slot + 1)]; + } + SharkValue* stack(int slot) const { + return *stack_addr(slot); + } + protected: + void set_stack(int slot, SharkValue* value) { + *stack_addr(slot) = value; + } + public: + int stack_depth() const { + return _sp - _stack; + } + void push(SharkValue* value) { + assert(stack_depth() < max_stack(), "stack overrun"); + *(_sp++) = value; + } + SharkValue* pop() { + assert(stack_depth() > 0, "stack underrun"); + return *(--_sp); + } + + // Monitors + public: + int num_monitors() const { + return _num_monitors; + } + void set_num_monitors(int num_monitors) { + _num_monitors = num_monitors; + } + + // Temporary oop slot + public: + llvm::Value** oop_tmp_addr() { + return &_oop_tmp; + } + llvm::Value* oop_tmp() const { + return _oop_tmp; + } + void set_oop_tmp(llvm::Value* oop_tmp) { + _oop_tmp = oop_tmp; + } + + // Safepointed status + public: + bool has_safepointed() const { + return _has_safepointed; + } + void set_has_safepointed(bool has_safepointed) { + _has_safepointed = has_safepointed; + } + + // Comparison + public: + bool equal_to(SharkState* other); + + // Copy and merge + public: + SharkState* copy() const { + return new SharkState(this); + } + void merge(SharkState* other, + llvm::BasicBlock* other_block, + llvm::BasicBlock* this_block); + + // Value replacement + public: + void replace_all(SharkValue* old_value, SharkValue* new_value); +}; + +class SharkTopLevelBlock; + +// SharkNormalEntryState objects are used to create the state +// that the method will be entered with for a normal invocation. +class SharkNormalEntryState : public SharkState { + public: + SharkNormalEntryState(SharkTopLevelBlock* block, + llvm::Value* method); +}; + +// SharkOSREntryState objects are used to create the state +// that the method will be entered with for an OSR invocation. +class SharkOSREntryState : public SharkState { + public: + SharkOSREntryState(SharkTopLevelBlock* block, + llvm::Value* method, + llvm::Value* osr_buf); +}; + +// SharkPHIState objects are used to manage the entry state +// for blocks with more than one entry path or for blocks +// entered from blocks that will be compiled later. +class SharkPHIState : public SharkState { + public: + SharkPHIState(SharkTopLevelBlock* block); + + private: + SharkTopLevelBlock* _block; + + private: + SharkTopLevelBlock* block() const { + return _block; + } + + public: + void add_incoming(SharkState* incoming_state); +}; diff --git a/hotspot/src/share/vm/shark/sharkStateScanner.cpp b/hotspot/src/share/vm/shark/sharkStateScanner.cpp new file mode 100644 index 00000000000..de588b19bcf --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkStateScanner.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkStateScanner.cpp.incl" + +using namespace llvm; + +void SharkStateScanner::scan(SharkState* state) { + start_frame(); + + // Expression stack + stack_integrity_checks(state); + start_stack(state->stack_depth()); + for (int i = state->stack_depth() - 1; i >= 0; i--) { + process_stack_slot( + i, + state->stack_addr(i), + stack()->stack_slots_offset() + + i + max_stack() - state->stack_depth()); + } + end_stack(); + + // Monitors + start_monitors(state->num_monitors()); + for (int i = 0; i < state->num_monitors(); i++) { + process_monitor( + i, + stack()->monitor_offset(i), + stack()->monitor_object_offset(i)); + } + end_monitors(); + + // Frame header + start_frame_header(); + process_oop_tmp_slot( + state->oop_tmp_addr(), stack()->oop_tmp_slot_offset()); + process_method_slot(state->method_addr(), stack()->method_slot_offset()); + process_pc_slot(stack()->pc_slot_offset()); + end_frame_header(); + + // Local variables + locals_integrity_checks(state); + start_locals(); + for (int i = 0; i < max_locals(); i++) { + process_local_slot( + i, + state->local_addr(i), + stack()->locals_slots_offset() + max_locals() - 1 - i); + } + end_locals(); + + end_frame(); +} + +#ifndef PRODUCT +void SharkStateScanner::stack_integrity_checks(SharkState* state) { + for (int i = 0; i < state->stack_depth(); i++) { + if (state->stack(i)) { + if (state->stack(i)->is_two_word()) + assert(state->stack(i - 1) == NULL, "should be"); + } + else { + assert(state->stack(i + 1)->is_two_word(), "should be"); + } + } +} + +void SharkStateScanner::locals_integrity_checks(SharkState* state) { + for (int i = 0; i < max_locals(); i++) { + if (state->local(i)) { + if (state->local(i)->is_two_word()) + assert(state->local(i + 1) == NULL, "should be"); + } + } +} +#endif // !PRODUCT diff --git a/hotspot/src/share/vm/shark/sharkStateScanner.hpp b/hotspot/src/share/vm/shark/sharkStateScanner.hpp new file mode 100644 index 00000000000..74c1294e6ab --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkStateScanner.hpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkState; + +class SharkStateScanner : public SharkTargetInvariants { + protected: + SharkStateScanner(SharkFunction* function) + : SharkTargetInvariants(function), _stack(function->stack()) {} + + private: + SharkStack* _stack; + + protected: + SharkStack* stack() const { + return _stack; + } + + // Scan the frame + public: + void scan(SharkState* state); + + // Callbacks + // Note that the offsets supplied to the various process_* callbacks + // are specified in wordSize words from the frame's unextended_sp. + protected: + virtual void start_frame() {} + + virtual void start_stack(int stack_depth) {} + virtual void process_stack_slot(int index, SharkValue** value, int offset) {} + virtual void end_stack() {} + + virtual void start_monitors(int num_monitors) {} + virtual void process_monitor(int index, int box_offset, int obj_offset) {} + virtual void end_monitors() {} + + virtual void start_frame_header() {} + virtual void process_oop_tmp_slot(llvm::Value** value, int offset) {} + virtual void process_method_slot(llvm::Value** value, int offset) {} + virtual void process_pc_slot(int offset) {} + virtual void end_frame_header() {} + + virtual void start_locals() {} + virtual void process_local_slot(int index, SharkValue** value, int offset) {} + virtual void end_locals() {} + + virtual void end_frame() {} + + // Integrity checks + private: + void stack_integrity_checks(SharkState* state) PRODUCT_RETURN; + void locals_integrity_checks(SharkState* state) PRODUCT_RETURN; +}; diff --git a/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp b/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp new file mode 100644 index 00000000000..5e93ca587c6 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp @@ -0,0 +1,1995 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkTopLevelBlock.cpp.incl" + +using namespace llvm; + +void SharkTopLevelBlock::scan_for_traps() { + // If typeflow found a trap then don't scan past it + int limit_bci = ciblock()->has_trap() ? ciblock()->trap_bci() : limit(); + + // Scan the bytecode for traps that are always hit + iter()->reset_to_bci(start()); + while (iter()->next_bci() < limit_bci) { + iter()->next(); + + ciField *field; + ciMethod *method; + ciInstanceKlass *klass; + bool will_link; + bool is_field; + + switch (bc()) { + case Bytecodes::_ldc: + case Bytecodes::_ldc_w: + if (!SharkConstant::for_ldc(iter())->is_loaded()) { + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret), bci()); + return; + } + break; + + case Bytecodes::_getfield: + case Bytecodes::_getstatic: + case Bytecodes::_putfield: + case Bytecodes::_putstatic: + field = iter()->get_field(will_link); + assert(will_link, "typeflow responsibility"); + is_field = (bc() == Bytecodes::_getfield || bc() == Bytecodes::_putfield); + + // If the bytecode does not match the field then bail out to + // the interpreter to throw an IncompatibleClassChangeError + if (is_field == field->is_static()) { + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_unhandled, + Deoptimization::Action_none), bci()); + return; + } + + // Bail out if we are trying to access a static variable + // before the class initializer has completed. + if (!is_field && !field->holder()->is_initialized()) { + if (!static_field_ok_in_clinit(field)) { + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret), bci()); + return; + } + } + break; + + case Bytecodes::_invokestatic: + case Bytecodes::_invokespecial: + case Bytecodes::_invokevirtual: + case Bytecodes::_invokeinterface: + method = iter()->get_method(will_link); + assert(will_link, "typeflow responsibility"); + + if (!method->holder()->is_linked()) { + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret), bci()); + return; + } + + if (bc() == Bytecodes::_invokevirtual) { + klass = ciEnv::get_instance_klass_for_declared_method_holder( + iter()->get_declared_method_holder()); + if (!klass->is_linked()) { + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret), bci()); + return; + } + } + break; + + case Bytecodes::_new: + klass = iter()->get_klass(will_link)->as_instance_klass(); + assert(will_link, "typeflow responsibility"); + + // Bail out if the class is unloaded + if (iter()->is_unresolved_klass() || !klass->is_initialized()) { + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret), bci()); + return; + } + + // Bail out if the class cannot be instantiated + if (klass->is_abstract() || klass->is_interface() || + klass->name() == ciSymbol::java_lang_Class()) { + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_unhandled, + Deoptimization::Action_reinterpret), bci()); + return; + } + break; + } + } + + // Trap if typeflow trapped (and we didn't before) + if (ciblock()->has_trap()) { + set_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_unloaded, + Deoptimization::Action_reinterpret, + ciblock()->trap_index()), ciblock()->trap_bci()); + return; + } +} + +bool SharkTopLevelBlock::static_field_ok_in_clinit(ciField* field) { + assert(field->is_static(), "should be"); + + // This code is lifted pretty much verbatim from C2's + // Parse::static_field_ok_in_clinit() in parse3.cpp. + bool access_OK = false; + if (target()->holder()->is_subclass_of(field->holder())) { + if (target()->is_static()) { + if (target()->name() == ciSymbol::class_initializer_name()) { + // It's OK to access static fields from the class initializer + access_OK = true; + } + } + else { + if (target()->name() == ciSymbol::object_initializer_name()) { + // It's also OK to access static fields inside a constructor, + // because any thread calling the constructor must first have + // synchronized on the class by executing a "new" bytecode. + access_OK = true; + } + } + } + return access_OK; +} + +SharkState* SharkTopLevelBlock::entry_state() { + if (_entry_state == NULL) { + assert(needs_phis(), "should do"); + _entry_state = new SharkPHIState(this); + } + return _entry_state; +} + +void SharkTopLevelBlock::add_incoming(SharkState* incoming_state) { + if (needs_phis()) { + ((SharkPHIState *) entry_state())->add_incoming(incoming_state); + } + else if (_entry_state == NULL) { + _entry_state = incoming_state; + } + else { + assert(entry_state()->equal_to(incoming_state), "should be"); + } +} + +void SharkTopLevelBlock::enter(SharkTopLevelBlock* predecessor, + bool is_exception) { + // This block requires phis: + // - if it is entered more than once + // - if it is an exception handler, because in which + // case we assume it's entered more than once. + // - if the predecessor will be compiled after this + // block, in which case we can't simple propagate + // the state forward. + if (!needs_phis() && + (entered() || + is_exception || + (predecessor && predecessor->index() >= index()))) + _needs_phis = true; + + // Recurse into the tree + if (!entered()) { + _entered = true; + + scan_for_traps(); + if (!has_trap()) { + for (int i = 0; i < num_successors(); i++) { + successor(i)->enter(this, false); + } + } + compute_exceptions(); + for (int i = 0; i < num_exceptions(); i++) { + SharkTopLevelBlock *handler = exception(i); + if (handler) + handler->enter(this, true); + } + } +} + +void SharkTopLevelBlock::initialize() { + char name[28]; + snprintf(name, sizeof(name), + "bci_%d%s", + start(), is_backedge_copy() ? "_backedge_copy" : ""); + _entry_block = function()->CreateBlock(name); +} + +void SharkTopLevelBlock::decache_for_Java_call(ciMethod *callee) { + SharkJavaCallDecacher(function(), bci(), callee).scan(current_state()); + for (int i = 0; i < callee->arg_size(); i++) + xpop(); +} + +void SharkTopLevelBlock::cache_after_Java_call(ciMethod *callee) { + if (callee->return_type()->size()) { + ciType *type; + switch (callee->return_type()->basic_type()) { + case T_BOOLEAN: + case T_BYTE: + case T_CHAR: + case T_SHORT: + type = ciType::make(T_INT); + break; + + default: + type = callee->return_type(); + } + + push(SharkValue::create_generic(type, NULL, false)); + } + SharkJavaCallCacher(function(), callee).scan(current_state()); +} + +void SharkTopLevelBlock::decache_for_VM_call() { + SharkVMCallDecacher(function(), bci()).scan(current_state()); +} + +void SharkTopLevelBlock::cache_after_VM_call() { + SharkVMCallCacher(function()).scan(current_state()); +} + +void SharkTopLevelBlock::decache_for_trap() { + SharkTrapDecacher(function(), bci()).scan(current_state()); +} + +void SharkTopLevelBlock::emit_IR() { + builder()->SetInsertPoint(entry_block()); + + // Parse the bytecode + parse_bytecode(start(), limit()); + + // If this block falls through to the next then it won't have been + // terminated by a bytecode and we have to add the branch ourselves + if (falls_through() && !has_trap()) + do_branch(ciTypeFlow::FALL_THROUGH); +} + +SharkTopLevelBlock* SharkTopLevelBlock::bci_successor(int bci) const { + // XXX now with Linear Search Technology (tm) + for (int i = 0; i < num_successors(); i++) { + ciTypeFlow::Block *successor = ciblock()->successors()->at(i); + if (successor->start() == bci) + return function()->block(successor->pre_order()); + } + ShouldNotReachHere(); +} + +void SharkTopLevelBlock::do_zero_check(SharkValue *value) { + if (value->is_phi() && value->as_phi()->all_incomers_zero_checked()) { + function()->add_deferred_zero_check(this, value); + } + else { + BasicBlock *continue_block = function()->CreateBlock("not_zero"); + SharkState *saved_state = current_state(); + set_current_state(saved_state->copy()); + zero_check_value(value, continue_block); + builder()->SetInsertPoint(continue_block); + set_current_state(saved_state); + } + + value->set_zero_checked(true); +} + +void SharkTopLevelBlock::do_deferred_zero_check(SharkValue* value, + int bci, + SharkState* saved_state, + BasicBlock* continue_block) { + if (value->as_phi()->all_incomers_zero_checked()) { + builder()->CreateBr(continue_block); + } + else { + iter()->force_bci(start()); + set_current_state(saved_state); + zero_check_value(value, continue_block); + } +} + +void SharkTopLevelBlock::zero_check_value(SharkValue* value, + BasicBlock* continue_block) { + BasicBlock *zero_block = builder()->CreateBlock(continue_block, "zero"); + + Value *a, *b; + switch (value->basic_type()) { + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: + a = value->jint_value(); + b = LLVMValue::jint_constant(0); + break; + case T_LONG: + a = value->jlong_value(); + b = LLVMValue::jlong_constant(0); + break; + case T_OBJECT: + case T_ARRAY: + a = value->jobject_value(); + b = LLVMValue::LLVMValue::null(); + break; + default: + tty->print_cr("Unhandled type %s", type2name(value->basic_type())); + ShouldNotReachHere(); + } + + builder()->CreateCondBr( + builder()->CreateICmpNE(a, b), continue_block, zero_block); + + builder()->SetInsertPoint(zero_block); + if (value->is_jobject()) { + call_vm( + builder()->throw_NullPointerException(), + builder()->CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) __FILE__), + PointerType::getUnqual(SharkType::jbyte_type())), + LLVMValue::jint_constant(__LINE__), + EX_CHECK_NONE); + } + else { + call_vm( + builder()->throw_ArithmeticException(), + builder()->CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) __FILE__), + PointerType::getUnqual(SharkType::jbyte_type())), + LLVMValue::jint_constant(__LINE__), + EX_CHECK_NONE); + } + + Value *pending_exception = get_pending_exception(); + clear_pending_exception(); + handle_exception(pending_exception, EX_CHECK_FULL); +} + +void SharkTopLevelBlock::check_bounds(SharkValue* array, SharkValue* index) { + BasicBlock *out_of_bounds = function()->CreateBlock("out_of_bounds"); + BasicBlock *in_bounds = function()->CreateBlock("in_bounds"); + + Value *length = builder()->CreateArrayLength(array->jarray_value()); + // we use an unsigned comparison to catch negative values + builder()->CreateCondBr( + builder()->CreateICmpULT(index->jint_value(), length), + in_bounds, out_of_bounds); + + builder()->SetInsertPoint(out_of_bounds); + SharkState *saved_state = current_state()->copy(); + + call_vm( + builder()->throw_ArrayIndexOutOfBoundsException(), + builder()->CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) __FILE__), + PointerType::getUnqual(SharkType::jbyte_type())), + LLVMValue::jint_constant(__LINE__), + index->jint_value(), + EX_CHECK_NONE); + + Value *pending_exception = get_pending_exception(); + clear_pending_exception(); + handle_exception(pending_exception, EX_CHECK_FULL); + + set_current_state(saved_state); + + builder()->SetInsertPoint(in_bounds); +} + +void SharkTopLevelBlock::check_pending_exception(int action) { + assert(action & EAM_CHECK, "should be"); + + BasicBlock *exception = function()->CreateBlock("exception"); + BasicBlock *no_exception = function()->CreateBlock("no_exception"); + + Value *pending_exception = get_pending_exception(); + builder()->CreateCondBr( + builder()->CreateICmpEQ(pending_exception, LLVMValue::null()), + no_exception, exception); + + builder()->SetInsertPoint(exception); + SharkState *saved_state = current_state()->copy(); + if (action & EAM_MONITOR_FUDGE) { + // The top monitor is marked live, but the exception was thrown + // while setting it up so we need to mark it dead before we enter + // any exception handlers as they will not expect it to be there. + set_num_monitors(num_monitors() - 1); + action ^= EAM_MONITOR_FUDGE; + } + clear_pending_exception(); + handle_exception(pending_exception, action); + set_current_state(saved_state); + + builder()->SetInsertPoint(no_exception); +} + +void SharkTopLevelBlock::compute_exceptions() { + ciExceptionHandlerStream str(target(), start()); + + int exc_count = str.count(); + _exc_handlers = new GrowableArray(exc_count); + _exceptions = new GrowableArray(exc_count); + + int index = 0; + for (; !str.is_done(); str.next()) { + ciExceptionHandler *handler = str.handler(); + if (handler->handler_bci() == -1) + break; + _exc_handlers->append(handler); + + // Try and get this exception's handler from typeflow. We should + // do it this way always, really, except that typeflow sometimes + // doesn't record exceptions, even loaded ones, and sometimes it + // returns them with a different handler bci. Why??? + SharkTopLevelBlock *block = NULL; + ciInstanceKlass* klass; + if (handler->is_catch_all()) { + klass = java_lang_Throwable_klass(); + } + else { + klass = handler->catch_klass(); + } + for (int i = 0; i < ciblock()->exceptions()->length(); i++) { + if (klass == ciblock()->exc_klasses()->at(i)) { + block = function()->block(ciblock()->exceptions()->at(i)->pre_order()); + if (block->start() == handler->handler_bci()) + break; + else + block = NULL; + } + } + + // If typeflow let us down then try and figure it out ourselves + if (block == NULL) { + for (int i = 0; i < function()->block_count(); i++) { + SharkTopLevelBlock *candidate = function()->block(i); + if (candidate->start() == handler->handler_bci()) { + if (block != NULL) { + NOT_PRODUCT(warning("there may be trouble ahead")); + block = NULL; + break; + } + block = candidate; + } + } + } + _exceptions->append(block); + } +} + +void SharkTopLevelBlock::handle_exception(Value* exception, int action) { + if (action & EAM_HANDLE && num_exceptions() != 0) { + // Clear the stack and push the exception onto it + while (xstack_depth()) + pop(); + push(SharkValue::create_jobject(exception, true)); + + // Work out how many options we have to check + bool has_catch_all = exc_handler(num_exceptions() - 1)->is_catch_all(); + int num_options = num_exceptions(); + if (has_catch_all) + num_options--; + + // Marshal any non-catch-all handlers + if (num_options > 0) { + bool all_loaded = true; + for (int i = 0; i < num_options; i++) { + if (!exc_handler(i)->catch_klass()->is_loaded()) { + all_loaded = false; + break; + } + } + + if (all_loaded) + marshal_exception_fast(num_options); + else + marshal_exception_slow(num_options); + } + + // Install the catch-all handler, if present + if (has_catch_all) { + SharkTopLevelBlock* handler = this->exception(num_options); + assert(handler != NULL, "catch-all handler cannot be unloaded"); + + builder()->CreateBr(handler->entry_block()); + handler->add_incoming(current_state()); + return; + } + } + + // No exception handler was found; unwind and return + handle_return(T_VOID, exception); +} + +void SharkTopLevelBlock::marshal_exception_fast(int num_options) { + Value *exception_klass = builder()->CreateValueOfStructEntry( + xstack(0)->jobject_value(), + in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::oop_type(), + "exception_klass"); + + for (int i = 0; i < num_options; i++) { + Value *check_klass = + builder()->CreateInlineOop(exc_handler(i)->catch_klass()); + + BasicBlock *not_exact = function()->CreateBlock("not_exact"); + BasicBlock *not_subtype = function()->CreateBlock("not_subtype"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ(check_klass, exception_klass), + handler_for_exception(i), not_exact); + + builder()->SetInsertPoint(not_exact); + builder()->CreateCondBr( + builder()->CreateICmpNE( + builder()->CreateCall2( + builder()->is_subtype_of(), check_klass, exception_klass), + LLVMValue::jbyte_constant(0)), + handler_for_exception(i), not_subtype); + + builder()->SetInsertPoint(not_subtype); + } +} + +void SharkTopLevelBlock::marshal_exception_slow(int num_options) { + int *indexes = NEW_RESOURCE_ARRAY(int, num_options); + for (int i = 0; i < num_options; i++) + indexes[i] = exc_handler(i)->catch_klass_index(); + + Value *index = call_vm( + builder()->find_exception_handler(), + builder()->CreateInlineData( + indexes, + num_options * sizeof(int), + PointerType::getUnqual(SharkType::jint_type())), + LLVMValue::jint_constant(num_options), + EX_CHECK_NO_CATCH); + + BasicBlock *no_handler = function()->CreateBlock("no_handler"); + SwitchInst *switchinst = builder()->CreateSwitch( + index, no_handler, num_options); + + for (int i = 0; i < num_options; i++) { + switchinst->addCase( + LLVMValue::jint_constant(i), + handler_for_exception(i)); + } + + builder()->SetInsertPoint(no_handler); +} + +BasicBlock* SharkTopLevelBlock::handler_for_exception(int index) { + SharkTopLevelBlock *successor = this->exception(index); + if (successor) { + successor->add_incoming(current_state()); + return successor->entry_block(); + } + else { + return make_trap( + exc_handler(index)->handler_bci(), + Deoptimization::make_trap_request( + Deoptimization::Reason_unhandled, + Deoptimization::Action_reinterpret)); + } +} + +void SharkTopLevelBlock::maybe_add_safepoint() { + if (current_state()->has_safepointed()) + return; + + BasicBlock *orig_block = builder()->GetInsertBlock(); + SharkState *orig_state = current_state()->copy(); + + BasicBlock *do_safepoint = function()->CreateBlock("do_safepoint"); + BasicBlock *safepointed = function()->CreateBlock("safepointed"); + + Value *state = builder()->CreateLoad( + builder()->CreateIntToPtr( + LLVMValue::intptr_constant( + (intptr_t) SafepointSynchronize::address_of_state()), + PointerType::getUnqual(SharkType::jint_type())), + "state"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ( + state, + LLVMValue::jint_constant(SafepointSynchronize::_synchronizing)), + do_safepoint, safepointed); + + builder()->SetInsertPoint(do_safepoint); + call_vm(builder()->safepoint(), EX_CHECK_FULL); + BasicBlock *safepointed_block = builder()->GetInsertBlock(); + builder()->CreateBr(safepointed); + + builder()->SetInsertPoint(safepointed); + current_state()->merge(orig_state, orig_block, safepointed_block); + + current_state()->set_has_safepointed(true); +} + +void SharkTopLevelBlock::maybe_add_backedge_safepoint() { + if (current_state()->has_safepointed()) + return; + + for (int i = 0; i < num_successors(); i++) { + if (successor(i)->can_reach(this)) { + maybe_add_safepoint(); + break; + } + } +} + +bool SharkTopLevelBlock::can_reach(SharkTopLevelBlock* other) { + for (int i = 0; i < function()->block_count(); i++) + function()->block(i)->_can_reach_visited = false; + + return can_reach_helper(other); +} + +bool SharkTopLevelBlock::can_reach_helper(SharkTopLevelBlock* other) { + if (this == other) + return true; + + if (_can_reach_visited) + return false; + _can_reach_visited = true; + + if (!has_trap()) { + for (int i = 0; i < num_successors(); i++) { + if (successor(i)->can_reach_helper(other)) + return true; + } + } + + for (int i = 0; i < num_exceptions(); i++) { + SharkTopLevelBlock *handler = exception(i); + if (handler && handler->can_reach_helper(other)) + return true; + } + + return false; +} + +BasicBlock* SharkTopLevelBlock::make_trap(int trap_bci, int trap_request) { + BasicBlock *trap_block = function()->CreateBlock("trap"); + BasicBlock *orig_block = builder()->GetInsertBlock(); + builder()->SetInsertPoint(trap_block); + + int orig_bci = bci(); + iter()->force_bci(trap_bci); + + do_trap(trap_request); + + builder()->SetInsertPoint(orig_block); + iter()->force_bci(orig_bci); + + return trap_block; +} + +void SharkTopLevelBlock::do_trap(int trap_request) { + decache_for_trap(); + builder()->CreateRet( + builder()->CreateCall2( + builder()->uncommon_trap(), + thread(), + LLVMValue::jint_constant(trap_request))); +} + +void SharkTopLevelBlock::call_register_finalizer(Value *receiver) { + BasicBlock *orig_block = builder()->GetInsertBlock(); + SharkState *orig_state = current_state()->copy(); + + BasicBlock *do_call = function()->CreateBlock("has_finalizer"); + BasicBlock *done = function()->CreateBlock("done"); + + Value *klass = builder()->CreateValueOfStructEntry( + receiver, + in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::oop_type(), + "klass"); + + Value *klass_part = builder()->CreateAddressOfStructEntry( + klass, + in_ByteSize(klassOopDesc::klass_part_offset_in_bytes()), + SharkType::klass_type(), + "klass_part"); + + Value *access_flags = builder()->CreateValueOfStructEntry( + klass_part, + in_ByteSize(Klass::access_flags_offset_in_bytes()), + SharkType::jint_type(), + "access_flags"); + + builder()->CreateCondBr( + builder()->CreateICmpNE( + builder()->CreateAnd( + access_flags, + LLVMValue::jint_constant(JVM_ACC_HAS_FINALIZER)), + LLVMValue::jint_constant(0)), + do_call, done); + + builder()->SetInsertPoint(do_call); + call_vm(builder()->register_finalizer(), receiver, EX_CHECK_FULL); + BasicBlock *branch_block = builder()->GetInsertBlock(); + builder()->CreateBr(done); + + builder()->SetInsertPoint(done); + current_state()->merge(orig_state, orig_block, branch_block); +} + +void SharkTopLevelBlock::handle_return(BasicType type, Value* exception) { + assert (exception == NULL || type == T_VOID, "exception OR result, please"); + + if (num_monitors()) { + // Protect our exception across possible monitor release decaches + if (exception) + set_oop_tmp(exception); + + // We don't need to check for exceptions thrown here. If + // we're returning a value then we just carry on as normal: + // the caller will see the pending exception and handle it. + // If we're returning with an exception then that exception + // takes priority and the release_lock one will be ignored. + while (num_monitors()) + release_lock(EX_CHECK_NONE); + + // Reload the exception we're throwing + if (exception) + exception = get_oop_tmp(); + } + + if (exception) { + builder()->CreateStore(exception, pending_exception_address()); + } + + Value *result_addr = stack()->CreatePopFrame(type2size[type]); + if (type != T_VOID) { + builder()->CreateStore( + pop_result(type)->generic_value(), + builder()->CreateIntToPtr( + result_addr, + PointerType::getUnqual(SharkType::to_stackType(type)))); + } + + builder()->CreateRet(LLVMValue::jint_constant(0)); +} + +void SharkTopLevelBlock::do_arraylength() { + SharkValue *array = pop(); + check_null(array); + Value *length = builder()->CreateArrayLength(array->jarray_value()); + push(SharkValue::create_jint(length, false)); +} + +void SharkTopLevelBlock::do_aload(BasicType basic_type) { + SharkValue *index = pop(); + SharkValue *array = pop(); + + check_null(array); + check_bounds(array, index); + + Value *value = builder()->CreateLoad( + builder()->CreateArrayAddress( + array->jarray_value(), basic_type, index->jint_value())); + + const Type *stack_type = SharkType::to_stackType(basic_type); + if (value->getType() != stack_type) + value = builder()->CreateIntCast(value, stack_type, basic_type != T_CHAR); + + switch (basic_type) { + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: + push(SharkValue::create_jint(value, false)); + break; + + case T_LONG: + push(SharkValue::create_jlong(value, false)); + break; + + case T_FLOAT: + push(SharkValue::create_jfloat(value)); + break; + + case T_DOUBLE: + push(SharkValue::create_jdouble(value)); + break; + + case T_OBJECT: + // You might expect that array->type()->is_array_klass() would + // always be true, but it isn't. If ciTypeFlow detects that a + // value is always null then that value becomes an untyped null + // object. Shark doesn't presently support this, so a generic + // T_OBJECT is created. In this case we guess the type using + // the BasicType we were supplied. In reality the generated + // code will never be used, as the null value will be caught + // by the above null pointer check. + // http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=324 + push( + SharkValue::create_generic( + array->type()->is_array_klass() ? + ((ciArrayKlass *) array->type())->element_type() : + ciType::make(basic_type), + value, false)); + break; + + default: + tty->print_cr("Unhandled type %s", type2name(basic_type)); + ShouldNotReachHere(); + } +} + +void SharkTopLevelBlock::do_astore(BasicType basic_type) { + SharkValue *svalue = pop(); + SharkValue *index = pop(); + SharkValue *array = pop(); + + check_null(array); + check_bounds(array, index); + + Value *value; + switch (basic_type) { + case T_BYTE: + case T_CHAR: + case T_SHORT: + case T_INT: + value = svalue->jint_value(); + break; + + case T_LONG: + value = svalue->jlong_value(); + break; + + case T_FLOAT: + value = svalue->jfloat_value(); + break; + + case T_DOUBLE: + value = svalue->jdouble_value(); + break; + + case T_OBJECT: + value = svalue->jobject_value(); + // XXX assignability check + break; + + default: + tty->print_cr("Unhandled type %s", type2name(basic_type)); + ShouldNotReachHere(); + } + + const Type *array_type = SharkType::to_arrayType(basic_type); + if (value->getType() != array_type) + value = builder()->CreateIntCast(value, array_type, basic_type != T_CHAR); + + Value *addr = builder()->CreateArrayAddress( + array->jarray_value(), basic_type, index->jint_value(), "addr"); + + builder()->CreateStore(value, addr); + + if (basic_type == T_OBJECT) // XXX or T_ARRAY? + builder()->CreateUpdateBarrierSet(oopDesc::bs(), addr); +} + +void SharkTopLevelBlock::do_return(BasicType type) { + if (target()->intrinsic_id() == vmIntrinsics::_Object_init) + call_register_finalizer(local(0)->jobject_value()); + maybe_add_safepoint(); + handle_return(type, NULL); +} + +void SharkTopLevelBlock::do_athrow() { + SharkValue *exception = pop(); + check_null(exception); + handle_exception(exception->jobject_value(), EX_CHECK_FULL); +} + +void SharkTopLevelBlock::do_goto() { + do_branch(ciTypeFlow::GOTO_TARGET); +} + +void SharkTopLevelBlock::do_jsr() { + push(SharkValue::address_constant(iter()->next_bci())); + do_branch(ciTypeFlow::GOTO_TARGET); +} + +void SharkTopLevelBlock::do_ret() { + assert(local(iter()->get_index())->address_value() == + successor(ciTypeFlow::GOTO_TARGET)->start(), "should be"); + do_branch(ciTypeFlow::GOTO_TARGET); +} + +// All propagation of state from one block to the next (via +// dest->add_incoming) is handled by these methods: +// do_branch +// do_if_helper +// do_switch +// handle_exception + +void SharkTopLevelBlock::do_branch(int successor_index) { + SharkTopLevelBlock *dest = successor(successor_index); + builder()->CreateBr(dest->entry_block()); + dest->add_incoming(current_state()); +} + +void SharkTopLevelBlock::do_if(ICmpInst::Predicate p, + SharkValue* b, + SharkValue* a) { + Value *llvm_a, *llvm_b; + if (a->is_jobject()) { + llvm_a = a->intptr_value(builder()); + llvm_b = b->intptr_value(builder()); + } + else { + llvm_a = a->jint_value(); + llvm_b = b->jint_value(); + } + do_if_helper(p, llvm_b, llvm_a, current_state(), current_state()); +} + +void SharkTopLevelBlock::do_if_helper(ICmpInst::Predicate p, + Value* b, + Value* a, + SharkState* if_taken_state, + SharkState* not_taken_state) { + SharkTopLevelBlock *if_taken = successor(ciTypeFlow::IF_TAKEN); + SharkTopLevelBlock *not_taken = successor(ciTypeFlow::IF_NOT_TAKEN); + + builder()->CreateCondBr( + builder()->CreateICmp(p, a, b), + if_taken->entry_block(), not_taken->entry_block()); + + if_taken->add_incoming(if_taken_state); + not_taken->add_incoming(not_taken_state); +} + +void SharkTopLevelBlock::do_switch() { + int len = switch_table_length(); + + SharkTopLevelBlock *dest_block = successor(ciTypeFlow::SWITCH_DEFAULT); + SwitchInst *switchinst = builder()->CreateSwitch( + pop()->jint_value(), dest_block->entry_block(), len); + dest_block->add_incoming(current_state()); + + for (int i = 0; i < len; i++) { + int dest_bci = switch_dest(i); + if (dest_bci != switch_default_dest()) { + dest_block = bci_successor(dest_bci); + switchinst->addCase( + LLVMValue::jint_constant(switch_key(i)), + dest_block->entry_block()); + dest_block->add_incoming(current_state()); + } + } +} + +ciMethod* SharkTopLevelBlock::improve_virtual_call(ciMethod* caller, + ciInstanceKlass* klass, + ciMethod* dest_method, + ciType* receiver_type) { + // If the method is obviously final then we are already done + if (dest_method->can_be_statically_bound()) + return dest_method; + + // Array methods are all inherited from Object and are monomorphic + if (receiver_type->is_array_klass() && + dest_method->holder() == java_lang_Object_klass()) + return dest_method; + +#ifdef SHARK_CAN_DEOPTIMIZE_ANYWHERE + // This code can replace a virtual call with a direct call if this + // class is the only one in the entire set of loaded classes that + // implements this method. This makes the compiled code dependent + // on other classes that implement the method not being loaded, a + // condition which is enforced by the dependency tracker. If the + // dependency tracker determines a method has become invalid it + // will mark it for recompilation, causing running copies to be + // deoptimized. Shark currently can't deoptimize arbitrarily like + // that, so this optimization cannot be used. + // http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=481 + + // All other interesting cases are instance classes + if (!receiver_type->is_instance_klass()) + return NULL; + + // Attempt to improve the receiver + ciInstanceKlass* actual_receiver = klass; + ciInstanceKlass *improved_receiver = receiver_type->as_instance_klass(); + if (improved_receiver->is_loaded() && + improved_receiver->is_initialized() && + !improved_receiver->is_interface() && + improved_receiver->is_subtype_of(actual_receiver)) { + actual_receiver = improved_receiver; + } + + // Attempt to find a monomorphic target for this call using + // class heirachy analysis. + ciInstanceKlass *calling_klass = caller->holder(); + ciMethod* monomorphic_target = + dest_method->find_monomorphic_target(calling_klass, klass, actual_receiver); + if (monomorphic_target != NULL) { + assert(!monomorphic_target->is_abstract(), "shouldn't be"); + + // Opto has a bunch of type checking here that I don't + // understand. It's to inhibit casting in one direction, + // possibly because objects in Opto can have inexact + // types, but I can't even tell which direction it + // doesn't like. For now I'm going to block *any* cast. + if (monomorphic_target != dest_method) { + if (SharkPerformanceWarnings) { + warning("found monomorphic target, but inhibited cast:"); + tty->print(" dest_method = "); + dest_method->print_short_name(tty); + tty->cr(); + tty->print(" monomorphic_target = "); + monomorphic_target->print_short_name(tty); + tty->cr(); + } + monomorphic_target = NULL; + } + } + + // Replace the virtual call with a direct one. This makes + // us dependent on that target method not getting overridden + // by dynamic class loading. + if (monomorphic_target != NULL) { + dependencies()->assert_unique_concrete_method( + actual_receiver, monomorphic_target); + return monomorphic_target; + } + + // Because Opto distinguishes exact types from inexact ones + // it can perform a further optimization to replace calls + // with non-monomorphic targets if the receiver has an exact + // type. We don't mark types this way, so we can't do this. + +#endif // SHARK_CAN_DEOPTIMIZE_ANYWHERE + + return NULL; +} + +Value *SharkTopLevelBlock::get_direct_callee(ciMethod* method) { + return builder()->CreateBitCast( + builder()->CreateInlineOop(method), + SharkType::methodOop_type(), + "callee"); +} + +Value *SharkTopLevelBlock::get_virtual_callee(SharkValue* receiver, + int vtable_index) { + Value *klass = builder()->CreateValueOfStructEntry( + receiver->jobject_value(), + in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::oop_type(), + "klass"); + + return builder()->CreateLoad( + builder()->CreateArrayAddress( + klass, + SharkType::methodOop_type(), + vtableEntry::size() * wordSize, + in_ByteSize(instanceKlass::vtable_start_offset() * wordSize), + LLVMValue::intptr_constant(vtable_index)), + "callee"); +} + +Value* SharkTopLevelBlock::get_interface_callee(SharkValue *receiver, + ciMethod* method) { + BasicBlock *loop = function()->CreateBlock("loop"); + BasicBlock *got_null = function()->CreateBlock("got_null"); + BasicBlock *not_null = function()->CreateBlock("not_null"); + BasicBlock *next = function()->CreateBlock("next"); + BasicBlock *got_entry = function()->CreateBlock("got_entry"); + + // Locate the receiver's itable + Value *object_klass = builder()->CreateValueOfStructEntry( + receiver->jobject_value(), in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::oop_type(), + "object_klass"); + + Value *vtable_start = builder()->CreateAdd( + builder()->CreatePtrToInt(object_klass, SharkType::intptr_type()), + LLVMValue::intptr_constant( + instanceKlass::vtable_start_offset() * HeapWordSize), + "vtable_start"); + + Value *vtable_length = builder()->CreateValueOfStructEntry( + object_klass, + in_ByteSize(instanceKlass::vtable_length_offset() * HeapWordSize), + SharkType::jint_type(), + "vtable_length"); + vtable_length = + builder()->CreateIntCast(vtable_length, SharkType::intptr_type(), false); + + bool needs_aligning = HeapWordsPerLong > 1; + Value *itable_start = builder()->CreateAdd( + vtable_start, + builder()->CreateShl( + vtable_length, + LLVMValue::intptr_constant(exact_log2(vtableEntry::size() * wordSize))), + needs_aligning ? "" : "itable_start"); + if (needs_aligning) { + itable_start = builder()->CreateAnd( + builder()->CreateAdd( + itable_start, LLVMValue::intptr_constant(BytesPerLong - 1)), + LLVMValue::intptr_constant(~(BytesPerLong - 1)), + "itable_start"); + } + + // Locate this interface's entry in the table + Value *iklass = builder()->CreateInlineOop(method->holder()); + BasicBlock *loop_entry = builder()->GetInsertBlock(); + builder()->CreateBr(loop); + builder()->SetInsertPoint(loop); + PHINode *itable_entry_addr = builder()->CreatePHI( + SharkType::intptr_type(), "itable_entry_addr"); + itable_entry_addr->addIncoming(itable_start, loop_entry); + + Value *itable_entry = builder()->CreateIntToPtr( + itable_entry_addr, SharkType::itableOffsetEntry_type(), "itable_entry"); + + Value *itable_iklass = builder()->CreateValueOfStructEntry( + itable_entry, + in_ByteSize(itableOffsetEntry::interface_offset_in_bytes()), + SharkType::oop_type(), + "itable_iklass"); + + builder()->CreateCondBr( + builder()->CreateICmpEQ(itable_iklass, LLVMValue::null()), + got_null, not_null); + + // A null entry means that the class doesn't implement the + // interface, and wasn't the same as the class checked when + // the interface was resolved. + builder()->SetInsertPoint(got_null); + builder()->CreateUnimplemented(__FILE__, __LINE__); + builder()->CreateUnreachable(); + + builder()->SetInsertPoint(not_null); + builder()->CreateCondBr( + builder()->CreateICmpEQ(itable_iklass, iklass), + got_entry, next); + + builder()->SetInsertPoint(next); + Value *next_entry = builder()->CreateAdd( + itable_entry_addr, + LLVMValue::intptr_constant(itableOffsetEntry::size() * wordSize)); + builder()->CreateBr(loop); + itable_entry_addr->addIncoming(next_entry, next); + + // Locate the method pointer + builder()->SetInsertPoint(got_entry); + Value *offset = builder()->CreateValueOfStructEntry( + itable_entry, + in_ByteSize(itableOffsetEntry::offset_offset_in_bytes()), + SharkType::jint_type(), + "offset"); + offset = + builder()->CreateIntCast(offset, SharkType::intptr_type(), false); + + return builder()->CreateLoad( + builder()->CreateIntToPtr( + builder()->CreateAdd( + builder()->CreateAdd( + builder()->CreateAdd( + builder()->CreatePtrToInt( + object_klass, SharkType::intptr_type()), + offset), + LLVMValue::intptr_constant( + method->itable_index() * itableMethodEntry::size() * wordSize)), + LLVMValue::intptr_constant( + itableMethodEntry::method_offset_in_bytes())), + PointerType::getUnqual(SharkType::methodOop_type())), + "callee"); +} + +void SharkTopLevelBlock::do_call() { + // Set frequently used booleans + bool is_static = bc() == Bytecodes::_invokestatic; + bool is_virtual = bc() == Bytecodes::_invokevirtual; + bool is_interface = bc() == Bytecodes::_invokeinterface; + + // Find the method being called + bool will_link; + ciMethod *dest_method = iter()->get_method(will_link); + assert(will_link, "typeflow responsibility"); + assert(dest_method->is_static() == is_static, "must match bc"); + + // Find the class of the method being called. Note + // that the superclass check in the second assertion + // is to cope with a hole in the spec that allows for + // invokeinterface instructions where the resolved + // method is a virtual method in java.lang.Object. + // javac doesn't generate code like that, but there's + // no reason a compliant Java compiler might not. + ciInstanceKlass *holder_klass = dest_method->holder(); + assert(holder_klass->is_loaded(), "scan_for_traps responsibility"); + assert(holder_klass->is_interface() || + holder_klass->super() == NULL || + !is_interface, "must match bc"); + ciKlass *holder = iter()->get_declared_method_holder(); + ciInstanceKlass *klass = + ciEnv::get_instance_klass_for_declared_method_holder(holder); + + // Find the receiver in the stack. We do this before + // trying to inline because the inliner can only use + // zero-checked values, not being able to perform the + // check itself. + SharkValue *receiver = NULL; + if (!is_static) { + receiver = xstack(dest_method->arg_size() - 1); + check_null(receiver); + } + + // Try to improve non-direct calls + bool call_is_virtual = is_virtual || is_interface; + ciMethod *call_method = dest_method; + if (call_is_virtual) { + ciMethod *optimized_method = improve_virtual_call( + target(), klass, dest_method, receiver->type()); + if (optimized_method) { + call_method = optimized_method; + call_is_virtual = false; + } + } + + // Try to inline the call + if (!call_is_virtual) { + if (SharkInliner::attempt_inline(call_method, current_state())) + return; + } + + // Find the method we are calling + Value *callee; + if (call_is_virtual) { + if (is_virtual) { + assert(klass->is_linked(), "scan_for_traps responsibility"); + int vtable_index = call_method->resolve_vtable_index( + target()->holder(), klass); + assert(vtable_index >= 0, "should be"); + callee = get_virtual_callee(receiver, vtable_index); + } + else { + assert(is_interface, "should be"); + callee = get_interface_callee(receiver, call_method); + } + } + else { + callee = get_direct_callee(call_method); + } + + // Load the SharkEntry from the callee + Value *base_pc = builder()->CreateValueOfStructEntry( + callee, methodOopDesc::from_interpreted_offset(), + SharkType::intptr_type(), + "base_pc"); + + // Load the entry point from the SharkEntry + Value *entry_point = builder()->CreateLoad( + builder()->CreateIntToPtr( + builder()->CreateAdd( + base_pc, + LLVMValue::intptr_constant(in_bytes(ZeroEntry::entry_point_offset()))), + PointerType::getUnqual( + PointerType::getUnqual(SharkType::entry_point_type()))), + "entry_point"); + + // Make the call + decache_for_Java_call(call_method); + Value *deoptimized_frames = builder()->CreateCall3( + entry_point, callee, base_pc, thread()); + + // If the callee got deoptimized then reexecute in the interpreter + BasicBlock *reexecute = function()->CreateBlock("reexecute"); + BasicBlock *call_completed = function()->CreateBlock("call_completed"); + builder()->CreateCondBr( + builder()->CreateICmpNE(deoptimized_frames, LLVMValue::jint_constant(0)), + reexecute, call_completed); + + builder()->SetInsertPoint(reexecute); + builder()->CreateCall2( + builder()->deoptimized_entry_point(), + builder()->CreateSub(deoptimized_frames, LLVMValue::jint_constant(1)), + thread()); + builder()->CreateBr(call_completed); + + // Cache after the call + builder()->SetInsertPoint(call_completed); + cache_after_Java_call(call_method); + + // Check for pending exceptions + check_pending_exception(EX_CHECK_FULL); + + // Mark that a safepoint check has occurred + current_state()->set_has_safepointed(true); +} + +bool SharkTopLevelBlock::static_subtype_check(ciKlass* check_klass, + ciKlass* object_klass) { + // If the class we're checking against is java.lang.Object + // then this is a no brainer. Apparently this can happen + // in reflective code... + if (check_klass == java_lang_Object_klass()) + return true; + + // Perform a subtype check. NB in opto's code for this + // (GraphKit::static_subtype_check) it says that static + // interface types cannot be trusted, and if opto can't + // trust them then I assume we can't either. + if (object_klass->is_loaded() && !object_klass->is_interface()) { + if (object_klass == check_klass) + return true; + + if (check_klass->is_loaded() && object_klass->is_subtype_of(check_klass)) + return true; + } + + return false; +} + +void SharkTopLevelBlock::do_instance_check() { + // Get the class we're checking against + bool will_link; + ciKlass *check_klass = iter()->get_klass(will_link); + + // Get the class of the object we're checking + ciKlass *object_klass = xstack(0)->type()->as_klass(); + + // Can we optimize this check away? + if (static_subtype_check(check_klass, object_klass)) { + if (bc() == Bytecodes::_instanceof) { + pop(); + push(SharkValue::jint_constant(1)); + } + return; + } + + // Need to check this one at runtime + if (will_link) + do_full_instance_check(check_klass); + else + do_trapping_instance_check(check_klass); +} + +bool SharkTopLevelBlock::maybe_do_instanceof_if() { + // Get the class we're checking against + bool will_link; + ciKlass *check_klass = iter()->get_klass(will_link); + + // If the class is unloaded then the instanceof + // cannot possibly succeed. + if (!will_link) + return false; + + // Keep a copy of the object we're checking + SharkValue *old_object = xstack(0); + + // Get the class of the object we're checking + ciKlass *object_klass = old_object->type()->as_klass(); + + // If the instanceof can be optimized away at compile time + // then any subsequent checkcasts will be too so we handle + // it normally. + if (static_subtype_check(check_klass, object_klass)) + return false; + + // Perform the instance check + do_full_instance_check(check_klass); + Value *result = pop()->jint_value(); + + // Create the casted object + SharkValue *new_object = SharkValue::create_generic( + check_klass, old_object->jobject_value(), old_object->zero_checked()); + + // Create two copies of the current state, one with the + // original object and one with all instances of the + // original object replaced with the new, casted object. + SharkState *new_state = current_state(); + SharkState *old_state = new_state->copy(); + new_state->replace_all(old_object, new_object); + + // Perform the check-and-branch + switch (iter()->next_bc()) { + case Bytecodes::_ifeq: + // branch if not an instance + do_if_helper( + ICmpInst::ICMP_EQ, + LLVMValue::jint_constant(0), result, + old_state, new_state); + break; + + case Bytecodes::_ifne: + // branch if an instance + do_if_helper( + ICmpInst::ICMP_NE, + LLVMValue::jint_constant(0), result, + new_state, old_state); + break; + + default: + ShouldNotReachHere(); + } + + return true; +} + +void SharkTopLevelBlock::do_full_instance_check(ciKlass* klass) { + BasicBlock *not_null = function()->CreateBlock("not_null"); + BasicBlock *subtype_check = function()->CreateBlock("subtype_check"); + BasicBlock *is_instance = function()->CreateBlock("is_instance"); + BasicBlock *not_instance = function()->CreateBlock("not_instance"); + BasicBlock *merge1 = function()->CreateBlock("merge1"); + BasicBlock *merge2 = function()->CreateBlock("merge2"); + + enum InstanceCheckStates { + IC_IS_NULL, + IC_IS_INSTANCE, + IC_NOT_INSTANCE, + }; + + // Pop the object off the stack + Value *object = pop()->jobject_value(); + + // Null objects aren't instances of anything + builder()->CreateCondBr( + builder()->CreateICmpEQ(object, LLVMValue::null()), + merge2, not_null); + BasicBlock *null_block = builder()->GetInsertBlock(); + + // Get the class we're checking against + builder()->SetInsertPoint(not_null); + Value *check_klass = builder()->CreateInlineOop(klass); + + // Get the class of the object being tested + Value *object_klass = builder()->CreateValueOfStructEntry( + object, in_ByteSize(oopDesc::klass_offset_in_bytes()), + SharkType::oop_type(), + "object_klass"); + + // Perform the check + builder()->CreateCondBr( + builder()->CreateICmpEQ(check_klass, object_klass), + is_instance, subtype_check); + + builder()->SetInsertPoint(subtype_check); + builder()->CreateCondBr( + builder()->CreateICmpNE( + builder()->CreateCall2( + builder()->is_subtype_of(), check_klass, object_klass), + LLVMValue::jbyte_constant(0)), + is_instance, not_instance); + + builder()->SetInsertPoint(is_instance); + builder()->CreateBr(merge1); + + builder()->SetInsertPoint(not_instance); + builder()->CreateBr(merge1); + + // First merge + builder()->SetInsertPoint(merge1); + PHINode *nonnull_result = builder()->CreatePHI( + SharkType::jint_type(), "nonnull_result"); + nonnull_result->addIncoming( + LLVMValue::jint_constant(IC_IS_INSTANCE), is_instance); + nonnull_result->addIncoming( + LLVMValue::jint_constant(IC_NOT_INSTANCE), not_instance); + BasicBlock *nonnull_block = builder()->GetInsertBlock(); + builder()->CreateBr(merge2); + + // Second merge + builder()->SetInsertPoint(merge2); + PHINode *result = builder()->CreatePHI( + SharkType::jint_type(), "result"); + result->addIncoming(LLVMValue::jint_constant(IC_IS_NULL), null_block); + result->addIncoming(nonnull_result, nonnull_block); + + // Handle the result + if (bc() == Bytecodes::_checkcast) { + BasicBlock *failure = function()->CreateBlock("failure"); + BasicBlock *success = function()->CreateBlock("success"); + + builder()->CreateCondBr( + builder()->CreateICmpNE( + result, LLVMValue::jint_constant(IC_NOT_INSTANCE)), + success, failure); + + builder()->SetInsertPoint(failure); + SharkState *saved_state = current_state()->copy(); + + call_vm( + builder()->throw_ClassCastException(), + builder()->CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) __FILE__), + PointerType::getUnqual(SharkType::jbyte_type())), + LLVMValue::jint_constant(__LINE__), + EX_CHECK_NONE); + + Value *pending_exception = get_pending_exception(); + clear_pending_exception(); + handle_exception(pending_exception, EX_CHECK_FULL); + + set_current_state(saved_state); + builder()->SetInsertPoint(success); + push(SharkValue::create_generic(klass, object, false)); + } + else { + push( + SharkValue::create_jint( + builder()->CreateIntCast( + builder()->CreateICmpEQ( + result, LLVMValue::jint_constant(IC_IS_INSTANCE)), + SharkType::jint_type(), false), false)); + } +} + +void SharkTopLevelBlock::do_trapping_instance_check(ciKlass* klass) { + BasicBlock *not_null = function()->CreateBlock("not_null"); + BasicBlock *is_null = function()->CreateBlock("null"); + + // Leave the object on the stack so it's there if we trap + builder()->CreateCondBr( + builder()->CreateICmpEQ(xstack(0)->jobject_value(), LLVMValue::null()), + is_null, not_null); + SharkState *saved_state = current_state()->copy(); + + // If it's not null then we need to trap + builder()->SetInsertPoint(not_null); + set_current_state(saved_state->copy()); + do_trap( + Deoptimization::make_trap_request( + Deoptimization::Reason_uninitialized, + Deoptimization::Action_reinterpret)); + + // If it's null then we're ok + builder()->SetInsertPoint(is_null); + set_current_state(saved_state); + if (bc() == Bytecodes::_checkcast) { + push(SharkValue::create_generic(klass, pop()->jobject_value(), false)); + } + else { + pop(); + push(SharkValue::jint_constant(0)); + } +} + +void SharkTopLevelBlock::do_new() { + bool will_link; + ciInstanceKlass* klass = iter()->get_klass(will_link)->as_instance_klass(); + assert(will_link, "typeflow responsibility"); + + BasicBlock *got_tlab = NULL; + BasicBlock *heap_alloc = NULL; + BasicBlock *retry = NULL; + BasicBlock *got_heap = NULL; + BasicBlock *initialize = NULL; + BasicBlock *got_fast = NULL; + BasicBlock *slow_alloc_and_init = NULL; + BasicBlock *got_slow = NULL; + BasicBlock *push_object = NULL; + + SharkState *fast_state = NULL; + + Value *tlab_object = NULL; + Value *heap_object = NULL; + Value *fast_object = NULL; + Value *slow_object = NULL; + Value *object = NULL; + + // The fast path + if (!Klass::layout_helper_needs_slow_path(klass->layout_helper())) { + if (UseTLAB) { + got_tlab = function()->CreateBlock("got_tlab"); + heap_alloc = function()->CreateBlock("heap_alloc"); + } + retry = function()->CreateBlock("retry"); + got_heap = function()->CreateBlock("got_heap"); + initialize = function()->CreateBlock("initialize"); + slow_alloc_and_init = function()->CreateBlock("slow_alloc_and_init"); + push_object = function()->CreateBlock("push_object"); + + size_t size_in_bytes = klass->size_helper() << LogHeapWordSize; + + // Thread local allocation + if (UseTLAB) { + Value *top_addr = builder()->CreateAddressOfStructEntry( + thread(), Thread::tlab_top_offset(), + PointerType::getUnqual(SharkType::intptr_type()), + "top_addr"); + + Value *end = builder()->CreateValueOfStructEntry( + thread(), Thread::tlab_end_offset(), + SharkType::intptr_type(), + "end"); + + Value *old_top = builder()->CreateLoad(top_addr, "old_top"); + Value *new_top = builder()->CreateAdd( + old_top, LLVMValue::intptr_constant(size_in_bytes)); + + builder()->CreateCondBr( + builder()->CreateICmpULE(new_top, end), + got_tlab, heap_alloc); + + builder()->SetInsertPoint(got_tlab); + tlab_object = builder()->CreateIntToPtr( + old_top, SharkType::oop_type(), "tlab_object"); + + builder()->CreateStore(new_top, top_addr); + builder()->CreateBr(initialize); + + builder()->SetInsertPoint(heap_alloc); + } + + // Heap allocation + Value *top_addr = builder()->CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) Universe::heap()->top_addr()), + PointerType::getUnqual(SharkType::intptr_type()), + "top_addr"); + + Value *end = builder()->CreateLoad( + builder()->CreateIntToPtr( + LLVMValue::intptr_constant((intptr_t) Universe::heap()->end_addr()), + PointerType::getUnqual(SharkType::intptr_type())), + "end"); + + builder()->CreateBr(retry); + builder()->SetInsertPoint(retry); + + Value *old_top = builder()->CreateLoad(top_addr, "top"); + Value *new_top = builder()->CreateAdd( + old_top, LLVMValue::intptr_constant(size_in_bytes)); + + builder()->CreateCondBr( + builder()->CreateICmpULE(new_top, end), + got_heap, slow_alloc_and_init); + + builder()->SetInsertPoint(got_heap); + heap_object = builder()->CreateIntToPtr( + old_top, SharkType::oop_type(), "heap_object"); + + Value *check = builder()->CreateCmpxchgPtr(new_top, top_addr, old_top); + builder()->CreateCondBr( + builder()->CreateICmpEQ(old_top, check), + initialize, retry); + + // Initialize the object + builder()->SetInsertPoint(initialize); + if (tlab_object) { + PHINode *phi = builder()->CreatePHI( + SharkType::oop_type(), "fast_object"); + phi->addIncoming(tlab_object, got_tlab); + phi->addIncoming(heap_object, got_heap); + fast_object = phi; + } + else { + fast_object = heap_object; + } + + builder()->CreateMemset( + builder()->CreateBitCast( + fast_object, PointerType::getUnqual(SharkType::jbyte_type())), + LLVMValue::jbyte_constant(0), + LLVMValue::jint_constant(size_in_bytes), + LLVMValue::jint_constant(HeapWordSize)); + + Value *mark_addr = builder()->CreateAddressOfStructEntry( + fast_object, in_ByteSize(oopDesc::mark_offset_in_bytes()), + PointerType::getUnqual(SharkType::intptr_type()), + "mark_addr"); + + Value *klass_addr = builder()->CreateAddressOfStructEntry( + fast_object, in_ByteSize(oopDesc::klass_offset_in_bytes()), + PointerType::getUnqual(SharkType::oop_type()), + "klass_addr"); + + // Set the mark + intptr_t mark; + if (UseBiasedLocking) { + Unimplemented(); + } + else { + mark = (intptr_t) markOopDesc::prototype(); + } + builder()->CreateStore(LLVMValue::intptr_constant(mark), mark_addr); + + // Set the class + Value *rtklass = builder()->CreateInlineOop(klass); + builder()->CreateStore(rtklass, klass_addr); + got_fast = builder()->GetInsertBlock(); + + builder()->CreateBr(push_object); + builder()->SetInsertPoint(slow_alloc_and_init); + fast_state = current_state()->copy(); + } + + // The slow path + call_vm( + builder()->new_instance(), + LLVMValue::jint_constant(iter()->get_klass_index()), + EX_CHECK_FULL); + slow_object = get_vm_result(); + got_slow = builder()->GetInsertBlock(); + + // Push the object + if (push_object) { + builder()->CreateBr(push_object); + builder()->SetInsertPoint(push_object); + } + if (fast_object) { + PHINode *phi = builder()->CreatePHI(SharkType::oop_type(), "object"); + phi->addIncoming(fast_object, got_fast); + phi->addIncoming(slow_object, got_slow); + object = phi; + current_state()->merge(fast_state, got_fast, got_slow); + } + else { + object = slow_object; + } + + push(SharkValue::create_jobject(object, true)); +} + +void SharkTopLevelBlock::do_newarray() { + BasicType type = (BasicType) iter()->get_index(); + + call_vm( + builder()->newarray(), + LLVMValue::jint_constant(type), + pop()->jint_value(), + EX_CHECK_FULL); + + ciArrayKlass *array_klass = ciArrayKlass::make(ciType::make(type)); + push(SharkValue::create_generic(array_klass, get_vm_result(), true)); +} + +void SharkTopLevelBlock::do_anewarray() { + bool will_link; + ciKlass *klass = iter()->get_klass(will_link); + assert(will_link, "typeflow responsibility"); + + ciObjArrayKlass *array_klass = ciObjArrayKlass::make(klass); + if (!array_klass->is_loaded()) { + Unimplemented(); + } + + call_vm( + builder()->anewarray(), + LLVMValue::jint_constant(iter()->get_klass_index()), + pop()->jint_value(), + EX_CHECK_FULL); + + push(SharkValue::create_generic(array_klass, get_vm_result(), true)); +} + +void SharkTopLevelBlock::do_multianewarray() { + bool will_link; + ciArrayKlass *array_klass = iter()->get_klass(will_link)->as_array_klass(); + assert(will_link, "typeflow responsibility"); + + // The dimensions are stack values, so we use their slots for the + // dimensions array. Note that we are storing them in the reverse + // of normal stack order. + int ndims = iter()->get_dimensions(); + + Value *dimensions = stack()->slot_addr( + stack()->stack_slots_offset() + max_stack() - xstack_depth(), + ArrayType::get(SharkType::jint_type(), ndims), + "dimensions"); + + for (int i = 0; i < ndims; i++) { + builder()->CreateStore( + xstack(ndims - 1 - i)->jint_value(), + builder()->CreateStructGEP(dimensions, i)); + } + + call_vm( + builder()->multianewarray(), + LLVMValue::jint_constant(iter()->get_klass_index()), + LLVMValue::jint_constant(ndims), + builder()->CreateStructGEP(dimensions, 0), + EX_CHECK_FULL); + + // Now we can pop the dimensions off the stack + for (int i = 0; i < ndims; i++) + pop(); + + push(SharkValue::create_generic(array_klass, get_vm_result(), true)); +} + +void SharkTopLevelBlock::acquire_method_lock() { + Value *lockee; + if (target()->is_static()) + lockee = builder()->CreateInlineOop(target()->holder()->java_mirror()); + else + lockee = local(0)->jobject_value(); + + iter()->force_bci(start()); // for the decache in acquire_lock + acquire_lock(lockee, EX_CHECK_NO_CATCH); +} + +void SharkTopLevelBlock::do_monitorenter() { + SharkValue *lockee = pop(); + check_null(lockee); + acquire_lock(lockee->jobject_value(), EX_CHECK_FULL); +} + +void SharkTopLevelBlock::do_monitorexit() { + pop(); // don't need this (monitors are block structured) + release_lock(EX_CHECK_NO_CATCH); +} + +void SharkTopLevelBlock::acquire_lock(Value *lockee, int exception_action) { + BasicBlock *try_recursive = function()->CreateBlock("try_recursive"); + BasicBlock *got_recursive = function()->CreateBlock("got_recursive"); + BasicBlock *not_recursive = function()->CreateBlock("not_recursive"); + BasicBlock *acquired_fast = function()->CreateBlock("acquired_fast"); + BasicBlock *lock_acquired = function()->CreateBlock("lock_acquired"); + + int monitor = num_monitors(); + Value *monitor_addr = stack()->monitor_addr(monitor); + Value *monitor_object_addr = stack()->monitor_object_addr(monitor); + Value *monitor_header_addr = stack()->monitor_header_addr(monitor); + + // Store the object and mark the slot as live + builder()->CreateStore(lockee, monitor_object_addr); + set_num_monitors(monitor + 1); + + // Try a simple lock + Value *mark_addr = builder()->CreateAddressOfStructEntry( + lockee, in_ByteSize(oopDesc::mark_offset_in_bytes()), + PointerType::getUnqual(SharkType::intptr_type()), + "mark_addr"); + + Value *mark = builder()->CreateLoad(mark_addr, "mark"); + Value *disp = builder()->CreateOr( + mark, LLVMValue::intptr_constant(markOopDesc::unlocked_value), "disp"); + builder()->CreateStore(disp, monitor_header_addr); + + Value *lock = builder()->CreatePtrToInt( + monitor_header_addr, SharkType::intptr_type()); + Value *check = builder()->CreateCmpxchgPtr(lock, mark_addr, disp); + builder()->CreateCondBr( + builder()->CreateICmpEQ(disp, check), + acquired_fast, try_recursive); + + // Locking failed, but maybe this thread already owns it + builder()->SetInsertPoint(try_recursive); + Value *addr = builder()->CreateAnd( + disp, + LLVMValue::intptr_constant(~markOopDesc::lock_mask_in_place)); + + // NB we use the entire stack, but JavaThread::is_lock_owned() + // uses a more limited range. I don't think it hurts though... + Value *stack_limit = builder()->CreateValueOfStructEntry( + thread(), Thread::stack_base_offset(), + SharkType::intptr_type(), + "stack_limit"); + + assert(sizeof(size_t) == sizeof(intptr_t), "should be"); + Value *stack_size = builder()->CreateValueOfStructEntry( + thread(), Thread::stack_size_offset(), + SharkType::intptr_type(), + "stack_size"); + + Value *stack_start = + builder()->CreateSub(stack_limit, stack_size, "stack_start"); + + builder()->CreateCondBr( + builder()->CreateAnd( + builder()->CreateICmpUGE(addr, stack_start), + builder()->CreateICmpULT(addr, stack_limit)), + got_recursive, not_recursive); + + builder()->SetInsertPoint(got_recursive); + builder()->CreateStore(LLVMValue::intptr_constant(0), monitor_header_addr); + builder()->CreateBr(acquired_fast); + + // Create an edge for the state merge + builder()->SetInsertPoint(acquired_fast); + SharkState *fast_state = current_state()->copy(); + builder()->CreateBr(lock_acquired); + + // It's not a recursive case so we need to drop into the runtime + builder()->SetInsertPoint(not_recursive); + call_vm( + builder()->monitorenter(), monitor_addr, + exception_action | EAM_MONITOR_FUDGE); + BasicBlock *acquired_slow = builder()->GetInsertBlock(); + builder()->CreateBr(lock_acquired); + + // All done + builder()->SetInsertPoint(lock_acquired); + current_state()->merge(fast_state, acquired_fast, acquired_slow); +} + +void SharkTopLevelBlock::release_lock(int exception_action) { + BasicBlock *not_recursive = function()->CreateBlock("not_recursive"); + BasicBlock *released_fast = function()->CreateBlock("released_fast"); + BasicBlock *slow_path = function()->CreateBlock("slow_path"); + BasicBlock *lock_released = function()->CreateBlock("lock_released"); + + int monitor = num_monitors() - 1; + Value *monitor_addr = stack()->monitor_addr(monitor); + Value *monitor_object_addr = stack()->monitor_object_addr(monitor); + Value *monitor_header_addr = stack()->monitor_header_addr(monitor); + + // If it is recursive then we're already done + Value *disp = builder()->CreateLoad(monitor_header_addr); + builder()->CreateCondBr( + builder()->CreateICmpEQ(disp, LLVMValue::intptr_constant(0)), + released_fast, not_recursive); + + // Try a simple unlock + builder()->SetInsertPoint(not_recursive); + + Value *lock = builder()->CreatePtrToInt( + monitor_header_addr, SharkType::intptr_type()); + + Value *lockee = builder()->CreateLoad(monitor_object_addr); + + Value *mark_addr = builder()->CreateAddressOfStructEntry( + lockee, in_ByteSize(oopDesc::mark_offset_in_bytes()), + PointerType::getUnqual(SharkType::intptr_type()), + "mark_addr"); + + Value *check = builder()->CreateCmpxchgPtr(disp, mark_addr, lock); + builder()->CreateCondBr( + builder()->CreateICmpEQ(lock, check), + released_fast, slow_path); + + // Create an edge for the state merge + builder()->SetInsertPoint(released_fast); + SharkState *fast_state = current_state()->copy(); + builder()->CreateBr(lock_released); + + // Need to drop into the runtime to release this one + builder()->SetInsertPoint(slow_path); + call_vm(builder()->monitorexit(), monitor_addr, exception_action); + BasicBlock *released_slow = builder()->GetInsertBlock(); + builder()->CreateBr(lock_released); + + // All done + builder()->SetInsertPoint(lock_released); + current_state()->merge(fast_state, released_fast, released_slow); + + // The object slot is now dead + set_num_monitors(monitor); +} diff --git a/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp b/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp new file mode 100644 index 00000000000..76aba1fd54a --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp @@ -0,0 +1,430 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkTopLevelBlock : public SharkBlock { + public: + SharkTopLevelBlock(SharkFunction* function, ciTypeFlow::Block* ciblock) + : SharkBlock(function), + _function(function), + _ciblock(ciblock), + _entered(false), + _has_trap(false), + _needs_phis(false), + _entry_state(NULL), + _entry_block(NULL) {} + + private: + SharkFunction* _function; + ciTypeFlow::Block* _ciblock; + + public: + SharkFunction* function() const { + return _function; + } + ciTypeFlow::Block* ciblock() const { + return _ciblock; + } + + // Function properties + public: + SharkStack* stack() const { + return function()->stack(); + } + + // Typeflow properties + public: + int index() const { + return ciblock()->pre_order(); + } + bool is_backedge_copy() const { + return ciblock()->is_backedge_copy(); + } + int stack_depth_at_entry() const { + return ciblock()->stack_size(); + } + ciType* local_type_at_entry(int index) const { + return ciblock()->local_type_at(index); + } + ciType* stack_type_at_entry(int slot) const { + return ciblock()->stack_type_at(slot); + } + int start() const { + return ciblock()->start(); + } + int limit() const { + return ciblock()->limit(); + } + bool falls_through() const { + return ciblock()->control() == ciBlock::fall_through_bci; + } + int num_successors() const { + return ciblock()->successors()->length(); + } + SharkTopLevelBlock* successor(int index) const { + return function()->block(ciblock()->successors()->at(index)->pre_order()); + } + SharkTopLevelBlock* bci_successor(int bci) const; + + // Exceptions + private: + GrowableArray* _exc_handlers; + GrowableArray* _exceptions; + + private: + void compute_exceptions(); + + private: + int num_exceptions() const { + return _exc_handlers->length(); + } + ciExceptionHandler* exc_handler(int index) const { + return _exc_handlers->at(index); + } + SharkTopLevelBlock* exception(int index) const { + return _exceptions->at(index); + } + + // Traps + private: + bool _has_trap; + int _trap_request; + int _trap_bci; + + void set_trap(int trap_request, int trap_bci) { + assert(!has_trap(), "shouldn't have"); + _has_trap = true; + _trap_request = trap_request; + _trap_bci = trap_bci; + } + + private: + bool has_trap() { + return _has_trap; + } + int trap_request() { + assert(has_trap(), "should have"); + return _trap_request; + } + int trap_bci() { + assert(has_trap(), "should have"); + return _trap_bci; + } + + private: + void scan_for_traps(); + + private: + bool static_field_ok_in_clinit(ciField* field); + + // Entry state + private: + bool _entered; + bool _needs_phis; + + public: + bool entered() const { + return _entered; + } + bool needs_phis() const { + return _needs_phis; + } + + private: + void enter(SharkTopLevelBlock* predecessor, bool is_exception); + + public: + void enter() { + enter(NULL, false); + } + + private: + SharkState* _entry_state; + + private: + SharkState* entry_state(); + + private: + llvm::BasicBlock* _entry_block; + + public: + llvm::BasicBlock* entry_block() const { + return _entry_block; + } + + public: + void initialize(); + + public: + void add_incoming(SharkState* incoming_state); + + // Method + public: + llvm::Value* method() { + return current_state()->method(); + } + + // Temporary oop storage + public: + void set_oop_tmp(llvm::Value* value) { + assert(value, "value must be non-NULL (will be reset by get_oop_tmp)"); + assert(!current_state()->oop_tmp(), "oop_tmp gets and sets must match"); + current_state()->set_oop_tmp(value); + } + llvm::Value* get_oop_tmp() { + llvm::Value* value = current_state()->oop_tmp(); + assert(value, "oop_tmp gets and sets must match"); + current_state()->set_oop_tmp(NULL); + return value; + } + + // Cache and decache + private: + void decache_for_Java_call(ciMethod* callee); + void cache_after_Java_call(ciMethod* callee); + void decache_for_VM_call(); + void cache_after_VM_call(); + void decache_for_trap(); + + // Monitors + private: + int num_monitors() { + return current_state()->num_monitors(); + } + int set_num_monitors(int num_monitors) { + current_state()->set_num_monitors(num_monitors); + } + + // Code generation + public: + void emit_IR(); + + // Branch helpers + private: + void do_branch(int successor_index); + + // Zero checks + private: + void do_zero_check(SharkValue* value); + void zero_check_value(SharkValue* value, llvm::BasicBlock* continue_block); + + public: + void do_deferred_zero_check(SharkValue* value, + int bci, + SharkState* saved_state, + llvm::BasicBlock* continue_block); + // Exceptions + private: + llvm::Value* pending_exception_address() const { + return builder()->CreateAddressOfStructEntry( + thread(), Thread::pending_exception_offset(), + llvm::PointerType::getUnqual(SharkType::oop_type()), + "pending_exception_addr"); + } + llvm::LoadInst* get_pending_exception() const { + return builder()->CreateLoad( + pending_exception_address(), "pending_exception"); + } + void clear_pending_exception() const { + builder()->CreateStore(LLVMValue::null(), pending_exception_address()); + } + public: + enum ExceptionActionMask { + // The actual bitmasks that things test against + EAM_CHECK = 1, // whether to check for pending exceptions + EAM_HANDLE = 2, // whether to attempt to handle pending exceptions + EAM_MONITOR_FUDGE = 4, // whether the monitor count needs adjusting + + // More convenient values for passing + EX_CHECK_NONE = 0, + EX_CHECK_NO_CATCH = EAM_CHECK, + EX_CHECK_FULL = EAM_CHECK | EAM_HANDLE + }; + void check_pending_exception(int action); + void handle_exception(llvm::Value* exception, int action); + void marshal_exception_fast(int num_options); + void marshal_exception_slow(int num_options); + llvm::BasicBlock* handler_for_exception(int index); + + // VM calls + private: + llvm::CallInst* call_vm(llvm::Value* callee, + llvm::Value** args_start, + llvm::Value** args_end, + int exception_action) { + decache_for_VM_call(); + stack()->CreateSetLastJavaFrame(); + llvm::CallInst *res = builder()->CreateCall(callee, args_start, args_end); + stack()->CreateResetLastJavaFrame(); + cache_after_VM_call(); + if (exception_action & EAM_CHECK) { + check_pending_exception(exception_action); + current_state()->set_has_safepointed(true); + } + return res; + } + + public: + llvm::CallInst* call_vm(llvm::Value* callee, + int exception_action) { + llvm::Value *args[] = {thread()}; + return call_vm(callee, args, args + 1, exception_action); + } + llvm::CallInst* call_vm(llvm::Value* callee, + llvm::Value* arg1, + int exception_action) { + llvm::Value *args[] = {thread(), arg1}; + return call_vm(callee, args, args + 2, exception_action); + } + llvm::CallInst* call_vm(llvm::Value* callee, + llvm::Value* arg1, + llvm::Value* arg2, + int exception_action) { + llvm::Value *args[] = {thread(), arg1, arg2}; + return call_vm(callee, args, args + 3, exception_action); + } + llvm::CallInst* call_vm(llvm::Value* callee, + llvm::Value* arg1, + llvm::Value* arg2, + llvm::Value* arg3, + int exception_action) { + llvm::Value *args[] = {thread(), arg1, arg2, arg3}; + return call_vm(callee, args, args + 4, exception_action); + } + + // VM call oop return handling + private: + llvm::LoadInst* get_vm_result() const { + llvm::Value *addr = builder()->CreateAddressOfStructEntry( + thread(), JavaThread::vm_result_offset(), + llvm::PointerType::getUnqual(SharkType::oop_type()), + "vm_result_addr"); + llvm::LoadInst *result = builder()->CreateLoad(addr, "vm_result"); + builder()->CreateStore(LLVMValue::null(), addr); + return result; + } + + // Synchronization + private: + void acquire_lock(llvm::Value* lockee, int exception_action); + void release_lock(int exception_action); + + public: + void acquire_method_lock(); + + // Bounds checks + private: + void check_bounds(SharkValue* array, SharkValue* index); + + // Safepoints + private: + void maybe_add_safepoint(); + void maybe_add_backedge_safepoint(); + + // Loop safepoint removal + private: + bool _can_reach_visited; + + bool can_reach(SharkTopLevelBlock* other); + bool can_reach_helper(SharkTopLevelBlock* other); + + // Traps + private: + llvm::BasicBlock* make_trap(int trap_bci, int trap_request); + void do_trap(int trap_request); + + // Returns + private: + void call_register_finalizer(llvm::Value* receiver); + void handle_return(BasicType type, llvm::Value* exception); + + // arraylength + private: + void do_arraylength(); + + // *aload and *astore + private: + void do_aload(BasicType basic_type); + void do_astore(BasicType basic_type); + + // *return and athrow + private: + void do_return(BasicType type); + void do_athrow(); + + // goto* + private: + void do_goto(); + + // jsr* and ret + private: + void do_jsr(); + void do_ret(); + + // if* + private: + void do_if_helper(llvm::ICmpInst::Predicate p, + llvm::Value* b, + llvm::Value* a, + SharkState* if_taken_state, + SharkState* not_taken_state); + void do_if(llvm::ICmpInst::Predicate p, SharkValue* b, SharkValue* a); + + // tableswitch and lookupswitch + private: + void do_switch(); + + // invoke* + private: + ciMethod* improve_virtual_call(ciMethod* caller, + ciInstanceKlass* klass, + ciMethod* dest_method, + ciType* receiver_type); + llvm::Value* get_direct_callee(ciMethod* method); + llvm::Value* get_virtual_callee(SharkValue* receiver, int vtable_index); + llvm::Value* get_interface_callee(SharkValue* receiver, ciMethod* method); + + void do_call(); + + // checkcast and instanceof + private: + bool static_subtype_check(ciKlass* check_klass, ciKlass* object_klass); + void do_full_instance_check(ciKlass* klass); + void do_trapping_instance_check(ciKlass* klass); + + void do_instance_check(); + bool maybe_do_instanceof_if(); + + // new and *newarray + private: + void do_new(); + void do_newarray(); + void do_anewarray(); + void do_multianewarray(); + + // monitorenter and monitorexit + private: + void do_monitorenter(); + void do_monitorexit(); +}; diff --git a/hotspot/src/share/vm/shark/sharkType.hpp b/hotspot/src/share/vm/shark/sharkType.hpp new file mode 100644 index 00000000000..9c5d9e977c0 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkType.hpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +class SharkType : public AllStatic { + private: + static SharkContext& context() { + return SharkContext::current(); + } + + // Basic types + public: + static const llvm::Type* void_type() { + return context().void_type(); + } + static const llvm::IntegerType* bit_type() { + return context().bit_type(); + } + static const llvm::IntegerType* jbyte_type() { + return context().jbyte_type(); + } + static const llvm::IntegerType* jshort_type() { + return context().jshort_type(); + } + static const llvm::IntegerType* jint_type() { + return context().jint_type(); + } + static const llvm::IntegerType* jlong_type() { + return context().jlong_type(); + } + static const llvm::Type* jfloat_type() { + return context().jfloat_type(); + } + static const llvm::Type* jdouble_type() { + return context().jdouble_type(); + } + static const llvm::IntegerType* intptr_type() { + return context().intptr_type(); + } + + // Compound types + public: + static const llvm::PointerType* itableOffsetEntry_type() { + return context().itableOffsetEntry_type(); + } + static const llvm::PointerType* jniEnv_type() { + return context().jniEnv_type(); + } + static const llvm::PointerType* jniHandleBlock_type() { + return context().jniHandleBlock_type(); + } + static const llvm::PointerType* klass_type() { + return context().klass_type(); + } + static const llvm::PointerType* methodOop_type() { + return context().methodOop_type(); + } + static const llvm::ArrayType* monitor_type() { + return context().monitor_type(); + } + static const llvm::PointerType* oop_type() { + return context().oop_type(); + } + static const llvm::PointerType* thread_type() { + return context().thread_type(); + } + static const llvm::PointerType* zeroStack_type() { + return context().zeroStack_type(); + } + static const llvm::FunctionType* entry_point_type() { + return context().entry_point_type(); + } + static const llvm::FunctionType* osr_entry_point_type() { + return context().osr_entry_point_type(); + } + + // Mappings + public: + static const llvm::Type* to_stackType(BasicType type) { + return context().to_stackType(type); + } + static const llvm::Type* to_stackType(ciType* type) { + return to_stackType(type->basic_type()); + } + static const llvm::Type* to_arrayType(BasicType type) { + return context().to_arrayType(type); + } + static const llvm::Type* to_arrayType(ciType* type) { + return to_arrayType(type->basic_type()); + } +}; diff --git a/hotspot/src/share/vm/shark/sharkValue.cpp b/hotspot/src/share/vm/shark/sharkValue.cpp new file mode 100644 index 00000000000..18b1fa6324b --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkValue.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_sharkValue.cpp.incl" + +using namespace llvm; + +// Cloning + +SharkValue* SharkNormalValue::clone() const { + return SharkValue::create_generic(type(), generic_value(), zero_checked()); +} +SharkValue* SharkPHIValue::clone() const { + return SharkValue::create_phi(type(), (PHINode *) generic_value(), this); +} +SharkValue* SharkAddressValue::clone() const { + return SharkValue::address_constant(address_value()); +} + +// Casting + +bool SharkValue::is_phi() const { + return false; +} +bool SharkPHIValue::is_phi() const { + return true; +} +SharkPHIValue* SharkValue::as_phi() { + ShouldNotCallThis(); +} +SharkPHIValue* SharkPHIValue::as_phi() { + return this; +} + +// Comparison + +bool SharkNormalValue::equal_to(SharkValue *other) const { + return (this->type() == other->type() && + this->generic_value() == other->generic_value() && + this->zero_checked() == other->zero_checked()); +} +bool SharkAddressValue::equal_to(SharkValue *other) const { + return (this->address_value() == other->address_value()); +} + +// Type access + +ciType* SharkValue::type() const { + ShouldNotCallThis(); +} +ciType* SharkNormalValue::type() const { + return _type; +} + +BasicType SharkNormalValue::basic_type() const { + return type()->basic_type(); +} +BasicType SharkAddressValue::basic_type() const { + return T_ADDRESS; +} + +int SharkNormalValue::size() const { + return type()->size(); +} +int SharkAddressValue::size() const { + return 1; +} + +bool SharkValue::is_jint() const { + return false; +} +bool SharkValue::is_jlong() const { + return false; +} +bool SharkValue::is_jfloat() const { + return false; +} +bool SharkValue::is_jdouble() const { + return false; +} +bool SharkValue::is_jobject() const { + return false; +} +bool SharkValue::is_jarray() const { + return false; +} +bool SharkValue::is_address() const { + return false; +} + +bool SharkNormalValue::is_jint() const { + return llvm_value()->getType() == SharkType::jint_type(); +} +bool SharkNormalValue::is_jlong() const { + return llvm_value()->getType() == SharkType::jlong_type(); +} +bool SharkNormalValue::is_jfloat() const { + return llvm_value()->getType() == SharkType::jfloat_type(); +} +bool SharkNormalValue::is_jdouble() const { + return llvm_value()->getType() == SharkType::jdouble_type(); +} +bool SharkNormalValue::is_jobject() const { + return llvm_value()->getType() == SharkType::oop_type(); +} +bool SharkNormalValue::is_jarray() const { + return basic_type() == T_ARRAY; +} +bool SharkAddressValue::is_address() const { + return true; +} + +// Typed conversions from SharkValues + +Value* SharkValue::jint_value() const { + ShouldNotCallThis(); +} +Value* SharkValue::jlong_value() const { + ShouldNotCallThis(); +} +Value* SharkValue::jfloat_value() const { + ShouldNotCallThis(); +} +Value* SharkValue::jdouble_value() const { + ShouldNotCallThis(); +} +Value* SharkValue::jobject_value() const { + ShouldNotCallThis(); +} +Value* SharkValue::jarray_value() const { + ShouldNotCallThis(); +} +int SharkValue::address_value() const { + ShouldNotCallThis(); +} + +Value* SharkNormalValue::jint_value() const { + assert(is_jint(), "should be"); + return llvm_value(); +} +Value* SharkNormalValue::jlong_value() const { + assert(is_jlong(), "should be"); + return llvm_value(); +} +Value* SharkNormalValue::jfloat_value() const { + assert(is_jfloat(), "should be"); + return llvm_value(); +} +Value* SharkNormalValue::jdouble_value() const { + assert(is_jdouble(), "should be"); + return llvm_value(); +} +Value* SharkNormalValue::jobject_value() const { + assert(is_jobject(), "should be"); + return llvm_value(); +} +Value* SharkNormalValue::jarray_value() const { + // XXX assert(is_jarray(), "should be"); + // XXX http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=324 + assert(is_jobject(), "should be"); + return llvm_value(); +} +int SharkAddressValue::address_value() const { + return _bci; +} + +// Type-losing conversions -- use with care! + +Value* SharkNormalValue::generic_value() const { + return llvm_value(); +} +Value* SharkAddressValue::generic_value() const { + return LLVMValue::intptr_constant(address_value()); +} + +Value* SharkValue::intptr_value(SharkBuilder* builder) const { + ShouldNotCallThis(); +} +Value* SharkNormalValue::intptr_value(SharkBuilder* builder) const { + return builder->CreatePtrToInt(jobject_value(), SharkType::intptr_type()); +} + +// Phi-style stuff for SharkPHIState::add_incoming + +void SharkValue::addIncoming(SharkValue *value, BasicBlock* block) { + ShouldNotCallThis(); +} +void SharkPHIValue::addIncoming(SharkValue *value, BasicBlock* block) { + assert(!is_clone(), "shouldn't be"); + ((llvm::PHINode *) generic_value())->addIncoming( + value->generic_value(), block); + if (!value->zero_checked()) + _all_incomers_zero_checked = false; +} +void SharkAddressValue::addIncoming(SharkValue *value, BasicBlock* block) { + assert(this->equal_to(value), "should be"); +} + +// Phi-style stuff for SharkState::merge + +SharkValue* SharkNormalValue::merge(SharkBuilder* builder, + SharkValue* other, + BasicBlock* other_block, + BasicBlock* this_block, + const char* name) { + assert(type() == other->type(), "should be"); + assert(zero_checked() == other->zero_checked(), "should be"); + + PHINode *phi = builder->CreatePHI(SharkType::to_stackType(type()), name); + phi->addIncoming(this->generic_value(), this_block); + phi->addIncoming(other->generic_value(), other_block); + return SharkValue::create_generic(type(), phi, zero_checked()); +} +SharkValue* SharkAddressValue::merge(SharkBuilder* builder, + SharkValue* other, + BasicBlock* other_block, + BasicBlock* this_block, + const char* name) { + assert(this->equal_to(other), "should be"); + return this; +} + +// Repeated null and divide-by-zero check removal + +bool SharkValue::zero_checked() const { + ShouldNotCallThis(); +} +void SharkValue::set_zero_checked(bool zero_checked) { + ShouldNotCallThis(); +} + +bool SharkNormalValue::zero_checked() const { + return _zero_checked; +} +void SharkNormalValue::set_zero_checked(bool zero_checked) { + _zero_checked = zero_checked; +} diff --git a/hotspot/src/share/vm/shark/sharkValue.hpp b/hotspot/src/share/vm/shark/sharkValue.hpp new file mode 100644 index 00000000000..06fcad1be19 --- /dev/null +++ b/hotspot/src/share/vm/shark/sharkValue.hpp @@ -0,0 +1,332 @@ +/* + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// Items on the stack and in local variables are tracked using +// SharkValue objects. +// +// All SharkValues are one of two core types, SharkNormalValue +// and SharkAddressValue, but no code outside this file should +// ever refer to those directly. The split is because of the +// way JSRs are handled: the typeflow pass expands them into +// multiple copies, so the return addresses pushed by jsr and +// popped by ret only exist at compile time. Having separate +// classes for these allows us to check that our jsr handling +// is correct, via assertions. +// +// There is one more type, SharkPHIValue, which is a subclass +// of SharkNormalValue with a couple of extra methods. Use of +// SharkPHIValue outside of this file is acceptable, so long +// as it is obtained via SharkValue::as_phi(). + +class SharkBuilder; +class SharkPHIValue; + +class SharkValue : public ResourceObj { + protected: + SharkValue() {} + + // Cloning + public: + virtual SharkValue* clone() const = 0; + + // Casting + public: + virtual bool is_phi() const; + virtual SharkPHIValue* as_phi(); + + // Comparison + public: + virtual bool equal_to(SharkValue* other) const = 0; + + // Type access + public: + virtual BasicType basic_type() const = 0; + virtual ciType* type() const; + + virtual bool is_jint() const; + virtual bool is_jlong() const; + virtual bool is_jfloat() const; + virtual bool is_jdouble() const; + virtual bool is_jobject() const; + virtual bool is_jarray() const; + virtual bool is_address() const; + + virtual int size() const = 0; + + bool is_one_word() const { + return size() == 1; + } + bool is_two_word() const { + return size() == 2; + } + + // Typed conversion from SharkValues + public: + virtual llvm::Value* jint_value() const; + virtual llvm::Value* jlong_value() const; + virtual llvm::Value* jfloat_value() const; + virtual llvm::Value* jdouble_value() const; + virtual llvm::Value* jobject_value() const; + virtual llvm::Value* jarray_value() const; + virtual int address_value() const; + + // Typed conversion to SharkValues + public: + static SharkValue* create_jint(llvm::Value* value, bool zero_checked) { + assert(value->getType() == SharkType::jint_type(), "should be"); + return create_generic(ciType::make(T_INT), value, zero_checked); + } + static SharkValue* create_jlong(llvm::Value* value, bool zero_checked) { + assert(value->getType() == SharkType::jlong_type(), "should be"); + return create_generic(ciType::make(T_LONG), value, zero_checked); + } + static SharkValue* create_jfloat(llvm::Value* value) { + assert(value->getType() == SharkType::jfloat_type(), "should be"); + return create_generic(ciType::make(T_FLOAT), value, false); + } + static SharkValue* create_jdouble(llvm::Value* value) { + assert(value->getType() == SharkType::jdouble_type(), "should be"); + return create_generic(ciType::make(T_DOUBLE), value, false); + } + static SharkValue* create_jobject(llvm::Value* value, bool zero_checked) { + assert(value->getType() == SharkType::oop_type(), "should be"); + return create_generic(ciType::make(T_OBJECT), value, zero_checked); + } + + // Typed conversion from constants of various types + public: + static SharkValue* jint_constant(jint value) { + return create_jint(LLVMValue::jint_constant(value), value != 0); + } + static SharkValue* jlong_constant(jlong value) { + return create_jlong(LLVMValue::jlong_constant(value), value != 0); + } + static SharkValue* jfloat_constant(jfloat value) { + return create_jfloat(LLVMValue::jfloat_constant(value)); + } + static SharkValue* jdouble_constant(jdouble value) { + return create_jdouble(LLVMValue::jdouble_constant(value)); + } + static SharkValue* null() { + return create_jobject(LLVMValue::null(), false); + } + static inline SharkValue* address_constant(int bci); + + // Type-losing conversions -- use with care! + public: + virtual llvm::Value* generic_value() const = 0; + virtual llvm::Value* intptr_value(SharkBuilder* builder) const; + + static inline SharkValue* create_generic(ciType* type, + llvm::Value* value, + bool zero_checked); + static inline SharkValue* create_phi(ciType* type, + llvm::PHINode* phi, + const SharkPHIValue* parent = NULL); + + // Phi-style stuff + public: + virtual void addIncoming(SharkValue* value, llvm::BasicBlock* block); + virtual SharkValue* merge(SharkBuilder* builder, + SharkValue* other, + llvm::BasicBlock* other_block, + llvm::BasicBlock* this_block, + const char* name) = 0; + + // Repeated null and divide-by-zero check removal + public: + virtual bool zero_checked() const; + virtual void set_zero_checked(bool zero_checked); +}; + +class SharkNormalValue : public SharkValue { + friend class SharkValue; + + protected: + SharkNormalValue(ciType* type, llvm::Value* value, bool zero_checked) + : _type(type), _llvm_value(value), _zero_checked(zero_checked) {} + + private: + ciType* _type; + llvm::Value* _llvm_value; + bool _zero_checked; + + private: + llvm::Value* llvm_value() const { + return _llvm_value; + } + + // Cloning + public: + SharkValue* clone() const; + + // Comparison + public: + bool equal_to(SharkValue* other) const; + + // Type access + public: + ciType* type() const; + BasicType basic_type() const; + int size() const; + + public: + bool is_jint() const; + bool is_jlong() const; + bool is_jfloat() const; + bool is_jdouble() const; + bool is_jobject() const; + bool is_jarray() const; + + // Typed conversions to LLVM values + public: + llvm::Value* jint_value() const; + llvm::Value* jlong_value() const; + llvm::Value* jfloat_value() const; + llvm::Value* jdouble_value() const; + llvm::Value* jobject_value() const; + llvm::Value* jarray_value() const; + + // Type-losing conversions, use with care + public: + llvm::Value* generic_value() const; + llvm::Value* intptr_value(SharkBuilder* builder) const; + + // Phi-style stuff + public: + SharkValue* merge(SharkBuilder* builder, + SharkValue* other, + llvm::BasicBlock* other_block, + llvm::BasicBlock* this_block, + const char* name); + + // Repeated null and divide-by-zero check removal + public: + bool zero_checked() const; + void set_zero_checked(bool zero_checked); +}; + +class SharkPHIValue : public SharkNormalValue { + friend class SharkValue; + + protected: + SharkPHIValue(ciType* type, llvm::PHINode* phi, const SharkPHIValue *parent) + : SharkNormalValue(type, phi, parent && parent->zero_checked()), + _parent(parent), + _all_incomers_zero_checked(true) {} + + private: + const SharkPHIValue* _parent; + bool _all_incomers_zero_checked; + + private: + const SharkPHIValue* parent() const { + return _parent; + } + bool is_clone() const { + return parent() != NULL; + } + + public: + bool all_incomers_zero_checked() const { + if (is_clone()) + return parent()->all_incomers_zero_checked(); + + return _all_incomers_zero_checked; + } + + // Cloning + public: + SharkValue* clone() const; + + // Casting + public: + bool is_phi() const; + SharkPHIValue* as_phi(); + + // Phi-style stuff + public: + void addIncoming(SharkValue *value, llvm::BasicBlock* block); +}; + +class SharkAddressValue : public SharkValue { + friend class SharkValue; + + protected: + SharkAddressValue(int bci) + : _bci(bci) {} + + private: + int _bci; + + // Cloning + public: + SharkValue* clone() const; + + // Comparison + public: + bool equal_to(SharkValue* other) const; + + // Type access + public: + BasicType basic_type() const; + int size() const; + bool is_address() const; + + // Typed conversion from SharkValues + public: + int address_value() const; + + // Type-losing conversion -- use with care! + public: + llvm::Value* generic_value() const; + + // Phi-style stuff + public: + void addIncoming(SharkValue *value, llvm::BasicBlock* block); + SharkValue* merge(SharkBuilder* builder, + SharkValue* other, + llvm::BasicBlock* other_block, + llvm::BasicBlock* this_block, + const char* name); +}; + +// SharkValue methods that can't be declared above + +inline SharkValue* SharkValue::create_generic(ciType* type, + llvm::Value* value, + bool zero_checked) { + return new SharkNormalValue(type, value, zero_checked); +} + +inline SharkValue* SharkValue::create_phi(ciType* type, + llvm::PHINode* phi, + const SharkPHIValue* parent) { + return new SharkPHIValue(type, phi, parent); +} + +inline SharkValue* SharkValue::address_constant(int bci) { + return new SharkAddressValue(bci); +} diff --git a/hotspot/src/share/vm/shark/shark_globals.cpp b/hotspot/src/share/vm/shark/shark_globals.cpp new file mode 100644 index 00000000000..50ea5295d97 --- /dev/null +++ b/hotspot/src/share/vm/shark/shark_globals.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_shark_globals.cpp.incl" + +SHARK_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG) diff --git a/hotspot/src/share/vm/shark/shark_globals.hpp b/hotspot/src/share/vm/shark/shark_globals.hpp new file mode 100644 index 00000000000..f0f7d3bbffa --- /dev/null +++ b/hotspot/src/share/vm/shark/shark_globals.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright 2008, 2009, 2010 Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#define SHARK_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \ + \ + product(intx, MaxNodeLimit, 65000, \ + "Maximum number of nodes") \ + \ + /* inlining */ \ + product(intx, SharkMaxInlineSize, 32, \ + "Maximum bytecode size of methods to inline when using Shark") \ + \ + /* compiler debugging */ \ + develop(ccstr, SharkPrintTypeflowOf, NULL, \ + "Print the typeflow of the specified method") \ + \ + diagnostic(ccstr, SharkPrintBitcodeOf, NULL, \ + "Print the LLVM bitcode of the specified method") \ + \ + diagnostic(ccstr, SharkPrintAsmOf, NULL, \ + "Print the asm of the specified method") \ + \ + develop(bool, SharkTraceBytecodes, false, \ + "Trace bytecode compilation") \ + \ + diagnostic(bool, SharkTraceInstalls, false, \ + "Trace method installation") \ + \ + diagnostic(bool, SharkPerformanceWarnings, false, \ + "Warn about things that could be made faster") \ + +SHARK_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG) diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index 0706ed1c9d6..7b1cd2200b0 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -552,140 +552,6 @@ static address same_page(address x, address y) { } } - -static void find(intptr_t x, bool print_pc) { - address addr = (address)x; - - CodeBlob* b = CodeCache::find_blob_unsafe(addr); - if (b != NULL) { - if (b->is_buffer_blob()) { - // the interpreter is generated into a buffer blob - InterpreterCodelet* i = Interpreter::codelet_containing(addr); - if (i != NULL) { - i->print(); - return; - } - if (Interpreter::contains(addr)) { - tty->print_cr(INTPTR_FORMAT " is pointing into interpreter code (not bytecode specific)", addr); - return; - } - // - if (AdapterHandlerLibrary::contains(b)) { - AdapterHandlerLibrary::print_handler(b); - } - // the stubroutines are generated into a buffer blob - StubCodeDesc* d = StubCodeDesc::desc_for(addr); - if (d != NULL) { - d->print(); - if (print_pc) tty->cr(); - return; - } - if (StubRoutines::contains(addr)) { - tty->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) stub routine", addr); - return; - } - // the InlineCacheBuffer is using stubs generated into a buffer blob - if (InlineCacheBuffer::contains(addr)) { - tty->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", addr); - return; - } - VtableStub* v = VtableStubs::stub_containing(addr); - if (v != NULL) { - v->print(); - return; - } - } - if (print_pc && b->is_nmethod()) { - ResourceMark rm; - tty->print("%#p: Compiled ", addr); - ((nmethod*)b)->method()->print_value_on(tty); - tty->print(" = (CodeBlob*)" INTPTR_FORMAT, b); - tty->cr(); - return; - } - if ( b->is_nmethod()) { - if (b->is_zombie()) { - tty->print_cr(INTPTR_FORMAT " is zombie nmethod", b); - } else if (b->is_not_entrant()) { - tty->print_cr(INTPTR_FORMAT " is non-entrant nmethod", b); - } - } - b->print(); - return; - } - - if (Universe::heap()->is_in(addr)) { - HeapWord* p = Universe::heap()->block_start(addr); - bool print = false; - // If we couldn't find it it just may mean that heap wasn't parseable - // See if we were just given an oop directly - if (p != NULL && Universe::heap()->block_is_obj(p)) { - print = true; - } else if (p == NULL && ((oopDesc*)addr)->is_oop()) { - p = (HeapWord*) addr; - print = true; - } - if (print) { - oop(p)->print(); - if (p != (HeapWord*)x && oop(p)->is_constMethod() && - constMethodOop(p)->contains(addr)) { - Thread *thread = Thread::current(); - HandleMark hm(thread); - methodHandle mh (thread, constMethodOop(p)->method()); - if (!mh->is_native()) { - tty->print_cr("bci_from(%p) = %d; print_codes():", - addr, mh->bci_from(address(x))); - mh->print_codes(); - } - } - return; - } - } else if (Universe::heap()->is_in_reserved(addr)) { - tty->print_cr(INTPTR_FORMAT " is an unallocated location in the heap", addr); - return; - } - - if (JNIHandles::is_global_handle((jobject) addr)) { - tty->print_cr(INTPTR_FORMAT " is a global jni handle", addr); - return; - } - if (JNIHandles::is_weak_global_handle((jobject) addr)) { - tty->print_cr(INTPTR_FORMAT " is a weak global jni handle", addr); - return; - } - if (JNIHandleBlock::any_contains((jobject) addr)) { - tty->print_cr(INTPTR_FORMAT " is a local jni handle", addr); - return; - } - - for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) { - // Check for privilege stack - if (thread->privileged_stack_top() != NULL && thread->privileged_stack_top()->contains(addr)) { - tty->print_cr(INTPTR_FORMAT " is pointing into the privilege stack for thread: " INTPTR_FORMAT, addr, thread); - return; - } - // If the addr is a java thread print information about that. - if (addr == (address)thread) { - thread->print(); - return; - } - } - - // Try an OS specific find - if (os::find(addr)) { - return; - } - - if (print_pc) { - tty->print_cr(INTPTR_FORMAT ": probably in C++ code; check debugger", addr); - Disassembler::decode(same_page(addr-40,addr),same_page(addr+40,addr)); - return; - } - - tty->print_cr(INTPTR_FORMAT " is pointing to unknown location", addr); -} - - class LookForRefInGenClosure : public OopsInGenClosure { public: oop target; @@ -767,7 +633,7 @@ extern "C" void findclass(const char name[]) { // Can we someday rename the other find to hsfind? extern "C" void hsfind(intptr_t x) { Command c("hsfind"); - find(x, false); + os::print_location(tty, x, false); } @@ -778,13 +644,13 @@ extern "C" void hsfindref(intptr_t x) { extern "C" void find(intptr_t x) { Command c("find"); - find(x, false); + os::print_location(tty, x, false); } extern "C" void findpc(intptr_t x) { Command c("findpc"); - find(x, true); + os::print_location(tty, x, true); } diff --git a/hotspot/src/share/vm/utilities/exceptions.cpp b/hotspot/src/share/vm/utilities/exceptions.cpp index 59c6176b80e..ef37af5071b 100644 --- a/hotspot/src/share/vm/utilities/exceptions.cpp +++ b/hotspot/src/share/vm/utilities/exceptions.cpp @@ -117,7 +117,7 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc (address)h_exception(), file, line, thread); } // for AbortVMOnException flag - NOT_PRODUCT(Exceptions::debug_check_abort(h_exception)); + NOT_PRODUCT(Exceptions::debug_check_abort(h_exception, message)); // Check for special boot-strapping/vm-thread handling if (special_exception(thread, file, line, h_exception)) return; @@ -375,17 +375,26 @@ ExceptionMark::~ExceptionMark() { #ifndef PRODUCT // caller frees value_string if necessary -void Exceptions::debug_check_abort(const char *value_string) { +void Exceptions::debug_check_abort(const char *value_string, const char* message) { if (AbortVMOnException != NULL && value_string != NULL && strstr(value_string, AbortVMOnException)) { - fatal(err_msg("Saw %s, aborting", value_string)); + if (AbortVMOnExceptionMessage == NULL || message == NULL || + strcmp(message, AbortVMOnExceptionMessage) == 0) { + fatal(err_msg("Saw %s, aborting", value_string)); + } } } -void Exceptions::debug_check_abort(Handle exception) { +void Exceptions::debug_check_abort(Handle exception, const char* message) { if (AbortVMOnException != NULL) { ResourceMark rm; - debug_check_abort(instanceKlass::cast(exception()->klass())->external_name()); + if (message == NULL && exception->is_a(SystemDictionary::Throwable_klass())) { + oop msg = java_lang_Throwable::message(exception); + if (msg != NULL) { + message = java_lang_String::as_utf8_string(msg); + } + } + debug_check_abort(instanceKlass::cast(exception()->klass())->external_name(), message); } } #endif diff --git a/hotspot/src/share/vm/utilities/exceptions.hpp b/hotspot/src/share/vm/utilities/exceptions.hpp index a331d03f0cc..245bfa4150d 100644 --- a/hotspot/src/share/vm/utilities/exceptions.hpp +++ b/hotspot/src/share/vm/utilities/exceptions.hpp @@ -143,8 +143,8 @@ class Exceptions { static void throw_stack_overflow_exception(Thread* thread, const char* file, int line); // for AbortVMOnException flag - NOT_PRODUCT(static void debug_check_abort(Handle exception);) - NOT_PRODUCT(static void debug_check_abort(const char *value_string);) + NOT_PRODUCT(static void debug_check_abort(Handle exception, const char* message = NULL);) + NOT_PRODUCT(static void debug_check_abort(const char *value_string, const char* message = NULL);) }; diff --git a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp index f069a5377ea..398f01b9471 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp @@ -216,8 +216,16 @@ extern "C" { #define DEBUG_EXCEPTION ::abort(); +#ifdef ARM +#ifdef SOLARIS +#define BREAKPOINT __asm__ volatile (".long 0xe1200070") +#else +#define BREAKPOINT __asm__ volatile (".long 0xe7f001f0") +#endif +#else extern "C" void breakpoint(); #define BREAKPOINT ::breakpoint() +#endif // checking for nanness #ifdef SOLARIS @@ -235,6 +243,12 @@ inline int g_isnan(double f) { return isnan(f); } #error "missing platform-specific definition here" #endif +// GCC 4.3 does not allow 0.0/0.0 to produce a NAN value +#if (__GNUC__ == 4) && (__GNUC_MINOR__ > 2) +#define CAN_USE_NAN_DEFINE 1 +#endif + + // Checking for finiteness inline int g_isfinite(jfloat f) { return finite(f); } diff --git a/hotspot/src/share/vm/utilities/growableArray.hpp b/hotspot/src/share/vm/utilities/growableArray.hpp index becb38ce107..e3941cfcb6f 100644 --- a/hotspot/src/share/vm/utilities/growableArray.hpp +++ b/hotspot/src/share/vm/utilities/growableArray.hpp @@ -97,7 +97,10 @@ class GenericGrowableArray : public ResourceObj { assert(_len >= 0 && _len <= _max, "initial_len too big"); _arena = (c_heap ? (Arena*)1 : NULL); set_nesting(); - assert(!c_heap || allocated_on_C_heap(), "growable array must be on C heap if elements are"); + assert(!on_C_heap() || allocated_on_C_heap(), "growable array must be on C heap if elements are"); + assert(!on_stack() || + (allocated_on_res_area() || allocated_on_stack()), + "growable array must be on stack if elements are not on arena and not on C heap"); } // This GA will use the given arena for storage. @@ -108,6 +111,10 @@ class GenericGrowableArray : public ResourceObj { assert(_len >= 0 && _len <= _max, "initial_len too big"); _arena = arena; assert(on_arena(), "arena has taken on reserved value 0 or 1"); + // Relax next assert to allow object allocation on resource area, + // on stack or embedded into an other object. + assert(allocated_on_arena() || allocated_on_stack(), + "growable array must be on arena or on stack if elements are on arena"); } void* raw_allocate(int elementSize); diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp index 97b86c13410..4f89f2aebe0 100644 --- a/hotspot/src/share/vm/utilities/macros.hpp +++ b/hotspot/src/share/vm/utilities/macros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,9 +151,11 @@ #if defined(IA32) || defined(AMD64) #define X86 #define X86_ONLY(code) code +#define NOT_X86(code) #else #undef X86 #define X86_ONLY(code) +#define NOT_X86(code) code #endif #ifdef IA32 @@ -188,4 +190,37 @@ #define NOT_SPARC(code) code #endif +#ifdef PPC +#define PPC_ONLY(code) code +#define NOT_PPC(code) +#else +#define PPC_ONLY(code) +#define NOT_PPC(code) code +#endif + +#ifdef E500V2 +#define E500V2_ONLY(code) code +#define NOT_E500V2(code) +#else +#define E500V2_ONLY(code) +#define NOT_E500V2(code) code +#endif + + +#ifdef ARM +#define ARM_ONLY(code) code +#define NOT_ARM(code) +#else +#define ARM_ONLY(code) +#define NOT_ARM(code) code +#endif + +#ifdef JAVASE_EMBEDDED +#define EMBEDDED_ONLY(code) code +#define NOT_EMBEDDED(code) +#else +#define EMBEDDED_ONLY(code) +#define NOT_EMBEDDED(code) code +#endif + #define define_pd_global(type, name, value) const type pd_##name = value; diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index a63a7b34330..15d66ab9ceb 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -479,8 +479,8 @@ void VMError::report(outputStream* st) { if (fr.sp()) { st->print(", sp=" PTR_FORMAT, fr.sp()); - st->print(", free space=%" INTPTR_FORMAT "k", - ((intptr_t)fr.sp() - (intptr_t)stack_bottom) >> 10); + size_t free_stack_size = pointer_delta(fr.sp(), stack_bottom, 1024); + st->print(", free space=" SIZE_FORMAT "k", free_stack_size); } st->cr(); @@ -687,16 +687,13 @@ void VMError::report(outputStream* st) { # undef END } +VMError* volatile VMError::first_error = NULL; +volatile jlong VMError::first_error_tid = -1; void VMError::report_and_die() { // Don't allocate large buffer on stack static char buffer[O_BUFLEN]; - // First error, and its thread id. We must be able to handle native thread, - // so use thread id instead of Thread* to identify thread. - static VMError* first_error; - static jlong first_error_tid; - // An error could happen before tty is initialized or after it has been // destroyed. Here we use a very simple unbuffered fdStream for printing. // Only out.print_raw() and out.print_raw_cr() should be used, as other diff --git a/hotspot/src/share/vm/utilities/vmError.hpp b/hotspot/src/share/vm/utilities/vmError.hpp index a2bbca37c2a..4cca492995e 100644 --- a/hotspot/src/share/vm/utilities/vmError.hpp +++ b/hotspot/src/share/vm/utilities/vmError.hpp @@ -57,6 +57,10 @@ class VMError : public StackObj { int _current_step; const char * _current_step_info; int _verbose; + // First error, and its thread id. We must be able to handle native thread, + // so use thread id instead of Thread* to identify thread. + static VMError* volatile first_error; + static volatile jlong first_error_tid; // used by reporting about OOM size_t _size; @@ -108,4 +112,7 @@ public: // returns original handler for signal, if it was resetted, or NULL if // signal was not changed by error reporter static address get_resetted_sighandler(int sig); + + // check to see if fatal error reporting is in progress + static bool fatal_error_in_progress() { return first_error != NULL; } }; diff --git a/hotspot/test/compiler/6973329/Test.java b/hotspot/test/compiler/6973329/Test.java new file mode 100644 index 00000000000..caecf8bbdd9 --- /dev/null +++ b/hotspot/test/compiler/6973329/Test.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 6973329 + * @summary C2 with Zero based COOP produces code with broken anti-dependency on x86 + * + * @run main/othervm -Xbatch -Xcomp -XX:CompileOnly=Test Test + */ + +class A { + A next; + int n; + + public int get_n() { + return n+1; + } +} +public class Test { + + A a; + + void test (A new_next) { + A prev_next = a.next; + a.next = new_next; + if (prev_next == null) { + a.n = a.get_n(); + } + } + + public static void main(String args[]) { + Test t = new Test(); + t.a = new A(); + t.a.n = 1; + t.test(new A()); + if (t.a.n != 2) { + System.out.println("Wrong value: " + t.a.n + " expected: 2"); + System.exit(97); + } + } +} + diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 6761d4606bf..4e045e1be2a 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -79,3 +79,6 @@ d524be5ef62e8b8cb890c59a5d2c19ef0ab50d45 jdk7-b100 15573625af97d01c4e24549041cba7584da7fe88 jdk7-b102 b7722e8788644507c10bb69a137de422d0300b24 jdk7-b103 d42c4acb6424a094bdafe2ad9c8c1c7ca7fb7b7e jdk7-b104 +3233b9a4c12ef2663a356d08bb141c02736c7f49 jdk7-b105 +5ba8469212a6cab95ca652eea414b753be7d245a jdk7-b106 +20ee37c1372a3eaefa49b426c6eb68a2e8f5d6e2 jdk7-b107 diff --git a/jaxws/.hgtags b/jaxws/.hgtags index f7d296f1195..c0a5c32e8d3 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -79,3 +79,6 @@ b55ce274490082712f5e002b38d2eed505ca863d jdk7-b101 d8580443d1815d68e0035a0560634e50fa899288 jdk7-b102 267386d6b923f724309cab855a555e2d86a15c8f jdk7-b103 bbc4cce6c20aeca4862804a6e8315a2350d43633 jdk7-b104 +39eb4f3031f4a985664cace00fca3bd1eab1e0aa jdk7-b105 +bc45ccc5bcca6cbe4ea433e279d4a93b06ab38c6 jdk7-b106 +017612ea6af417a5e378619704da01bb3a583bdb jdk7-b107 diff --git a/jdk/.hgtags b/jdk/.hgtags index 8e2227fdb7a..c06fc47e775 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -79,3 +79,6 @@ d58354a69011f3d3354765fa3167567c4c4a9612 jdk7-b101 13029a61b16bec06535d4f0aa98229b358684128 jdk7-b102 6488b70a23cc6dc4b7e00809bc503c2884bafb28 jdk7-b103 1a92820132a0221c5bdedd42d0888c57ce4cbb34 jdk7-b104 +3b0abcb512807bb6f6d27755bc50103211bde6ee jdk7-b105 +b91ef6b60f4e19bf4592c6dd594c9bac62487519 jdk7-b106 +882103f334bb23745d3fd70fb7928c347478b0f4 jdk7-b107 diff --git a/jdk/make/common/shared/Defs-windows.gmk b/jdk/make/common/shared/Defs-windows.gmk index 121cd94ea49..ac9daf4cd6c 100644 --- a/jdk/make/common/shared/Defs-windows.gmk +++ b/jdk/make/common/shared/Defs-windows.gmk @@ -89,7 +89,7 @@ define FullPath $(shell $(CYGPATH_CMD) $1 2> $(DEV_NULL)) endef define OptFullPath -$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1"; else echo "$1"; fi) +$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1" 2> $(DEV_NULL); else echo "$1"; fi) endef else # Temporary until we upgrade to MKS 8.7, MKS pwd returns mixed mode path diff --git a/jdk/make/common/shared/Defs.gmk b/jdk/make/common/shared/Defs.gmk index 3ccab90196c..ed32779c8c2 100644 --- a/jdk/make/common/shared/Defs.gmk +++ b/jdk/make/common/shared/Defs.gmk @@ -136,15 +136,20 @@ define GetVersion $(shell echo $1 | sed -e 's@[^0-9]*\([0-9][0-9]*\.[0-9][.0-9]*\).*@\1@' ) endef +# Return one part of the version numbers, watch out for non digits. +define VersionWord # Number Version +$(word $1,$(subst ., ,$(subst -, ,$2))) +endef + # Given a major.minor.micro version, return the major, minor, or micro number define MajorVersion -$(if $(word 1, $(subst ., ,$1)),$(word 1, $(subst ., ,$1)),0) +$(if $(call VersionWord,1,$1),$(call VersionWord,1,$1),0) endef define MinorVersion -$(if $(word 2, $(subst ., ,$1)),$(word 2, $(subst ., ,$1)),0) +$(if $(call VersionWord,2,$1),$(call VersionWord,2,$1),0) endef define MicroVersion -$(if $(word 3, $(subst ., ,$1)),$(word 3, $(subst ., ,$1)),0) +$(if $(call VersionWord,3,$1),$(call VersionWord,3,$1),0) endef # Macro that returns missing, same, newer, or older $1=version $2=required diff --git a/jdk/make/jdk_generic_profile.sh b/jdk/make/jdk_generic_profile.sh index 3f2e08446f0..4363a1b710e 100644 --- a/jdk/make/jdk_generic_profile.sh +++ b/jdk/make/jdk_generic_profile.sh @@ -340,6 +340,10 @@ PATH="${path4sdk}" export PATH # Export variables required for Zero +if [ "${SHARK_BUILD}" = true ] ; then + ZERO_BUILD=true + export ZERO_BUILD +fi if [ "${ZERO_BUILD}" = true ] ; then # ZERO_LIBARCH is the name of the architecture-specific # subdirectory under $JAVA_HOME/jre/lib @@ -417,4 +421,55 @@ if [ "${ZERO_BUILD}" = true ] ; then fi export LIBFFI_CFLAGS export LIBFFI_LIBS + + # LLVM_CFLAGS, LLVM_LDFLAGS and LLVM_LIBS tell the compiler how to + # compile and link against LLVM + if [ "${SHARK_BUILD}" = true ] ; then + if [ "${LLVM_CONFIG}" = "" ] ; then + LLVM_CONFIG=$(which llvm-config 2>/dev/null) + fi + if [ ! -x "${LLVM_CONFIG}" ] ; then + echo "ERROR: Unable to locate llvm-config" + exit 1 + fi + llvm_components="jit engine nativecodegen" + + unset LLVM_CFLAGS + for flag in $("${LLVM_CONFIG}" --cxxflags $llvm_components); do + if echo "${flag}" | grep -q '^-[ID]'; then + if [ "${flag}" != "-D_DEBUG" ] ; then + if [ "${LLVM_CFLAGS}" != "" ] ; then + LLVM_CFLAGS="${LLVM_CFLAGS} " + fi + LLVM_CFLAGS="${LLVM_CFLAGS}${flag}" + fi + fi + done + llvm_version=$("${LLVM_CONFIG}" --version | sed 's/\.//; s/svn.*//') + LLVM_CFLAGS="${LLVM_CFLAGS} -DSHARK_LLVM_VERSION=${llvm_version}" + + unset LLVM_LDFLAGS + for flag in $("${LLVM_CONFIG}" --ldflags $llvm_components); do + if echo "${flag}" | grep -q '^-L'; then + if [ "${LLVM_LDFLAGS}" != "" ] ; then + LLVM_LDFLAGS="${LLVM_LDFLAGS} " + fi + LLVM_LDFLAGS="${LLVM_LDFLAGS}${flag}" + fi + done + + unset LLVM_LIBS + for flag in $("${LLVM_CONFIG}" --libs $llvm_components); do + if echo "${flag}" | grep -q '^-l'; then + if [ "${LLVM_LIBS}" != "" ] ; then + LLVM_LIBS="${LLVM_LIBS} " + fi + LLVM_LIBS="${LLVM_LIBS}${flag}" + fi + done + + export LLVM_CFLAGS + export LLVM_LDFLAGS + export LLVM_LIBS + fi fi diff --git a/jdk/make/sun/javazic/tzdata/VERSION b/jdk/make/sun/javazic/tzdata/VERSION index e3847595a31..804986c10b7 100644 --- a/jdk/make/sun/javazic/tzdata/VERSION +++ b/jdk/make/sun/javazic/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2010i +tzdata2010l diff --git a/jdk/make/sun/javazic/tzdata/africa b/jdk/make/sun/javazic/tzdata/africa index c0bdbe92e7e..ce560077e00 100644 --- a/jdk/make/sun/javazic/tzdata/africa +++ b/jdk/make/sun/javazic/tzdata/africa @@ -316,8 +316,25 @@ Rule Egypt 2007 only - Sep Thu>=1 23:00s 0 - # and can be found by searching for "winter" in their search engine # (at least today). +# From Alexander Krivenyshev (2010-07-20): +# According to News from Egypt - Al-Masry Al-Youm Egypt's cabinet has +# decided that Daylight Saving Time will not be used in Egypt during +# Ramadan. +# +# Arabic translation: +# "Clocks to go back during Ramadan--and then forward again" +# +# http://www.almasryalyoum.com/en/news/clocks-go-back-during-ramadan-and-then-forward-again +# +# or +# +# http://www.worldtimezone.com/dst_news/dst_news_egypt02.html +# + Rule Egypt 2008 only - Aug lastThu 23:00s 0 - Rule Egypt 2009 only - Aug 20 23:00s 0 - +Rule Egypt 2010 only - Aug 11 0:00 0 - +Rule Egypt 2010 only - Sep 10 0:00 1:00 S Rule Egypt 2010 max - Sep lastThu 23:00s 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] diff --git a/jdk/make/sun/javazic/tzdata/asia b/jdk/make/sun/javazic/tzdata/asia index d4b6cc3c1d2..bc69266fa95 100644 --- a/jdk/make/sun/javazic/tzdata/asia +++ b/jdk/make/sun/javazic/tzdata/asia @@ -2200,6 +2200,18 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # "At 12:01am Friday, clocks in Israel and the West Bank will change to # 1:01am, while Gaza clocks will change at 12:01am Saturday morning." +# From Steffen Thorsen (2010-08-11): +# According to several sources, including +# +# http://www.maannews.net/eng/ViewDetails.aspx?ID=306795 +# +# the clocks were set back one hour at 2010-08-11 00:00:00 local time in +# Gaza and the West Bank. +# Some more background info: +# +# http://www.timeanddate.com/news/time/westbank-gaza-end-dst-2010.html +# + # The rules for Egypt are stolen from the `africa' file. # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule EgyptAsia 1957 only - May 10 0:00 1:00 S @@ -2220,6 +2232,7 @@ Rule Palestine 2008 only - Aug lastFri 2:00 0 - Rule Palestine 2009 only - Mar lastFri 0:00 1:00 S Rule Palestine 2010 max - Mar lastSat 0:01 1:00 S Rule Palestine 2009 max - Sep Fri>=1 2:00 0 - +Rule Palestine 2010 only - Aug 11 0:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct diff --git a/jdk/make/sun/javazic/tzdata/australasia b/jdk/make/sun/javazic/tzdata/australasia index f66d663986a..b406c592761 100644 --- a/jdk/make/sun/javazic/tzdata/australasia +++ b/jdk/make/sun/javazic/tzdata/australasia @@ -368,10 +368,10 @@ Zone Pacific/Kwajalein 11:09:20 - LMT 1901 # Micronesia # Zone NAME GMTOFF RULES FORMAT [UNTIL] -Zone Pacific/Truk 10:07:08 - LMT 1901 - 10:00 - TRUT # Truk Time -Zone Pacific/Ponape 10:32:52 - LMT 1901 # Kolonia - 11:00 - PONT # Ponape Time +Zone Pacific/Chuuk 10:07:08 - LMT 1901 + 10:00 - CHUT # Chuuk Time +Zone Pacific/Pohnpei 10:32:52 - LMT 1901 # Kolonia + 11:00 - PONT # Pohnpei Time Zone Pacific/Kosrae 10:51:56 - LMT 1901 11:00 - KOST 1969 Oct # Kosrae Time 12:00 - KOST 1999 diff --git a/jdk/make/sun/javazic/tzdata/backward b/jdk/make/sun/javazic/tzdata/backward index 1116af03170..4ccea7c7dbe 100644 --- a/jdk/make/sun/javazic/tzdata/backward +++ b/jdk/make/sun/javazic/tzdata/backward @@ -112,7 +112,9 @@ Link Pacific/Chatham NZ-CHAT Link America/Denver Navajo Link Asia/Shanghai PRC Link Pacific/Pago_Pago Pacific/Samoa -Link Pacific/Truk Pacific/Yap +Link Pacific/Chuuk Pacific/Yap +Link Pacific/Chuuk Pacific/Truk +Link Pacific/Pohnpei Pacific/Ponape Link Europe/Warsaw Poland Link Europe/Lisbon Portugal Link Asia/Taipei ROC diff --git a/jdk/make/sun/javazic/tzdata/europe b/jdk/make/sun/javazic/tzdata/europe index d806f6ef000..6fc7d22f3c2 100644 --- a/jdk/make/sun/javazic/tzdata/europe +++ b/jdk/make/sun/javazic/tzdata/europe @@ -1035,22 +1035,47 @@ Zone Europe/Tallinn 1:39:00 - LMT 1880 2:00 EU EE%sT # Finland -# + # From Hannu Strang (1994-09-25 06:03:37 UTC): # Well, here in Helsinki we're just changing from summer time to regular one, # and it's supposed to change at 4am... + +# From Janne Snabb (2010-0715): # -# From Paul Eggert (2006-03-22): -# Shanks & Pottenger say Finland has switched at 02:00 standard time -# since 1981. Go with Strang instead. +# I noticed that the Finland data is not accurate for years 1981 and 1982. +# During these two first trial years the DST adjustment was made one hour +# earlier than in forthcoming years. Starting 1983 the adjustment was made +# according to the central European standards. # +# This is documented in Heikki Oja: Aikakirja 2007, published by The Almanac +# Office of University of Helsinki, ISBN 952-10-3221-9, available online (in +# Finnish) at +# +# +# http://almanakka.helsinki.fi/aikakirja/Aikakirja2007kokonaan.pdf +# +# +# Page 105 (56 in PDF version) has a handy table of all past daylight savings +# transitions. It is easy enough to interpret without Finnish skills. +# +# This is also confirmed by Finnish Broadcasting Company's archive at: +# +# +# http://www.yle.fi/elavaarkisto/?s=s&g=1&ag=5&t=&a=3401 +# +# +# The news clip from 1981 says that "the time between 2 and 3 o'clock does not +# exist tonight." + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Finland 1942 only - Apr 3 0:00 1:00 S Rule Finland 1942 only - Oct 3 0:00 0 - +Rule Finland 1981 1982 - Mar lastSun 2:00 1:00 S +Rule Finland 1981 1982 - Sep lastSun 3:00 0 - # Zone NAME GMTOFF RULES FORMAT [UNTIL] Zone Europe/Helsinki 1:39:52 - LMT 1878 May 31 1:39:52 - HMT 1921 May # Helsinki Mean Time - 2:00 Finland EE%sT 1981 Mar 29 2:00 + 2:00 Finland EE%sT 1983 2:00 EU EE%sT # Aaland Is diff --git a/jdk/make/sun/javazic/tzdata/leapseconds b/jdk/make/sun/javazic/tzdata/leapseconds index f674e22c18c..50426088b76 100644 --- a/jdk/make/sun/javazic/tzdata/leapseconds +++ b/jdk/make/sun/javazic/tzdata/leapseconds @@ -82,9 +82,9 @@ Leap 2008 Dec 31 23:59:60 + S # FAX : 33 (0) 1 40 51 22 91 # Internet : services.iers@obspm.fr # -# Paris, 4 July 2009 +# Paris, 14 July 2010 # -# Bulletin C 38 +# Bulletin C 40 # # To authorities responsible # for the measurement and @@ -92,9 +92,9 @@ Leap 2008 Dec 31 23:59:60 + S # # INFORMATION ON UTC - TAI # -# NO positive leap second will be introduced at the end of December 2009. +# NO positive leap second will be introduced at the end of December 2010. # The difference between Coordinated Universal Time UTC and the -# International Atomic Time TAI is : +# International Atomic Time TAI is : # # from 2009 January 1, 0h UTC, until further notice : UTC-TAI = -34 s # @@ -104,6 +104,6 @@ Leap 2008 Dec 31 23:59:60 + S # will be no time step at the next possible date. # # Daniel GAMBIS -# Director +# Director # Earth Orientation Center of IERS # Observatoire de Paris, France diff --git a/jdk/make/sun/javazic/tzdata/northamerica b/jdk/make/sun/javazic/tzdata/northamerica index ed833a1e358..d07c69c9b45 100644 --- a/jdk/make/sun/javazic/tzdata/northamerica +++ b/jdk/make/sun/javazic/tzdata/northamerica @@ -1346,6 +1346,83 @@ Zone America/Montreal -4:54:16 - LMT 1884 # entry since our cutoff date of 1970, so we can move # America/Coral_Harbour to the 'backward' file. +# From Mark Brader (2010-03-06): +# +# Currently the database has: +# +# # Ontario +# +# # From Paul Eggert (2006-07-09): +# # Shanks & Pottenger write that since 1970 most of Ontario has been like +# # Toronto. +# # Thunder Bay skipped DST in 1973. +# # Many smaller locales did not observe peacetime DST until 1974; +# # Nipigon (EST) and Rainy River (CST) are the largest that we know of. +# +# In the (Toronto) Globe and Mail for Saturday, 1955-09-24, in the bottom +# right corner of page 1, it says that Toronto will return to standard +# time at 2 am Sunday morning (which agrees with the database), and that: +# +# The one-hour setback will go into effect throughout most of Ontario, +# except in areas like Windsor which remains on standard time all year. +# +# Windsor is, of course, a lot larger than Nipigon. +# +# I only came across this incidentally. I don't know if Windsor began +# observing DST when Detroit did, or in 1974, or on some other date. +# +# By the way, the article continues by noting that: +# +# Some cities in the United States have pushed the deadline back +# three weeks and will change over from daylight saving in October. + +# From Arthur David Olson (2010-07-17): +# +# "Standard Time and Time Zones in Canada" appeared in +# The Journal of The Royal Astronomical Society of Canada, +# volume 26, number 2 (February 1932) and, as of 2010-07-17, +# was available at +# +# http://adsabs.harvard.edu/full/1932JRASC..26...49S +# +# +# It includes the text below (starting on page 57): +# +# A list of the places in Canada using daylight saving time would +# require yearly revision. From information kindly furnished by +# the provincial governments and by the postmasters in many cities +# and towns, it is found that the following places used daylight sav- +# ing in 1930. The information for the province of Quebec is definite, +# for the other provinces only approximate: +# +# Province Daylight saving time used +# Prince Edward Island Not used. +# Nova Scotia In Halifax only. +# New Brunswick In St. John only. +# Quebec In the following places: +# Montreal Lachine +# Quebec Mont-Royal +# Levis Iberville +# St. Lambert Cap de la Madeleine +# Verdun Loretteville +# Westmount Richmond +# Outremont St. Jerome +# Longueuil Greenfield Park +# Arvida Waterloo +# Chambly-Canton Beaulieu +# Melbourne La Tuque +# St. Theophile Buckingham +# Ontario Used generally in the cities and towns along +# the southerly part of the province. Not +# used in the northwesterlhy part. +# Manitoba Not used. +# Saskatchewan In Regina only. +# Alberta Not used. +# British Columbia Not used. +# +# With some exceptions, the use of daylight saving may be said to be limited +# to those cities and towns lying between Quebec city and Windsor, Ont. + # Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S Rule Toronto 1919 only - Mar 30 23:30 1:00 D Rule Toronto 1919 only - Oct 26 0:00 0 S @@ -2111,7 +2188,44 @@ Zone America/Hermosillo -7:23:52 - LMT 1921 Dec 31 23:36:08 -8:00 - PST 1970 -7:00 Mexico M%sT 1999 -7:00 - MST + +# From Alexander Krivenyshev (2010-04-21): +# According to news, Bahía de Banderas (Mexican state of Nayarit) +# changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to +# share the same time zone as nearby city Puerto Vallarta, Jalisco). +# +# (Spanish) +# Bahía de Banderas homologa su horario al del centro del +# país, a partir de este domingo +# +# http://www.nayarit.gob.mx/notes.asp?id=20748 +# +# +# Bahía de Banderas homologa su horario con el del Centro del +# País +# +# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50" +# +# +# (English) +# Puerto Vallarta and Bahía de Banderas: One Time Zone +# +# http://virtualvallarta.com/puertovallarta/puertovallarta/localnews/2009-12-03-Puerto-Vallarta-and-Bahia-de-Banderas-One-Time-Zone.shtml +# +# +# or +# +# http://www.worldtimezone.com/dst_news/dst_news_mexico08.html +# +# +# "Mexico's Senate approved the amendments to the Mexican Schedule System that +# will allow Bahía de Banderas and Puerto Vallarta to share the same time +# zone ..." # Baja California Sur, Nayarit, Sinaloa + +# From Arthur David Olson (2010-05-01): +# Use "Bahia_Banderas" to keep the name to fourteen characters. + Zone America/Mazatlan -7:05:40 - LMT 1921 Dec 31 23:54:20 -7:00 - MST 1927 Jun 10 23:00 -6:00 - CST 1930 Nov 15 @@ -2122,6 +2236,19 @@ Zone America/Mazatlan -7:05:40 - LMT 1921 Dec 31 23:54:20 -7:00 - MST 1949 Jan 14 -8:00 - PST 1970 -7:00 Mexico M%sT + +Zone America/Bahia_Banderas -7:01:00 - LMT 1921 Dec 31 23:59:00 + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 + -7:00 - MST 1931 May 1 23:00 + -6:00 - CST 1931 Oct + -7:00 - MST 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 + -7:00 Mexico M%sT 2010 Apr 4 2:00 + -6:00 Mexico C%sT + # Baja California (near US border) Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 0:11:56 -7:00 - MST 1924 diff --git a/jdk/make/sun/javazic/tzdata/zone.tab b/jdk/make/sun/javazic/tzdata/zone.tab index 0d5feba865b..b63bd11ffc4 100644 --- a/jdk/make/sun/javazic/tzdata/zone.tab +++ b/jdk/make/sun/javazic/tzdata/zone.tab @@ -199,8 +199,8 @@ ET +0902+03842 Africa/Addis_Ababa FI +6010+02458 Europe/Helsinki FJ -1808+17825 Pacific/Fiji FK -5142-05751 Atlantic/Stanley -FM +0725+15147 Pacific/Truk Truk (Chuuk) and Yap -FM +0658+15813 Pacific/Ponape Ponape (Pohnpei) +FM +0725+15147 Pacific/Chuuk Chuuk (Truk) and Yap +FM +0658+15813 Pacific/Pohnpei Pohnpei (Ponape) FM +0519+16259 Pacific/Kosrae Kosrae FO +6201-00646 Atlantic/Faroe FR +4852+00220 Europe/Paris @@ -310,6 +310,7 @@ MX +2934-10425 America/Ojinaga US Mountain Time - Chihuahua near US border MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora MX +3232-11701 America/Tijuana US Pacific Time - Baja California near US border MX +3018-11452 America/Santa_Isabel Mexican Pacific Time - Baja California away from US border +MX +2048-10515 America/Bahia_Banderas Mexican Central Time - Bahia de Banderas MY +0310+10142 Asia/Kuala_Lumpur peninsular Malaysia MY +0133+11020 Asia/Kuching Sabah & Sarawak MZ -2558+03235 Africa/Maputo diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java index 515218729ed..0c1b0954300 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Attribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ package com.sun.java.util.jar.pack; import java.io.*; import java.util.*; -import com.sun.java.util.jar.pack.Package.Class; import com.sun.java.util.jar.pack.ConstantPool.*; /** @@ -96,20 +95,20 @@ class Attribute implements Comparable, Constants { return this.def.compareTo(that.def); } - static private final byte[] noBytes = {}; - static private final HashMap canonLists = new HashMap(); - static private final HashMap attributes = new HashMap(); - static private final HashMap standardDefs = new HashMap(); + private static final byte[] noBytes = {}; + private static final Map, List> canonLists = new HashMap<>(); + private static final Map attributes = new HashMap<>(); + private static final Map standardDefs = new HashMap<>(); // Canonicalized lists of trivial attrs (Deprecated, etc.) // are used by trimToSize, in order to reduce footprint // of some common cases. (Note that Code attributes are // always zero size.) - public static List getCanonList(List al) { + public static List getCanonList(List al) { synchronized (canonLists) { - List cl = (List) canonLists.get(al); + List cl = canonLists.get(al); if (cl == null) { - cl = new ArrayList(al.size()); + cl = new ArrayList<>(al.size()); cl.addAll(al); cl = Collections.unmodifiableList(cl); canonLists.put(al, cl); @@ -122,7 +121,7 @@ class Attribute implements Comparable, Constants { public static Attribute find(int ctype, String name, String layout) { Layout key = Layout.makeKey(ctype, name, layout); synchronized (attributes) { - Attribute a = (Attribute) attributes.get(key); + Attribute a = attributes.get(key); if (a == null) { a = new Layout(ctype, name, layout).canonicalInstance(); attributes.put(key, a); @@ -131,24 +130,29 @@ class Attribute implements Comparable, Constants { } } - public static Object keyForLookup(int ctype, String name) { + public static Layout keyForLookup(int ctype, String name) { return Layout.makeKey(ctype, name); } // Find canonical empty attribute with given ctype and name, // and with the standard layout. - public static Attribute lookup(Map defs, int ctype, String name) { - if (defs == null) defs = standardDefs; - return (Attribute) defs.get(Layout.makeKey(ctype, name)); + public static Attribute lookup(Map defs, int ctype, + String name) { + if (defs == null) { + defs = standardDefs; + } + return defs.get(Layout.makeKey(ctype, name)); } - public static Attribute define(Map defs, int ctype, String name, String layout) { + + public static Attribute define(Map defs, int ctype, + String name, String layout) { Attribute a = find(ctype, name, layout); defs.put(Layout.makeKey(ctype, name), a); return a; } static { - Map sd = standardDefs; + Map sd = standardDefs; define(sd, ATTR_CONTEXT_CLASS, "Signature", "RSH"); define(sd, ATTR_CONTEXT_CLASS, "Synthetic", ""); define(sd, ATTR_CONTEXT_CLASS, "Deprecated", ""); @@ -244,7 +248,7 @@ class Attribute implements Comparable, Constants { +"\n ()[] ]" ) }; - Map sd = standardDefs; + Map sd = standardDefs; String defaultLayout = mdLayouts[2]; String annotationsLayout = mdLayouts[1] + mdLayouts[2]; String paramsLayout = mdLayouts[0] + annotationsLayout; @@ -275,10 +279,6 @@ class Attribute implements Comparable, Constants { return null; } - public static Map getStandardDefs() { - return new HashMap(standardDefs); - } - /** Base class for any attributed object (Class, Field, Method, Code). * Flags are included because they are used to help transmit the * presence of attributes. That is, flags are a mix of modifier @@ -291,7 +291,7 @@ class Attribute implements Comparable, Constants { protected abstract Entry[] getCPMap(); protected int flags; // defined here for convenience - protected List attributes; + protected List attributes; public int attributeSize() { return (attributes == null) ? 0 : attributes.size(); @@ -301,16 +301,15 @@ class Attribute implements Comparable, Constants { if (attributes == null) { return; } - if (attributes.size() == 0) { + if (attributes.isEmpty()) { attributes = null; return; } if (attributes instanceof ArrayList) { - ArrayList al = (ArrayList) attributes; + ArrayList al = (ArrayList)attributes; al.trimToSize(); boolean allCanon = true; - for (Iterator i = al.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : al) { if (!a.isCanonical()) { allCanon = false; } @@ -330,9 +329,9 @@ class Attribute implements Comparable, Constants { public void addAttribute(Attribute a) { if (attributes == null) - attributes = new ArrayList(3); + attributes = new ArrayList<>(3); else if (!(attributes instanceof ArrayList)) - attributes = new ArrayList(attributes); // unfreeze it + attributes = new ArrayList<>(attributes); // unfreeze it attributes.add(a); } @@ -340,32 +339,31 @@ class Attribute implements Comparable, Constants { if (attributes == null) return null; if (!attributes.contains(a)) return null; if (!(attributes instanceof ArrayList)) - attributes = new ArrayList(attributes); // unfreeze it + attributes = new ArrayList<>(attributes); // unfreeze it attributes.remove(a); return a; } public Attribute getAttribute(int n) { - return (Attribute) attributes.get(n); + return attributes.get(n); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { if (attributes == null) return; - for (Iterator i = attributes.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : attributes) { a.visitRefs(this, mode, refs); } } - static final List noAttributes = Arrays.asList(new Object[0]); + static final List noAttributes = Arrays.asList(new Attribute[0]); - public List getAttributes() { + public List getAttributes() { if (attributes == null) return noAttributes; return attributes; } - public void setAttributes(List attrList) { + public void setAttributes(List attrList) { if (attrList.isEmpty()) attributes = null; else @@ -374,8 +372,7 @@ class Attribute implements Comparable, Constants { public Attribute getAttribute(String attrName) { if (attributes == null) return null; - for (Iterator i = attributes.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : attributes) { if (a.name().equals(attrName)) return a; } @@ -384,8 +381,7 @@ class Attribute implements Comparable, Constants { public Attribute getAttribute(Layout attrDef) { if (attributes == null) return null; - for (Iterator i = attributes.iterator(); i.hasNext(); ) { - Attribute a = (Attribute) i.next(); + for (Attribute a : attributes) { if (a.layout() == attrDef) return a; } @@ -457,14 +453,8 @@ class Attribute implements Comparable, Constants { public String layout() { return layout; } public Attribute canonicalInstance() { return canon; } - // Cache of name reference. - private Entry nameRef; // name, for use by visitRefs public Entry getNameRef() { - Entry nameRef = this.nameRef; - if (nameRef == null) { - this.nameRef = nameRef = ConstantPool.getUtf8Entry(name()); - } - return nameRef; + return ConstantPool.getUtf8Entry(name()); } public boolean isEmpty() { return layout == ""; } @@ -834,14 +824,14 @@ class Attribute implements Comparable, Constants { */ static //private Layout.Element[] tokenizeLayout(Layout self, int curCble, String layout) { - ArrayList col = new ArrayList(layout.length()); + ArrayList col = new ArrayList<>(layout.length()); tokenizeLayout(self, curCble, layout, col); Layout.Element[] res = new Layout.Element[col.size()]; col.toArray(res); return res; } static //private - void tokenizeLayout(Layout self, int curCble, String layout, ArrayList col) { + void tokenizeLayout(Layout self, int curCble, String layout, ArrayList col) { boolean prevBCI = false; for (int len = layout.length(), i = 0; i < len; ) { int start = i; @@ -899,7 +889,7 @@ class Attribute implements Comparable, Constants { case 'T': // union: 'T' any_int union_case* '(' ')' '[' body ']' kind = EK_UN; i = tokenizeSInt(e, layout, i); - ArrayList cases = new ArrayList(); + ArrayList cases = new ArrayList<>(); for (;;) { // Keep parsing cases until we hit the default case. if (layout.charAt(i++) != '(') @@ -1053,7 +1043,7 @@ class Attribute implements Comparable, Constants { } static //private String[] splitBodies(String layout) { - ArrayList bodies = new ArrayList(); + ArrayList bodies = new ArrayList<>(); // Parse several independent layout bodies: "[foo][bar]...[baz]" for (int i = 0; i < layout.length(); i++) { if (layout.charAt(i++) != '[') @@ -1132,7 +1122,9 @@ class Attribute implements Comparable, Constants { int parseIntBefore(String layout, int dash) { int end = dash; int beg = end; - while (beg > 0 && isDigit(layout.charAt(beg-1))) --beg; + while (beg > 0 && isDigit(layout.charAt(beg-1))) { + --beg; + } if (beg == end) return Integer.parseInt("empty"); // skip backward over a sign if (beg >= 1 && layout.charAt(beg-1) == '-') --beg; @@ -1145,7 +1137,9 @@ class Attribute implements Comparable, Constants { int end = beg; int limit = layout.length(); if (end < limit && layout.charAt(end) == '-') ++end; - while (end < limit && isDigit(layout.charAt(end))) ++end; + while (end < limit && isDigit(layout.charAt(end))) { + ++end; + } if (beg == end) return Integer.parseInt("empty"); return Integer.parseInt(layout.substring(beg, end)); } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java index ab138bc2d91..ac6199abe25 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package com.sun.java.util.jar.pack; -import java.io.*; import java.util.*; /** @@ -40,20 +39,13 @@ class ConstantPool implements Constants { return Utils.currentPropMap().getInteger(Utils.DEBUG_VERBOSE); } - // Uniquification tables for factory methods: - private static final HashMap utf8Entries = new HashMap(); - private static final HashMap classEntries = new HashMap(); - private static final HashMap literalEntries = new HashMap(); - private static final HashMap signatureEntries = new HashMap(); - private static final HashMap descriptorEntries = new HashMap(); - private static final HashMap memberEntries = new HashMap(); - /** Factory for Utf8 string constants. * Used for well-known strings like "SourceFile", "", etc. * Also used to back up more complex constant pool entries, like Class. */ public static synchronized Utf8Entry getUtf8Entry(String value) { - Utf8Entry e = (Utf8Entry) utf8Entries.get(value); + Map utf8Entries = Utils.getUtf8Entries(); + Utf8Entry e = utf8Entries.get(value); if (e == null) { e = new Utf8Entry(value); utf8Entries.put(e.stringValue(), e); @@ -62,9 +54,10 @@ class ConstantPool implements Constants { } /** Factory for Class constants. */ public static synchronized ClassEntry getClassEntry(String name) { - ClassEntry e = (ClassEntry) classEntries.get(name); + Map classEntries = Utils.getClassEntries(); + ClassEntry e = classEntries.get(name); if (e == null) { - e = (ClassEntry) new ClassEntry(getUtf8Entry(name)); + e = new ClassEntry(getUtf8Entry(name)); assert(name.equals(e.stringValue())); classEntries.put(e.stringValue(), e); } @@ -72,7 +65,8 @@ class ConstantPool implements Constants { } /** Factory for literal constants (String, Integer, etc.). */ public static synchronized LiteralEntry getLiteralEntry(Comparable value) { - LiteralEntry e = (LiteralEntry) literalEntries.get(value); + Map literalEntries = Utils.getLiteralEntries(); + LiteralEntry e = literalEntries.get(value); if (e == null) { if (value instanceof String) e = new StringEntry(getUtf8Entry((String)value)); @@ -89,7 +83,8 @@ class ConstantPool implements Constants { /** Factory for signature (type) constants. */ public static synchronized SignatureEntry getSignatureEntry(String type) { - SignatureEntry e = (SignatureEntry) signatureEntries.get(type); + Map signatureEntries = Utils.getSignatureEntries(); + SignatureEntry e = signatureEntries.get(type); if (e == null) { e = new SignatureEntry(type); assert(e.stringValue().equals(type)); @@ -104,8 +99,9 @@ class ConstantPool implements Constants { /** Factory for descriptor (name-and-type) constants. */ public static synchronized DescriptorEntry getDescriptorEntry(Utf8Entry nameRef, SignatureEntry typeRef) { + Map descriptorEntries = Utils.getDescriptorEntries(); String key = DescriptorEntry.stringValueOf(nameRef, typeRef); - DescriptorEntry e = (DescriptorEntry) descriptorEntries.get(key); + DescriptorEntry e = descriptorEntries.get(key); if (e == null) { e = new DescriptorEntry(nameRef, typeRef); assert(e.stringValue().equals(key)) @@ -121,8 +117,9 @@ class ConstantPool implements Constants { /** Factory for member reference constants. */ public static synchronized MemberEntry getMemberEntry(byte tag, ClassEntry classRef, DescriptorEntry descRef) { + Map memberEntries = Utils.getMemberEntries(); String key = MemberEntry.stringValueOf(tag, classRef, descRef); - MemberEntry e = (MemberEntry) memberEntries.get(key); + MemberEntry e = memberEntries.get(key); if (e == null) { e = new MemberEntry(tag, classRef, descRef); assert(e.stringValue().equals(key)) @@ -489,8 +486,9 @@ class ConstantPool implements Constants { String[] parts = structureSignature(value); formRef = getUtf8Entry(parts[0]); classRefs = new ClassEntry[parts.length-1]; - for (int i = 1; i < parts.length; i++) - classRefs[i-1] = getClassEntry(parts[i]); + for (int i = 1; i < parts.length; i++) { + classRefs[i - 1] = getClassEntry(parts[i]); + } hashCode(); // force computation of valueHash } protected int computeValueHash() { @@ -527,8 +525,9 @@ class ConstantPool implements Constants { String stringValueOf(Utf8Entry formRef, ClassEntry[] classRefs) { String[] parts = new String[1+classRefs.length]; parts[0] = formRef.stringValue(); - for (int i = 1; i < parts.length; i++) - parts[i] = classRefs[i-1].stringValue(); + for (int i = 1; i < parts.length; i++) { + parts[i] = classRefs[i - 1].stringValue(); + } return flattenSignature(parts).intern(); } @@ -543,19 +542,23 @@ class ConstantPool implements Constants { int size = 0; for (int i = min; i < max; i++) { switch (form.charAt(i)) { - case 'D': - case 'J': - if (countDoublesTwice) size++; - break; - case '[': - // Skip rest of array info. - while (form.charAt(i) == '[') ++i; - break; - case ';': - continue; - default: - assert(0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i))); - break; + case 'D': + case 'J': + if (countDoublesTwice) { + size++; + } + break; + case '[': + // Skip rest of array info. + while (form.charAt(i) == '[') { + ++i; + } + break; + case ';': + continue; + default: + assert (0 <= JAVA_SIGNATURE_CHARS.indexOf(form.charAt(i))); + break; } size++; } @@ -586,8 +589,9 @@ class ConstantPool implements Constants { s = "/" + formRef.stringValue(); } int i; - while ((i = s.indexOf(';')) >= 0) - s = s.substring(0,i) + s.substring(i+1); + while ((i = s.indexOf(';')) >= 0) { + s = s.substring(0, i) + s.substring(i + 1); + } return s; } } @@ -732,11 +736,11 @@ class ConstantPool implements Constants { clearIndex(); this.cpMap = cpMap; } - protected Index(String debugName, Collection cpMapList) { + protected Index(String debugName, Collection cpMapList) { this(debugName); setMap(cpMapList); } - protected void setMap(Collection cpMapList) { + protected void setMap(Collection cpMapList) { cpMap = new Entry[cpMapList.size()]; cpMapList.toArray(cpMap); setMap(cpMap); @@ -756,11 +760,13 @@ class ConstantPool implements Constants { // // As a special hack, if flattenSigs, signatures are // treated as equivalent entries of cpMap. This is wrong - // fron a Collection point of view, because contains() + // from a Collection point of view, because contains() // reports true for signatures, but the iterator() // never produces them! private int findIndexOf(Entry e) { - if (indexKey == null) initializeIndex(); + if (indexKey == null) { + initializeIndex(); + } int probe = findIndexLocation(e); if (indexKey[probe] != e) { if (flattenSigs && e.tag == CONSTANT_Signature) { @@ -832,7 +838,9 @@ class ConstantPool implements Constants { System.out.println("initialize Index "+debugName+" ["+size()+"]"); int hsize0 = (int)((cpMap.length + 10) * 1.5); int hsize = 1; - while (hsize < hsize0) hsize <<= 1; + while (hsize < hsize0) { + hsize <<= 1; + } indexKey = new Entry[hsize]; indexValue = new int[hsize]; for (int i = 0; i < cpMap.length; i++) { @@ -855,7 +863,7 @@ class ConstantPool implements Constants { return toArray(new Entry[size()]); } public Object clone() { - return new Index(debugName, (Entry[]) cpMap.clone()); + return new Index(debugName, cpMap.clone()); } public String toString() { return "Index "+debugName+" ["+size()+"]"; @@ -901,22 +909,24 @@ class ConstantPool implements Constants { public static Index[] partition(Index ix, int[] keys) { // %%% Should move this into class Index. - ArrayList parts = new ArrayList(); + ArrayList> parts = new ArrayList<>(); Entry[] cpMap = ix.cpMap; assert(keys.length == cpMap.length); for (int i = 0; i < keys.length; i++) { int key = keys[i]; if (key < 0) continue; - while (key >= parts.size()) parts.add(null); - ArrayList part = (ArrayList) parts.get(key); + while (key >= parts.size()) { + parts.add(null); + } + List part = parts.get(key); if (part == null) { - parts.set(key, part = new ArrayList()); + parts.set(key, part = new ArrayList<>()); } part.add(cpMap[i]); } Index[] indexes = new Index[parts.size()]; for (int key = 0; key < indexes.length; key++) { - ArrayList part = (ArrayList) parts.get(key); + List part = parts.get(key); if (part == null) continue; indexes[key] = new Index(ix.debugName+"/part#"+key, part); assert(indexes[key].indexOf(part.get(0)) == 0); @@ -1048,9 +1058,10 @@ class ConstantPool implements Constants { whichClasses[i] = whichClass; } perClassIndexes = partition(allMembers, whichClasses); - for (int i = 0; i < perClassIndexes.length; i++) - assert(perClassIndexes[i]==null - || perClassIndexes[i].assertIsSorted()); + for (int i = 0; i < perClassIndexes.length; i++) { + assert (perClassIndexes[i] == null || + perClassIndexes[i].assertIsSorted()); + } indexByTagAndClass[tag] = perClassIndexes; } int whichClass = allClasses.indexOf(classRef); @@ -1113,7 +1124,7 @@ class ConstantPool implements Constants { * Also, discard null from cpRefs. */ public static - void completeReferencesIn(Set cpRefs, boolean flattenSigs) { + void completeReferencesIn(Set cpRefs, boolean flattenSigs) { cpRefs.remove(null); for (ListIterator work = new ArrayList(cpRefs).listIterator(cpRefs.size()); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java index 50d145db99f..2630febb7c3 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package com.sun.java.util.jar.pack; -import java.lang.Error; import java.io.*; import java.text.MessageFormat; import java.util.*; @@ -35,10 +34,11 @@ import java.util.zip.*; /** Command line interface for Pack200. */ class Driver { - private static final ResourceBundle RESOURCE= ResourceBundle.getBundle("com.sun.java.util.jar.pack.DriverResource"); + private static final ResourceBundle RESOURCE = + ResourceBundle.getBundle("com.sun.java.util.jar.pack.DriverResource"); public static void main(String[] ava) throws IOException { - ArrayList av = new ArrayList(Arrays.asList(ava)); + ArrayList av = new ArrayList<>(Arrays.asList(ava)); boolean doPack = true; boolean doUnpack = false; @@ -61,7 +61,7 @@ class Driver { } // Collect engine properties here: - HashMap engProps = new HashMap(); + HashMap engProps = new HashMap<>(); engProps.put(verboseProp, System.getProperty(verboseProp)); String optionMap; @@ -75,7 +75,7 @@ class Driver { } // Collect argument properties here: - HashMap avProps = new HashMap(); + HashMap avProps = new HashMap<>(); try { for (;;) { String state = parseCommandOptions(av, optionMap, avProps); @@ -133,8 +133,9 @@ class Driver { if (engProps.get(verboseProp) != null) fileProps.list(System.out); propIn.close(); - for (Map.Entry me : fileProps.entrySet()) - engProps.put((String)me.getKey(), (String)me.getValue()); + for (Map.Entry me : fileProps.entrySet()) { + engProps.put((String) me.getKey(), (String) me.getValue()); + } } else if (state == "--version") { System.out.println(MessageFormat.format(RESOURCE.getString(DriverResource.VERSION), Driver.class.getName(), "1.31, 07/05/05")); return; @@ -493,7 +494,7 @@ class Driver { String resultString = null; // Convert options string into optLines dictionary. - TreeMap optmap = new TreeMap(); + TreeMap optmap = new TreeMap<>(); loadOptmap: for (String optline : options.split("\n")) { String[] words = optline.split("\\p{Space}+"); @@ -687,7 +688,9 @@ class Driver { // Report number of arguments consumed. args.subList(0, argp.nextIndex()).clear(); // Report any unconsumed partial argument. - while (pbp.hasPrevious()) args.add(0, pbp.previous()); + while (pbp.hasPrevious()) { + args.add(0, pbp.previous()); + } //System.out.println(args+" // "+properties+" -> "+resultString); return resultString; } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java index f8c55dc6656..c6d96085180 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,13 +28,8 @@ package com.sun.java.util.jar.pack; import java.nio.*; import java.io.*; -import java.nio.channels.*; -import java.util.Date; import java.util.jar.*; import java.util.zip.*; -import java.util.*; -//import com.sun.java.util.jar.pack.Pack200; - class NativeUnpack { // Pointer to the native unpacker obj @@ -91,13 +86,13 @@ class NativeUnpack { NativeUnpack(UnpackerImpl p200) { super(); _p200 = p200; - _props = p200._props; + _props = p200.props; p200._nunp = this; } // for JNI callbacks static private Object currentInstance() { - UnpackerImpl p200 = (UnpackerImpl) Utils.currentInstance.get(); + UnpackerImpl p200 = (UnpackerImpl) Utils.getTLGlobals(); return (p200 == null)? null: p200._nunp; } @@ -216,10 +211,10 @@ class NativeUnpack { ++_fileCount; updateProgress(); } + presetInput = getUnusedInput(); long consumed = finish(); if (_verbose > 0) Utils.log.info("bytes consumed = "+consumed); - presetInput = getUnusedInput(); if (presetInput == null && !Utils.isPackMagic(Utils.readMagic(in))) { break; diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java index 1ea04690ed8..29d217687c4 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Package.java @@ -25,9 +25,9 @@ package com.sun.java.util.jar.pack; +import com.sun.java.util.jar.pack.Attribute.Layout; import java.lang.reflect.Modifier; import java.util.*; -import java.util.zip.*; import java.util.jar.*; import java.io.*; import com.sun.java.util.jar.pack.ConstantPool.*; @@ -77,10 +77,11 @@ class Package implements Constants { cp = new ConstantPool.IndexGroup(); classes.clear(); files.clear(); + BandStructure.nextSeqForDebug = 0; } int getPackageVersion() { - return (package_majver << 16) + (int)package_minver; + return (package_majver << 16) + package_minver; } // Special empty versions of Code and InnerClasses, used for markers. @@ -89,7 +90,7 @@ class Package implements Constants { public static final Attribute.Layout attrSourceFileSpecial; public static final Map attrDefs; static { - HashMap ad = new HashMap(2); + HashMap ad = new HashMap<>(3); attrCodeEmpty = Attribute.define(ad, ATTR_CONTEXT_METHOD, "Code", "").layout(); attrInnerClassesEmpty = Attribute.define(ad, ATTR_CONTEXT_CLASS, @@ -159,9 +160,9 @@ class Package implements Constants { } } - ArrayList classes = new ArrayList(); + ArrayList classes = new ArrayList<>(); - public List getClasses() { + public List getClasses() { return classes; } @@ -186,11 +187,11 @@ class Package implements Constants { ClassEntry[] interfaces; // Class parts - ArrayList fields; - ArrayList methods; + ArrayList fields; + ArrayList methods; //ArrayList attributes; // in Attribute.Holder.this.attributes // Note that InnerClasses may be collected at the package level. - ArrayList innerClasses; + ArrayList innerClasses; Class(int flags, ClassEntry thisClass, ClassEntry superClass, ClassEntry[] interfaces) { this.magic = JAVA_MAGIC; @@ -270,7 +271,7 @@ class Package implements Constants { if (a != olda) { if (verbose > 2) Utils.log.fine("recoding obvious SourceFile="+obvious); - List newAttrs = new ArrayList(getAttributes()); + List newAttrs = new ArrayList<>(getAttributes()); int where = newAttrs.indexOf(olda); newAttrs.set(where, a); setAttributes(newAttrs); @@ -295,12 +296,12 @@ class Package implements Constants { boolean hasInnerClasses() { return innerClasses != null; } - List getInnerClasses() { + List getInnerClasses() { return innerClasses; } - public void setInnerClasses(Collection ics) { - innerClasses = (ics == null) ? null : new ArrayList(ics); + public void setInnerClasses(Collection ics) { + innerClasses = (ics == null) ? null : new ArrayList(ics); // Edit the attribute list, if necessary. Attribute a = getAttribute(attrInnerClassesEmpty); if (innerClasses != null && a == null) @@ -318,19 +319,18 @@ class Package implements Constants { * The order of the resulting list is consistent * with that of Package.this.allInnerClasses. */ - public List computeGloballyImpliedICs() { - HashSet cpRefs = new HashSet(); + public List computeGloballyImpliedICs() { + HashSet cpRefs = new HashSet<>(); { // This block temporarily displaces this.innerClasses. - ArrayList innerClassesSaved = innerClasses; + ArrayList innerClassesSaved = innerClasses; innerClasses = null; // ignore for the moment visitRefs(VRM_CLASSIC, cpRefs); innerClasses = innerClassesSaved; } ConstantPool.completeReferencesIn(cpRefs, true); - HashSet icRefs = new HashSet(); - for (Iterator i = cpRefs.iterator(); i.hasNext(); ) { - Entry e = (Entry) i.next(); + HashSet icRefs = new HashSet<>(); + for (Entry e : cpRefs) { // Restrict cpRefs to InnerClasses entries only. if (!(e instanceof ClassEntry)) continue; // For every IC reference, add its outers also. @@ -345,9 +345,8 @@ class Package implements Constants { // This loop is structured this way so as to accumulate // entries into impliedICs in an order which reflects // the order of allInnerClasses. - ArrayList impliedICs = new ArrayList(); - for (Iterator i = allInnerClasses.iterator(); i.hasNext(); ) { - InnerClass ic = (InnerClass) i.next(); + ArrayList impliedICs = new ArrayList<>(); + for (InnerClass ic : allInnerClasses) { // This one is locally relevant if it describes // a member of the current class, or if the current // class uses it somehow. In the particular case @@ -366,10 +365,11 @@ class Package implements Constants { // Helper for both minimizing and expanding. // Computes a symmetric difference. - private List computeICdiff() { - List impliedICs = computeGloballyImpliedICs(); - List actualICs = getInnerClasses(); - if (actualICs == null) actualICs = Collections.EMPTY_LIST; + private List computeICdiff() { + List impliedICs = computeGloballyImpliedICs(); + List actualICs = getInnerClasses(); + if (actualICs == null) + actualICs = Collections.EMPTY_LIST; // Symmetric difference is calculated from I, A like this: // diff = (I+A) - (I*A) @@ -388,8 +388,8 @@ class Package implements Constants { // Diff is A since I is empty. } // (I*A) is non-trivial - HashSet center = new HashSet(actualICs); - center.retainAll(new HashSet(impliedICs)); + HashSet center = new HashSet<>(actualICs); + center.retainAll(new HashSet<>(impliedICs)); impliedICs.addAll(actualICs); impliedICs.removeAll(center); // Diff is now I^A = (I+A)-(I*A). @@ -407,9 +407,9 @@ class Package implements Constants { * to use the globally implied ICs changed. */ void minimizeLocalICs() { - List diff = computeICdiff(); - List actualICs = innerClasses; - List localICs; // will be the diff, modulo edge cases + List diff = computeICdiff(); + List actualICs = innerClasses; + List localICs; // will be the diff, modulo edge cases if (diff.isEmpty()) { // No diff, so transmit no attribute. localICs = null; @@ -439,12 +439,12 @@ class Package implements Constants { * Otherwise, return positive if any IC tuples were added. */ int expandLocalICs() { - List localICs = innerClasses; - List actualICs; + List localICs = innerClasses; + List actualICs; int changed; if (localICs == null) { // Diff was empty. (Common case.) - List impliedICs = computeGloballyImpliedICs(); + List impliedICs = computeGloballyImpliedICs(); if (impliedICs.isEmpty()) { actualICs = null; changed = 0; @@ -490,7 +490,7 @@ class Package implements Constants { protected Entry[] getCPMap() { return cpMap; } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { if (verbose > 2) Utils.log.fine("visitRefs "+this); // Careful: The descriptor is used by the package, // but the classfile breaks it into component refs. @@ -518,7 +518,7 @@ class Package implements Constants { super(flags, descriptor); assert(!descriptor.isMethod()); if (fields == null) - fields = new ArrayList(); + fields = new ArrayList<>(); boolean added = fields.add(this); assert(added); order = fields.size(); @@ -543,7 +543,7 @@ class Package implements Constants { super(flags, descriptor); assert(descriptor.isMethod()); if (methods == null) - methods = new ArrayList(); + methods = new ArrayList<>(); boolean added = methods.add(this); assert(added); } @@ -573,7 +573,7 @@ class Package implements Constants { code.strip(attrName); super.strip(attrName); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { super.visitRefs(mode, refs); if (code != null) { if (mode == VRM_CLASSIC) { @@ -614,7 +614,7 @@ class Package implements Constants { super.strip(attrName); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { if (verbose > 2) Utils.log.fine("visitRefs "+this); refs.add(thisClass); refs.add(superClass); @@ -641,7 +641,7 @@ class Package implements Constants { super.visitRefs(mode, refs); } - protected void visitInnerClassRefs(int mode, Collection refs) { + protected void visitInnerClassRefs(int mode, Collection refs) { Package.visitInnerClassRefs(innerClasses, mode, refs); } @@ -713,16 +713,15 @@ class Package implements Constants { } // What non-class files are in this unit? - ArrayList files = new ArrayList(); + ArrayList files = new ArrayList<>(); - public List getFiles() { + public List getFiles() { return files; } - public List getClassStubs() { - ArrayList classStubs = new ArrayList(classes.size()); - for (Iterator i = classes.iterator(); i.hasNext(); ) { - Class cls = (Class) i.next(); + public List getClassStubs() { + ArrayList classStubs = new ArrayList<>(classes.size()); + for (Class cls : classes) { assert(cls.file.isClassStub()); classStubs.add(cls.file); } @@ -840,7 +839,7 @@ class Package implements Constants { public InputStream getInputStream() { InputStream in = new ByteArrayInputStream(append.toByteArray()); if (prepend.size() == 0) return in; - ArrayList isa = new ArrayList(prepend.size()+1); + ArrayList isa = new ArrayList<>(prepend.size()+1); for (Iterator i = prepend.iterator(); i.hasNext(); ) { byte[] bytes = (byte[]) i.next(); isa.add(new ByteArrayInputStream(bytes)); @@ -849,7 +848,7 @@ class Package implements Constants { return new SequenceInputStream(Collections.enumeration(isa)); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { assert(name != null); refs.add(name); } @@ -877,8 +876,8 @@ class Package implements Constants { } // Is there a globally declared table of inner classes? - ArrayList allInnerClasses = new ArrayList(); - HashMap allInnerClassesByThis; + ArrayList allInnerClasses = new ArrayList<>(); + HashMap allInnerClassesByThis; public List getAllInnerClasses() { @@ -886,15 +885,14 @@ class Package implements Constants { } public - void setAllInnerClasses(Collection ics) { + void setAllInnerClasses(Collection ics) { assert(ics != allInnerClasses); allInnerClasses.clear(); allInnerClasses.addAll(ics); // Make an index: - allInnerClassesByThis = new HashMap(allInnerClasses.size()); - for (Iterator i = allInnerClasses.iterator(); i.hasNext(); ) { - InnerClass ic = (InnerClass) i.next(); + allInnerClassesByThis = new HashMap<>(allInnerClasses.size()); + for (InnerClass ic : allInnerClasses) { Object pic = allInnerClassesByThis.put(ic.thisClass, ic); assert(pic == null); // caller must ensure key uniqueness! } @@ -904,7 +902,7 @@ class Package implements Constants { public InnerClass getGlobalInnerClass(Entry thisClass) { assert(thisClass instanceof ClassEntry); - return (InnerClass) allInnerClassesByThis.get(thisClass); + return allInnerClassesByThis.get(thisClass); } static @@ -963,7 +961,7 @@ class Package implements Constants { return this.thisClass.compareTo(that.thisClass); } - protected void visitRefs(int mode, Collection refs) { + protected void visitRefs(int mode, Collection refs) { refs.add(thisClass); if (mode == VRM_CLASSIC || !predictable) { // If the name can be demangled, the package omits @@ -980,7 +978,7 @@ class Package implements Constants { // Helper for building InnerClasses attributes. static private - void visitInnerClassRefs(Collection innerClasses, int mode, Collection refs) { + void visitInnerClassRefs(Collection innerClasses, int mode, Collection refs) { if (innerClasses == null) { return; // no attribute; nothing to do } @@ -1165,9 +1163,8 @@ class Package implements Constants { } } - protected void visitRefs(int mode, Collection refs) { - for (Iterator i = classes.iterator(); i.hasNext(); ) { - Class c = (Class)i.next(); + protected void visitRefs(int mode, Collection refs) { + for ( Class c : classes) { c.visitRefs(mode, refs); } if (mode != VRM_CLASSIC) { @@ -1259,7 +1256,7 @@ class Package implements Constants { } // Use this before writing the package file. - void buildGlobalConstantPool(Set requiredEntries) { + void buildGlobalConstantPool(Set requiredEntries) { if (verbose > 1) Utils.log.fine("Checking for unused CP entries"); requiredEntries.add(getRefString("")); // uconditionally present @@ -1291,9 +1288,8 @@ class Package implements Constants { // Use this before writing the class files. void ensureAllClassFiles() { - HashSet fileSet = new HashSet(files); - for (Iterator i = classes.iterator(); i.hasNext(); ) { - Class cls = (Class) i.next(); + HashSet fileSet = new HashSet<>(files); + for (Class cls : classes) { // Add to the end of ths list: if (!fileSet.contains(cls.file)) files.add(cls.file); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java index 9c285794303..449bbbeb5b1 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,11 @@ package com.sun.java.util.jar.pack; +import com.sun.java.util.jar.pack.Attribute.Layout; import java.util.*; import java.util.jar.*; -import java.util.zip.*; import java.io.*; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeEvent; /* @@ -41,31 +40,22 @@ import java.beans.PropertyChangeEvent; */ -public class PackerImpl implements Pack200.Packer { +public class PackerImpl extends TLGlobals implements Pack200.Packer { /** * Constructs a Packer object and sets the initial state of * the packer engines. */ - public PackerImpl() { - _props = new PropMap(); - //_props.getProperty() consults defaultProps invisibly. - //_props.putAll(defaultProps); - } - - - // Private stuff. - final PropMap _props; + public PackerImpl() {} /** * Get the set of options for the pack and unpack engines. * @return A sorted association of option key strings to option values. */ - public SortedMap properties() { - return _props; + public SortedMap properties() { + return props; } - //Driver routines /** @@ -78,21 +68,22 @@ public class PackerImpl implements Pack200.Packer { */ public void pack(JarFile in, OutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : - TimeZone.getDefault(); + TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) + ? null + : TimeZone.getDefault(); try { Utils.currentInstance.set(this); if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { + if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) { Utils.copyJarFile(in, out); } else { (new DoPack()).run(in, out); - in.close(); } } finally { Utils.currentInstance.set(null); if (tz != null) TimeZone.setDefault(tz); + in.close(); } } @@ -112,21 +103,20 @@ public class PackerImpl implements Pack200.Packer { */ public void pack(JarInputStream in, OutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : + TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : TimeZone.getDefault(); try { Utils.currentInstance.set(this); if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - if ("0".equals(_props.getProperty(Pack200.Packer.EFFORT))) { + if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) { Utils.copyJarFile(in, out); } else { (new DoPack()).run(in, out); - in.close(); } } finally { Utils.currentInstance.set(null); if (tz != null) TimeZone.setDefault(tz); - + in.close(); } } /** @@ -134,7 +124,7 @@ public class PackerImpl implements Pack200.Packer { * @param listener An object to be invoked when a property is changed. */ public void addPropertyChangeListener(PropertyChangeListener listener) { - _props.addListener(listener); + props.addListener(listener); } /** @@ -142,7 +132,7 @@ public class PackerImpl implements Pack200.Packer { * @param listener The PropertyChange listener to be removed. */ public void removePropertyChangeListener(PropertyChangeListener listener) { - _props.removeListener(listener); + props.removeListener(listener); } @@ -151,11 +141,11 @@ public class PackerImpl implements Pack200.Packer { // The packer worker. private class DoPack { - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); { - _props.setInteger(Pack200.Packer.PROGRESS, 0); - if (verbose > 0) Utils.log.info(_props.toString()); + props.setInteger(Pack200.Packer.PROGRESS, 0); + if (verbose > 0) Utils.log.info(props.toString()); } // Here's where the bits are collected before getting packed: @@ -163,7 +153,7 @@ public class PackerImpl implements Pack200.Packer { final String unknownAttrCommand; { - String uaMode = _props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); + String uaMode = props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); if (!(Pack200.Packer.STRIP.equals(uaMode) || Pack200.Packer.PASS.equals(uaMode) || Pack200.Packer.ERROR.equals(uaMode))) { @@ -191,13 +181,12 @@ public class PackerImpl implements Pack200.Packer { }; for (int i = 0; i < ctypes.length; i++) { String pfx = keys[i]; - Map map = _props.prefixMap(pfx); - for (Iterator j = map.keySet().iterator(); j.hasNext(); ) { - String key = (String) j.next(); + Map map = props.prefixMap(pfx); + for (String key : map.keySet()) { assert(key.startsWith(pfx)); String name = key.substring(pfx.length()); - String layout = _props.getProperty(key); - Object lkey = Attribute.keyForLookup(ctypes[i], name); + String layout = props.getProperty(key); + Layout lkey = Attribute.keyForLookup(ctypes[i], name); if (Pack200.Packer.STRIP.equals(layout) || Pack200.Packer.PASS.equals(layout) || Pack200.Packer.ERROR.equals(layout)) { @@ -222,25 +211,25 @@ public class PackerImpl implements Pack200.Packer { } final boolean keepFileOrder - = _props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER); + = props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER); final boolean keepClassOrder - = _props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER); + = props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER); final boolean keepModtime - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); + = Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME)); final boolean latestModtime - = Pack200.Packer.LATEST.equals(_props.getProperty(Pack200.Packer.MODIFICATION_TIME)); + = Pack200.Packer.LATEST.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME)); final boolean keepDeflateHint - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Packer.DEFLATE_HINT)); + = Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.DEFLATE_HINT)); { if (!keepModtime && !latestModtime) { - int modtime = _props.getTime(Pack200.Packer.MODIFICATION_TIME); + int modtime = props.getTime(Pack200.Packer.MODIFICATION_TIME); if (modtime != Constants.NO_MODTIME) { pkg.default_modtime = modtime; } } if (!keepDeflateHint) { - boolean deflate_hint = _props.getBoolean(Pack200.Packer.DEFLATE_HINT); + boolean deflate_hint = props.getBoolean(Pack200.Packer.DEFLATE_HINT); if (deflate_hint) { pkg.default_options |= Constants.AO_DEFLATE_HINT; } @@ -254,10 +243,10 @@ public class PackerImpl implements Pack200.Packer { final long segmentLimit; { long limit; - if (_props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals("")) + if (props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").equals("")) limit = -1; else - limit = _props.getLong(Pack200.Packer.SEGMENT_LIMIT); + limit = props.getLong(Pack200.Packer.SEGMENT_LIMIT); limit = Math.min(Integer.MAX_VALUE, limit); limit = Math.max(-1, limit); if (limit == -1) @@ -265,10 +254,10 @@ public class PackerImpl implements Pack200.Packer { segmentLimit = limit; } - final List passFiles; // parsed pack.pass.file options + final List passFiles; // parsed pack.pass.file options { // Which class files will be passed through? - passFiles = _props.getProperties(Pack200.Packer.PASS_FILE_PFX); + passFiles = props.getProperties(Pack200.Packer.PASS_FILE_PFX); for (ListIterator i = passFiles.listIterator(); i.hasNext(); ) { String file = (String) i.next(); if (file == null) { i.remove(); continue; } @@ -283,28 +272,28 @@ public class PackerImpl implements Pack200.Packer { { // Fill in permitted range of major/minor version numbers. int ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"min.class.majver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.majver")) != 0) pkg.min_class_majver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"min.class.minver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"min.class.minver")) != 0) pkg.min_class_minver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"max.class.majver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.majver")) != 0) pkg.max_class_majver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"max.class.minver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"max.class.minver")) != 0) pkg.max_class_minver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"package.minver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"package.minver")) != 0) pkg.package_minver = (short) ver; - if ((ver = _props.getInteger(Utils.COM_PREFIX+"package.majver")) != 0) + if ((ver = props.getInteger(Utils.COM_PREFIX+"package.majver")) != 0) pkg.package_majver = (short) ver; } { // Hook for testing: Forces use of special archive modes. - int opt = _props.getInteger(Utils.COM_PREFIX+"archive.options"); + int opt = props.getInteger(Utils.COM_PREFIX+"archive.options"); if (opt != 0) pkg.default_options |= opt; } - // (Done collecting options from _props.) + // (Done collecting options from props.) boolean isClassFile(String name) { if (!name.endsWith(".class")) return false; @@ -423,16 +412,18 @@ public class PackerImpl implements Pack200.Packer { Package.File file = null; // (5078608) : discount the resource files in META-INF // from segment computation. - long inflen = (isMetaInfFile(name)) ? 0L : - inFile.getInputLength(); + long inflen = (isMetaInfFile(name)) + ? 0L + : inFile.getInputLength(); if ((segmentSize += inflen) > segmentLimit) { segmentSize -= inflen; int nextCount = -1; // don't know; it's a stream flushPartial(out, nextCount); } - if (verbose > 1) + if (verbose > 1) { Utils.log.fine("Reading " + name); + } assert(je.isDirectory() == name.endsWith("/")); @@ -450,18 +441,18 @@ public class PackerImpl implements Pack200.Packer { } void run(JarFile in, OutputStream out) throws IOException { - List inFiles = scanJar(in); + List inFiles = scanJar(in); if (verbose > 0) Utils.log.info("Reading " + inFiles.size() + " files..."); int numDone = 0; - for (Iterator i = inFiles.iterator(); i.hasNext(); ) { - InFile inFile = (InFile) i.next(); + for (InFile inFile : inFiles) { String name = inFile.name; // (5078608) : discount the resource files completely from segmenting - long inflen = (isMetaInfFile(name)) ? 0L : - inFile.getInputLength() ; + long inflen = (isMetaInfFile(name)) + ? 0L + : inFile.getInputLength() ; if ((segmentSize += inflen) > segmentLimit) { segmentSize -= inflen; // Estimate number of remaining segments: @@ -530,11 +521,11 @@ public class PackerImpl implements Pack200.Packer { } void flushPartial(OutputStream out, int nextCount) throws IOException { - if (pkg.files.size() == 0 && pkg.classes.size() == 0) { + if (pkg.files.isEmpty() && pkg.classes.isEmpty()) { return; // do not flush an empty segment } flushPackage(out, Math.max(1, nextCount)); - _props.setInteger(Pack200.Packer.PROGRESS, 25); + props.setInteger(Pack200.Packer.PROGRESS, 25); // In case there will be another segment: makeNextPackage(); segmentCount += 1; @@ -543,10 +534,10 @@ public class PackerImpl implements Pack200.Packer { } void flushAll(OutputStream out) throws IOException { - _props.setInteger(Pack200.Packer.PROGRESS, 50); + props.setInteger(Pack200.Packer.PROGRESS, 50); flushPackage(out, 0); out.flush(); - _props.setInteger(Pack200.Packer.PROGRESS, 100); + props.setInteger(Pack200.Packer.PROGRESS, 100); segmentCount += 1; segmentTotalSize += segmentSize; segmentSize = 0; @@ -582,11 +573,11 @@ public class PackerImpl implements Pack200.Packer { pkg.trimStubs(); // Do some stripping, maybe. - if (_props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions"); - if (_props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions"); + if (props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses"); // Must choose an archive version; PackageWriter does not. if (pkg.package_majver <= 0) pkg.choosePackageVersion(); @@ -606,11 +597,10 @@ public class PackerImpl implements Pack200.Packer { } } - List scanJar(JarFile jf) throws IOException { + List scanJar(JarFile jf) throws IOException { // Collect jar entries, preserving order. - List inFiles = new ArrayList(); - for (Enumeration e = jf.entries(); e.hasMoreElements(); ) { - JarEntry je = (JarEntry) e.nextElement(); + List inFiles = new ArrayList<>(); + for (JarEntry je : Collections.list(jf.entries())) { InFile inFile = new InFile(jf, je); assert(je.isDirectory() == inFile.name.endsWith("/")); inFiles.add(inFile); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java index 6b92236f82e..78c709f343d 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/PropMap.java @@ -91,7 +91,7 @@ class PropMap extends TreeMap { String.valueOf(Boolean.getBoolean(Utils.PACK_DEFAULT_TIMEZONE))); // The segment size is unlimited - props.put(Pack200.Packer.SEGMENT_LIMIT, ""); + props.put(Pack200.Packer.SEGMENT_LIMIT, "-1"); // Preserve file ordering by default. props.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.TRUE); diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java new file mode 100644 index 00000000000..0e40bde8b63 --- /dev/null +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.java.util.jar.pack; + +import com.sun.java.util.jar.pack.ConstantPool.ClassEntry; +import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry; +import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry; +import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; +import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; +import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedMap; + +/* + * @author ksrini + */ + +/* + * This class provides a container to hold the global variables, for packer + * and unpacker instances. This is typically stashed away in a ThreadLocal, + * and the storage is destroyed upon completion. Therefore any local + * references to these members must be eliminated appropriately to prevent a + * memory leak. + */ +class TLGlobals { + // Global environment + final PropMap props; + + // Needed by ConstantPool.java + private final Map utf8Entries; + private final Map classEntries; + private final Map literalEntries; + private final Map signatureEntries; + private final Map descriptorEntries; + private final Map memberEntries; + + TLGlobals() { + utf8Entries = new HashMap<>(); + classEntries = new HashMap<>(); + literalEntries = new HashMap<>(); + signatureEntries = new HashMap<>(); + descriptorEntries = new HashMap<>(); + memberEntries = new HashMap<>(); + props = new PropMap(); + } + + SortedMap getPropMap() { + return props; + } + + Map getUtf8Entries() { + return utf8Entries; + } + + Map getClassEntries() { + return classEntries; + } + + Map getLiteralEntries() { + return literalEntries; + } + + Map getDescriptorEntries() { + return descriptorEntries; + } + + Map getSignatureEntries() { + return signatureEntries; + } + + Map getMemberEntries() { + return memberEntries; + } +} diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java index d131a1255f4..11c8abf07f1 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.util.jar.*; import java.util.zip.*; import java.io.*; import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeEvent; /* * Implementation of the Pack provider. @@ -40,7 +39,7 @@ import java.beans.PropertyChangeEvent; */ -public class UnpackerImpl implements Pack200.Unpacker { +public class UnpackerImpl extends TLGlobals implements Pack200.Unpacker { /** @@ -48,7 +47,7 @@ public class UnpackerImpl implements Pack200.Unpacker { * @param listener An object to be invoked when a property is changed. */ public void addPropertyChangeListener(PropertyChangeListener listener) { - _props.addListener(listener); + props.addListener(listener); } @@ -57,25 +56,19 @@ public class UnpackerImpl implements Pack200.Unpacker { * @param listener The PropertyChange listener to be removed. */ public void removePropertyChangeListener(PropertyChangeListener listener) { - _props.removeListener(listener); + props.removeListener(listener); } - public UnpackerImpl() { - _props = new PropMap(); - //_props.getProperty() consults defaultProps invisibly. - //_props.putAll(defaultProps); - } + public UnpackerImpl() {} - // Private stuff. - final PropMap _props; /** * Get the set of options for the pack and unpack engines. * @return A sorted association of option key strings to option values. */ - public SortedMap properties() { - return _props; + public SortedMap properties() { + return props; } // Back-pointer to NativeUnpacker, when active. @@ -101,19 +94,20 @@ public class UnpackerImpl implements Pack200.Unpacker { */ public void unpack(InputStream in0, JarOutputStream out) throws IOException { assert(Utils.currentInstance.get() == null); - TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : - TimeZone.getDefault(); + TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) + ? null + : TimeZone.getDefault(); try { Utils.currentInstance.set(this); if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); BufferedInputStream in = new BufferedInputStream(in0); if (Utils.isJarMagic(Utils.readMagic(in))) { if (verbose > 0) Utils.log.info("Copying unpacked JAR file..."); Utils.copyJarFile(new JarInputStream(in), out); - } else if (_props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { + } else if (props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { (new DoUnpack()).run(in, out); in.close(); Utils.markJarFile(out); @@ -142,36 +136,38 @@ public class UnpackerImpl implements Pack200.Unpacker { // %%% Reconsider if native unpacker learns to memory-map the file. FileInputStream instr = new FileInputStream(in); unpack(instr, out); - if (_props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { + if (props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { in.delete(); } } private class DoUnpack { - final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); + final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); { - _props.setInteger(Pack200.Unpacker.PROGRESS, 0); + props.setInteger(Pack200.Unpacker.PROGRESS, 0); } // Here's where the bits are read from disk: final Package pkg = new Package(); final boolean keepModtime - = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); + = Pack200.Packer.KEEP.equals( + props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); final boolean keepDeflateHint - = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); + = Pack200.Packer.KEEP.equals( + props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); final int modtime; final boolean deflateHint; { if (!keepModtime) { - modtime = _props.getTime(Utils.UNPACK_MODIFICATION_TIME); + modtime = props.getTime(Utils.UNPACK_MODIFICATION_TIME); } else { modtime = pkg.default_modtime; } deflateHint = (keepDeflateHint) ? false : - _props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); + props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); } // Checksum apparatus. @@ -181,7 +177,7 @@ public class UnpackerImpl implements Pack200.Unpacker { public void run(BufferedInputStream in, JarOutputStream out) throws IOException { if (verbose > 0) { - _props.list(System.out); + props.list(System.out); } for (int seg = 1; ; seg++) { unpackSegment(in, out); @@ -194,25 +190,26 @@ public class UnpackerImpl implements Pack200.Unpacker { } private void unpackSegment(InputStream in, JarOutputStream out) throws IOException { - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); + props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); // Process the output directory or jar output. new PackageReader(pkg, in).read(); - if (_props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); - if (_props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); + if (props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); + if (props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); + props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); pkg.ensureAllClassFiles(); // Now write out the files. - HashSet classesToWrite = new HashSet(pkg.getClasses()); + HashSet classesToWrite = new HashSet<>(pkg.getClasses()); for (Iterator i = pkg.getFiles().iterator(); i.hasNext(); ) { Package.File file = (Package.File) i.next(); String name = file.nameString; JarEntry je = new JarEntry(Utils.getJarEntryName(name)); boolean deflate; - deflate = (keepDeflateHint) ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || - ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) : - deflateHint; + deflate = (keepDeflateHint) + ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || + ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) + : deflateHint; boolean needCRC = !deflate; // STORE mode requires CRC @@ -250,7 +247,7 @@ public class UnpackerImpl implements Pack200.Unpacker { Utils.log.info("Writing "+Utils.zeString((ZipEntry)je)); } assert(classesToWrite.isEmpty()); - _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100"); + props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100"); pkg.reset(); // reset for the next segment, if any } } diff --git a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java index 8edbed10c46..2dc47c41464 100644 --- a/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java +++ b/jdk/src/share/classes/com/sun/java/util/jar/pack/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,13 @@ package com.sun.java.util.jar.pack; +import com.sun.java.util.jar.pack.Attribute.Layout; +import com.sun.java.util.jar.pack.ConstantPool.ClassEntry; +import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry; +import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry; +import com.sun.java.util.jar.pack.ConstantPool.MemberEntry; +import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry; +import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry; import java.util.*; import java.util.jar.*; import java.util.zip.*; @@ -113,17 +120,46 @@ class Utils { */ static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200"; - // Keep a TLS point to the current Packer or Unpacker. - // This makes it simpler to supply environmental options + // Keep a TLS point to the global data and environment. + // This makes it simpler to supply environmental options // to the engine code, especially the native code. - static final ThreadLocal currentInstance = new ThreadLocal(); + static final ThreadLocal currentInstance = new ThreadLocal<>(); + + // convenience methods to access the TL globals + static TLGlobals getTLGlobals() { + return currentInstance.get(); + } + + static Map getUtf8Entries() { + return getTLGlobals().getUtf8Entries(); + } + + static Map getClassEntries() { + return getTLGlobals().getClassEntries(); + } + + static Map getLiteralEntries() { + return getTLGlobals().getLiteralEntries(); + } + + static Map getDescriptorEntries() { + return getTLGlobals().getDescriptorEntries(); + } + + static Map getSignatureEntries() { + return getTLGlobals().getSignatureEntries(); + } + + static Map getMemberEntries() { + return getTLGlobals().getMemberEntries(); + } static PropMap currentPropMap() { Object obj = currentInstance.get(); if (obj instanceof PackerImpl) - return ((PackerImpl)obj)._props; + return ((PackerImpl)obj).props; if (obj instanceof UnpackerImpl) - return ((UnpackerImpl)obj)._props; + return ((UnpackerImpl)obj).props; return null; } diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java index 4503d261fff..dec38eb752d 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/Connection.java @@ -813,7 +813,8 @@ public final class Connection implements Runnable { try { while (true) { try { - inbuf = new byte[10]; + // type and length (at most 128 octets for long form) + inbuf = new byte[129]; offset = 0; seqlen = 0; diff --git a/jdk/src/share/classes/com/sun/tools/example/debug/tty/TTYResources.java b/jdk/src/share/classes/com/sun/tools/example/debug/tty/TTYResources.java index 6998ed90b39..2c5e12d5eb8 100644 --- a/jdk/src/share/classes/com/sun/tools/example/debug/tty/TTYResources.java +++ b/jdk/src/share/classes/com/sun/tools/example/debug/tty/TTYResources.java @@ -45,7 +45,7 @@ public class TTYResources extends java.util.ListResourceBundle { * @return the contents of this ResourceBundle. */ public Object[][] getContents() { - return new Object[][] { + Object[][] temp = new Object[][] { // NOTE: The value strings in this file containing "{0}" are // processed by the java.text.MessageFormat class. Any // single quotes appearing in these strings need to be @@ -449,5 +449,7 @@ public class TTYResources extends java.util.ListResourceBundle { "For command help type ''help'' at {0} prompt"}, // END OF MATERIAL TO LOCALIZE }; + + return temp; } } diff --git a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java index fad8ad6da66..46a14a0aa20 100644 --- a/jdk/src/share/classes/java/lang/AbstractStringBuilder.java +++ b/jdk/src/share/classes/java/lang/AbstractStringBuilder.java @@ -470,7 +470,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { public AbstractStringBuilder append(CharSequence s, int start, int end) { if (s == null) s = "null"; - if ((start < 0) || (end < 0) || (start > end) || (end > s.length())) + if ((start < 0) || (start > end) || (end > s.length())) throw new IndexOutOfBoundsException( "start " + start + ", end " + end + ", s.length() " + s.length()); @@ -529,7 +529,8 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * or {@code offset+len > str.length} */ public AbstractStringBuilder append(char str[], int offset, int len) { - ensureCapacityInternal(count + len); + if (len > 0) // let arraycopy report AIOOBE for len < 0 + ensureCapacityInternal(count + len); System.arraycopy(str, offset, value, count, len); count += len; return this; diff --git a/jdk/src/share/classes/java/lang/Thread.java b/jdk/src/share/classes/java/lang/Thread.java index c379ec59135..c3592cf5cf3 100644 --- a/jdk/src/share/classes/java/lang/Thread.java +++ b/jdk/src/share/classes/java/lang/Thread.java @@ -413,6 +413,18 @@ class Thread implements Runnable { tid = nextThreadID(); } + /** + * Throws CloneNotSupportedException as a Thread can not be meaningfully + * cloned. Construct a new Thread instead. + * + * @throws CloneNotSupportedException + * always + */ + @Override + protected Object clone() throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + /** * Allocates a new {@code Thread} object. This constructor has the same * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} diff --git a/jdk/src/share/classes/java/lang/Throwable.java b/jdk/src/share/classes/java/lang/Throwable.java index 213f5f86d5c..4d4169139e8 100644 --- a/jdk/src/share/classes/java/lang/Throwable.java +++ b/jdk/src/share/classes/java/lang/Throwable.java @@ -200,7 +200,16 @@ public class Throwable implements Serializable { * @serial * @since 1.7 */ - private List suppressedExceptions = Collections.emptyList(); + private List suppressedExceptions = null; + /* + * This field is lazily initialized when the first suppressed + * exception is added. + * + * OutOfMemoryError is preallocated in the VM for better OOM + * diagnosability during VM initialization. Constructor can't + * be not invoked. If a new field to be added in the future must + * be initialized to non-null, it requires a synchronized VM change. + */ /** Message for trying to suppress a null exception. */ private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception."; @@ -329,7 +338,7 @@ public class Throwable implements Serializable { * cause is nonexistent or unknown. * @since 1.4 */ - public Throwable getCause() { + public synchronized Throwable getCause() { return (cause==this ? null : cause); } @@ -563,7 +572,7 @@ public class Throwable implements Serializable { s.println("\tat " + traceElement); // Print suppressed exceptions, if any - for (Throwable se : suppressedExceptions) + for (Throwable se : getSuppressedExceptions()) se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu); // Print cause, if any @@ -604,7 +613,7 @@ public class Throwable implements Serializable { s.println(prefix + "\t... " + framesInCommon + " more"); // Print suppressed exceptions, if any - for (Throwable se : suppressedExceptions) + for (Throwable se : getSuppressedExceptions()) se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, prefix +"\t", dejaVu); @@ -747,7 +756,9 @@ public class Throwable implements Serializable { if (defensiveCopy[i] == null) throw new NullPointerException("stackTrace[" + i + "]"); - this.stackTrace = defensiveCopy; + synchronized (this) { + this.stackTrace = defensiveCopy; + } } /** @@ -772,11 +783,11 @@ public class Throwable implements Serializable { private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); // read in all fields - List suppressed = Collections.emptyList(); + List suppressed = null; if (suppressedExceptions != null && !suppressedExceptions.isEmpty()) { // Copy Throwables to new list suppressed = new ArrayList(); - for(Throwable t : suppressedExceptions) { + for (Throwable t : suppressedExceptions) { if (t == null) throw new NullPointerException(NULL_CAUSE_MESSAGE); suppressed.add(t); @@ -819,7 +830,7 @@ public class Throwable implements Serializable { if (exception == this) throw new IllegalArgumentException("Self-suppression not permitted"); - if (suppressedExceptions.size() == 0) + if (suppressedExceptions == null) suppressedExceptions = new ArrayList(); suppressedExceptions.add(exception); } @@ -835,7 +846,10 @@ public class Throwable implements Serializable { * suppressed to deliver this exception. * @since 1.7 */ - public Throwable[] getSuppressedExceptions() { - return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); + public synchronized Throwable[] getSuppressedExceptions() { + if (suppressedExceptions == null) + return EMPTY_THROWABLE_ARRAY; + else + return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY); } } diff --git a/jdk/src/share/classes/java/net/HttpCookie.java b/jdk/src/share/classes/java/net/HttpCookie.java index 5b00869ab95..07d9cee3e8a 100644 --- a/jdk/src/share/classes/java/net/HttpCookie.java +++ b/jdk/src/share/classes/java/net/HttpCookie.java @@ -1093,14 +1093,8 @@ public final class HttpCookie implements Cloneable { return sb.toString(); } - private static SimpleDateFormat[] cDateFormats = null; - static { - cDateFormats = new SimpleDateFormat[COOKIE_DATE_FORMATS.length]; - for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) { - cDateFormats[i] = new SimpleDateFormat(COOKIE_DATE_FORMATS[i], Locale.US); - cDateFormats[i].setTimeZone(TimeZone.getTimeZone("GMT")); - } - } + static final TimeZone GMT = TimeZone.getTimeZone("GMT"); + /* * @param dateString a date string in one of the formats * defined in Netscape cookie spec @@ -1109,12 +1103,14 @@ public final class HttpCookie implements Cloneable { * time and the time specified by dateString */ private long expiryDate2DeltaSeconds(String dateString) { - for (SimpleDateFormat df : cDateFormats) { + for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) { + SimpleDateFormat df = new SimpleDateFormat(COOKIE_DATE_FORMATS[i], Locale.US); + df.setTimeZone(GMT); try { Date date = df.parse(dateString); return (date.getTime() - whenCreated) / 1000; } catch (Exception e) { - + // Ignore, try the next date format } } return 0; diff --git a/jdk/src/share/classes/java/net/URI.java b/jdk/src/share/classes/java/net/URI.java index c05b7b2abaa..9b891b4b4dd 100644 --- a/jdk/src/share/classes/java/net/URI.java +++ b/jdk/src/share/classes/java/net/URI.java @@ -856,9 +856,7 @@ public final class URI try { return new URI(str); } catch (URISyntaxException x) { - IllegalArgumentException y = new IllegalArgumentException(); - y.initCause(x); - throw y; + throw new IllegalArgumentException(x.getMessage(), x); } } diff --git a/jdk/src/share/classes/java/security/KeyStore.java b/jdk/src/share/classes/java/security/KeyStore.java index 7ecac8025c1..c1e2e4649e7 100644 --- a/jdk/src/share/classes/java/security/KeyStore.java +++ b/jdk/src/share/classes/java/security/KeyStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,17 +131,19 @@ import javax.security.auth.callback.*; * to read existing entries from the keystore, or to write new entries * into the keystore: *
+ *    KeyStore.ProtectionParameter protParam =
+ *        new KeyStore.PasswordProtection(password);
+ *
  *    // get my private key
  *    KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
- *        ks.getEntry("privateKeyAlias", password);
+ *        ks.getEntry("privateKeyAlias", protParam);
  *    PrivateKey myPrivateKey = pkEntry.getPrivateKey();
  *
  *    // save my secret key
  *    javax.crypto.SecretKey mySecretKey;
  *    KeyStore.SecretKeyEntry skEntry =
  *        new KeyStore.SecretKeyEntry(mySecretKey);
- *    ks.setEntry("secretKeyAlias", skEntry,
- *        new KeyStore.PasswordProtection(password));
+ *    ks.setEntry("secretKeyAlias", skEntry, protParam);
  *
  *    // store away the keystore
  *    java.io.FileOutputStream fos = null;
diff --git a/jdk/src/share/classes/java/sql/Date.java b/jdk/src/share/classes/java/sql/Date.java
index 39cf98ce93f..7c2356e75c2 100644
--- a/jdk/src/share/classes/java/sql/Date.java
+++ b/jdk/src/share/classes/java/sql/Date.java
@@ -103,27 +103,46 @@ public class Date extends java.util.Date {
      *         JDBC date escape format (yyyy-mm-dd)
      */
     public static Date valueOf(String s) {
-        int year;
-        int month;
-        int day;
+        final int YEAR_LENGTH = 4;
+        final int MONTH_LENGTH = 2;
+        final int DAY_LENGTH = 2;
+        final int MAX_MONTH = 12;
+        final int MAX_DAY = 31;
         int firstDash;
         int secondDash;
+        Date d = null;
 
-        if (s == null) throw new java.lang.IllegalArgumentException();
-
-        firstDash = s.indexOf('-');
-        secondDash = s.indexOf('-', firstDash+1);
-        if ((firstDash > 0) & (secondDash > 0) & (secondDash < s.length()-1)) {
-            year = Integer.parseInt(s.substring(0, firstDash)) - 1900;
-            month = Integer.parseInt(s.substring(firstDash+1, secondDash)) - 1;
-            day = Integer.parseInt(s.substring(secondDash+1));
-        } else {
+        if (s == null) {
             throw new java.lang.IllegalArgumentException();
         }
 
-        return new Date(year, month, day);
+        firstDash = s.indexOf('-');
+        secondDash = s.indexOf('-', firstDash + 1);
+
+        if ((firstDash > 0) && (secondDash > 0) && (secondDash < s.length() - 1)) {
+            String yyyy = s.substring(0, firstDash);
+            String mm = s.substring(firstDash + 1, secondDash);
+            String dd = s.substring(secondDash + 1);
+            if (yyyy.length() == YEAR_LENGTH && mm.length() == MONTH_LENGTH &&
+                    dd.length() == DAY_LENGTH) {
+                int year = Integer.parseInt(yyyy);
+                int month = Integer.parseInt(mm);
+                int day = Integer.parseInt(dd);
+
+                if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
+                    d = new Date(year - 1900, month - 1, day);
+                }
+            }
+        }
+        if (d == null) {
+            throw new java.lang.IllegalArgumentException();
+        }
+
+        return d;
+
     }
 
+
     /**
      * Formats a date in the date escape format yyyy-mm-dd.
      * 

diff --git a/jdk/src/share/classes/javax/swing/JTable.java b/jdk/src/share/classes/javax/swing/JTable.java index 8ca98bbe15a..bcf00a37547 100644 --- a/jdk/src/share/classes/javax/swing/JTable.java +++ b/jdk/src/share/classes/javax/swing/JTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -946,7 +946,6 @@ public class JTable extends JComponent implements TableModelListener, Scrollable /** * Returns the height of a table row, in pixels. - * The default row height is 16.0. * * @return the height in pixels of a table row * @see #setRowHeight diff --git a/jdk/src/share/classes/sun/applet/resources/MsgAppletViewer.java b/jdk/src/share/classes/sun/applet/resources/MsgAppletViewer.java index fcf66e64c18..6c24c7f2946 100644 --- a/jdk/src/share/classes/sun/applet/resources/MsgAppletViewer.java +++ b/jdk/src/share/classes/sun/applet/resources/MsgAppletViewer.java @@ -29,7 +29,7 @@ import java.util.ListResourceBundle; public class MsgAppletViewer extends ListResourceBundle { public Object[][] getContents() { - return new Object[][] { + Object[][] temp = new Object[][] { {"textframe.button.dismiss", "Dismiss"}, {"appletviewer.tool.title", "Applet Viewer: {0}"}, {"appletviewer.menu.applet", "Applet"}, @@ -197,5 +197,7 @@ public class MsgAppletViewer extends ListResourceBundle { {"appletsecurityexception.checkread.unknown", "unknown class loader type. unable to check for checking read {0}"}, {"appletsecurityexception.checkconnect.unknown", "unknown class loader type. unable to check for checking connect"}, }; + + return temp; } } diff --git a/jdk/src/share/classes/sun/java2d/pisces/Dasher.java b/jdk/src/share/classes/sun/java2d/pisces/Dasher.java index 1a1f328adc4..f5b5e049143 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/Dasher.java +++ b/jdk/src/share/classes/sun/java2d/pisces/Dasher.java @@ -36,117 +36,71 @@ package sun.java2d.pisces; * semantics are unclear. * */ -public class Dasher extends LineSink { +public class Dasher implements LineSink { + private final LineSink output; + private final float[] dash; + private final float startPhase; + private final boolean startDashOn; + private final int startIdx; - LineSink output; - int[] dash; - int startPhase; - boolean startDashOn; - int startIdx; + private final float m00, m10, m01, m11; + private final float det; - int idx; - boolean dashOn; - int phase; + private boolean firstDashOn; + private boolean starting; - int sx, sy; - int x0, y0; + private int idx; + private boolean dashOn; + private float phase; - int m00, m01; - int m10, m11; + private float sx, sy; + private float x0, y0; + private float sx1, sy1; - Transform4 transform; - - boolean symmetric; - long ldet; - - boolean firstDashOn; - boolean starting; - int sx1, sy1; - - /** - * Empty constructor. setOutput and - * setParameters must be called prior to calling any - * other methods. - */ - public Dasher() {} /** * Constructs a Dasher. * * @param output an output LineSink. - * @param dash an array of ints containing the dash - * pattern in S15.16 format. - * @param phase an int containing the dash phase in - * S15.16 format. + * @param dash an array of ints containing the dash pattern + * @param phase an int containing the dash phase * @param transform a Transform4 object indicating * the transform that has been previously applied to all incoming * coordinates. This is required in order to compute dash lengths * properly. */ public Dasher(LineSink output, - int[] dash, int phase, - Transform4 transform) { - setOutput(output); - setParameters(dash, phase, transform); - } - - /** - * Sets the output LineSink of this - * Dasher. - * - * @param output an output LineSink. - */ - public void setOutput(LineSink output) { - this.output = output; - } - - /** - * Sets the parameters of this Dasher. - * - * @param dash an array of ints containing the dash - * pattern in S15.16 format. - * @param phase an int containing the dash phase in - * S15.16 format. - * @param transform a Transform4 object indicating - * the transform that has been previously applied to all incoming - * coordinates. This is required in order to compute dash lengths - * properly. - */ - public void setParameters(int[] dash, int phase, - Transform4 transform) { + float[] dash, float phase, + float a00, float a01, float a10, float a11) { if (phase < 0) { throw new IllegalArgumentException("phase < 0 !"); } + this.output = output; + // Normalize so 0 <= phase < dash[0] int idx = 0; dashOn = true; - int d; + float d; while (phase >= (d = dash[idx])) { phase -= d; idx = (idx + 1) % dash.length; dashOn = !dashOn; } - this.dash = new int[dash.length]; - for (int i = 0; i < dash.length; i++) { - this.dash[i] = dash[i]; - } + this.dash = dash; this.startPhase = this.phase = phase; this.startDashOn = dashOn; this.startIdx = idx; - this.transform = transform; - - this.m00 = transform.m00; - this.m01 = transform.m01; - this.m10 = transform.m10; - this.m11 = transform.m11; - this.ldet = ((long)m00*m11 - (long)m01*m10) >> 16; - this.symmetric = (m00 == m11 && m10 == -m01); + m00 = a00; + m01 = a01; + m10 = a10; + m11 = a11; + det = m00 * m11 - m01 * m10; } - public void moveTo(int x0, int y0) { + public void moveTo(float x0, float y0) { output.moveTo(x0, y0); this.idx = startIdx; this.dashOn = this.startDashOn; @@ -160,7 +114,7 @@ public class Dasher extends LineSink { output.lineJoin(); } - private void goTo(int x1, int y1) { + private void goTo(float x1, float y1) { if (dashOn) { if (starting) { this.sx1 = x1; @@ -180,52 +134,64 @@ public class Dasher extends LineSink { this.y0 = y1; } - public void lineTo(int x1, int y1) { + public void lineTo(float x1, float y1) { + // The widened line is squished to a 0 width one, so no drawing is done + if (det == 0) { + goTo(x1, y1); + return; + } + float dx = x1 - x0; + float dy = y1 - y0; + + + // Compute segment length in the untransformed + // coordinate system + + float la = (dy*m00 - dx*m10)/det; + float lb = (dy*m01 - dx*m11)/det; + float origLen = (float) Math.hypot(la, lb); + + if (origLen == 0) { + // Let the output LineSink deal with cases where dx, dy are 0. + goTo(x1, y1); + return; + } + + // The scaling factors needed to get the dx and dy of the + // transformed dash segments. + float cx = dx / origLen; + float cy = dy / origLen; + while (true) { - int d = dash[idx] - phase; - int lx = x1 - x0; - int ly = y1 - y0; - - // Compute segment length in the untransformed - // coordinate system - // IMPL NOTE - use fixed point - - int l; - if (symmetric) { - l = (int)((PiscesMath.hypot(lx, ly)*65536L)/ldet); - } else{ - long la = ((long)ly*m00 - (long)lx*m10)/ldet; - long lb = ((long)ly*m01 - (long)lx*m11)/ldet; - l = (int)PiscesMath.hypot(la, lb); - } - - if (l < d) { + float leftInThisDashSegment = dash[idx] - phase; + if (origLen < leftInThisDashSegment) { goTo(x1, y1); // Advance phase within current dash segment - phase += l; + phase += origLen; + return; + } else if (origLen == leftInThisDashSegment) { + goTo(x1, y1); + phase = 0f; + idx = (idx + 1) % dash.length; + dashOn = !dashOn; return; } - long t; - int xsplit, ysplit; -// // For zero length dashses, SE appears to move 1/8 unit -// // in device space -// if (d == 0) { -// double dlx = lx/65536.0; -// double dly = ly/65536.0; -// len = PiscesMath.hypot(dlx, dly); -// double dt = 1.0/(8*len); -// double dxsplit = (x0/65536.0) + dt*dlx; -// double dysplit = (y0/65536.0) + dt*dly; -// xsplit = (int)(dxsplit*65536.0); -// ysplit = (int)(dysplit*65536.0); -// } else { - t = ((long)d << 16)/l; - xsplit = x0 + (int)(t*(x1 - x0) >> 16); - ysplit = y0 + (int)(t*(y1 - y0) >> 16); -// } - goTo(xsplit, ysplit); + float dashx, dashy; + float dashdx = dash[idx] * cx; + float dashdy = dash[idx] * cy; + if (phase == 0) { + dashx = x0 + dashdx; + dashy = y0 + dashdy; + } else { + float p = (leftInThisDashSegment) / dash[idx]; + dashx = x0 + p * dashdx; + dashy = y0 + p * dashdy; + } + goTo(dashx, dashy); + + origLen -= (dash[idx] - phase); // Advance to next dash segment idx = (idx + 1) % dash.length; dashOn = !dashOn; @@ -233,6 +199,7 @@ public class Dasher extends LineSink { } } + public void close() { lineTo(sx, sy); if (firstDashOn) { diff --git a/jdk/src/share/classes/sun/java2d/pisces/LineSink.java b/jdk/src/share/classes/sun/java2d/pisces/LineSink.java index 6f92dd4a416..81300a25fa0 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/LineSink.java +++ b/jdk/src/share/classes/sun/java2d/pisces/LineSink.java @@ -39,16 +39,16 @@ package sun.java2d.pisces; * LineSink interface. * */ -public abstract class LineSink { +public interface LineSink { /** * Moves the current drawing position to the point (x0, * y0). * - * @param x0 the X coordinate in S15.16 format - * @param y0 the Y coordinate in S15.16 format + * @param x0 the X coordinate + * @param y0 the Y coordinate */ - public abstract void moveTo(int x0, int y0); + public void moveTo(float x0, float y0); /** * Provides a hint that the current segment should be joined to @@ -65,29 +65,29 @@ public abstract class LineSink { *

Other LineSink classes should simply pass this * hint to their output sink as needed. */ - public abstract void lineJoin(); + public void lineJoin(); /** * Draws a line from the current drawing position to the point * (x1, y1) and sets the current drawing position to * (x1, y1). * - * @param x1 the X coordinate in S15.16 format - * @param y1 the Y coordinate in S15.16 format + * @param x1 the X coordinate + * @param y1 the Y coordinate */ - public abstract void lineTo(int x1, int y1); + public void lineTo(float x1, float y1); /** * Closes the current path by drawing a line from the current * drawing position to the point specified by the moset recent * moveTo command. */ - public abstract void close(); + public void close(); /** * Ends the current path. It may be necessary to end a path in * order to allow end caps to be drawn. */ - public abstract void end(); + public void end(); } diff --git a/jdk/src/share/classes/sun/java2d/pisces/PiscesMath.java b/jdk/src/share/classes/sun/java2d/pisces/PiscesMath.java deleted file mode 100644 index 0a6e9421687..00000000000 --- a/jdk/src/share/classes/sun/java2d/pisces/PiscesMath.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.java2d.pisces; - -public class PiscesMath { - - private PiscesMath() {} - - private static final int SINTAB_LG_ENTRIES = 10; - private static final int SINTAB_ENTRIES = 1 << SINTAB_LG_ENTRIES; - private static int[] sintab; - - public static final int PI = (int)(Math.PI*65536.0); - public static final int TWO_PI = (int)(2.0*Math.PI*65536.0); - public static final int PI_OVER_TWO = (int)((Math.PI/2.0)*65536.0); - public static final int SQRT_TWO = (int)(Math.sqrt(2.0)*65536.0); - - static { - sintab = new int[SINTAB_ENTRIES + 1]; - for (int i = 0; i < SINTAB_ENTRIES + 1; i++) { - double theta = i*(Math.PI/2.0)/SINTAB_ENTRIES; - sintab[i] = (int)(Math.sin(theta)*65536.0); - } - } - - public static int sin(int theta) { - int sign = 1; - if (theta < 0) { - theta = -theta; - sign = -1; - } - // 0 <= theta - while (theta >= TWO_PI) { - theta -= TWO_PI; - } - // 0 <= theta < 2*PI - if (theta >= PI) { - theta = TWO_PI - theta; - sign = -sign; - } - // 0 <= theta < PI - if (theta > PI_OVER_TWO) { - theta = PI - theta; - } - // 0 <= theta <= PI/2 - int itheta = (int)((long)theta*SINTAB_ENTRIES/(PI_OVER_TWO)); - return sign*sintab[itheta]; - } - - public static int cos(int theta) { - return sin(PI_OVER_TWO - theta); - } - -// public static double sqrt(double x) { -// double dsqrt = Math.sqrt(x); -// int ix = (int)(x*65536.0); -// Int Isqrt = Isqrt(Ix); - -// Long Lx = (Long)(X*65536.0); -// Long Lsqrt = Lsqrt(Lx); - -// System.Out.Println(); -// System.Out.Println("X = " + X); -// System.Out.Println("Dsqrt = " + Dsqrt); - -// System.Out.Println("Ix = " + Ix); -// System.Out.Println("Isqrt = " + Isqrt/65536.0); - -// System.Out.Println("Lx = " + Lx); -// System.Out.Println("Lsqrt = " + Lsqrt/65536.0); - -// Return Dsqrt; -// } - - // From Ken Turkowski, _Fixed-Point Square Root_, In Graphics Gems V - public static int isqrt(int x) { - int fracbits = 16; - - int root = 0; - int remHi = 0; - int remLo = x; - int count = 15 + fracbits/2; - - do { - remHi = (remHi << 2) | (remLo >>> 30); // N.B. - unsigned shift R - remLo <<= 2; - root <<= 1; - int testdiv = (root << 1) + 1; - if (remHi >= testdiv) { - remHi -= testdiv; - root++; - } - } while (count-- != 0); - - return root; - } - - public static long lsqrt(long x) { - int fracbits = 16; - - long root = 0; - long remHi = 0; - long remLo = x; - int count = 31 + fracbits/2; - - do { - remHi = (remHi << 2) | (remLo >>> 62); // N.B. - unsigned shift R - remLo <<= 2; - root <<= 1; - long testDiv = (root << 1) + 1; - if (remHi >= testDiv) { - remHi -= testDiv; - root++; - } - } while (count-- != 0); - - return root; - } - - public static double hypot(double x, double y) { - // new RuntimeException().printStackTrace(); - return Math.sqrt(x*x + y*y); - } - - public static int hypot(int x, int y) { - return (int)((lsqrt((long)x*x + (long)y*y) + 128) >> 8); - } - - public static long hypot(long x, long y) { - return (lsqrt(x*x + y*y) + 128) >> 8; - } -} diff --git a/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java b/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java index 6446cb109e3..ee2b35e6809 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java +++ b/jdk/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java @@ -27,6 +27,7 @@ package sun.java2d.pisces; import java.awt.Shape; import java.awt.BasicStroke; +import java.awt.geom.FlatteningPathIterator; import java.awt.geom.Path2D; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; @@ -37,23 +38,9 @@ import sun.java2d.pipe.RenderingEngine; import sun.java2d.pipe.AATileGenerator; public class PiscesRenderingEngine extends RenderingEngine { - public static Transform4 IdentT4 = new Transform4(); public static double defaultFlat = 0.1; - static int FloatToS15_16(float flt) { - flt = flt * 65536f + 0.5f; - if (flt <= -(65536f * 65536f)) { - return Integer.MIN_VALUE; - } else if (flt >= (65536f * 65536f)) { - return Integer.MAX_VALUE; - } else { - return (int) Math.floor(flt); - } - } - - static float S15_16ToFloat(int fix) { - return (fix / 65536f); - } + private static enum NormMode {OFF, ON_NO_AA, ON_WITH_AA} /** * Create a widened path as specified by the parameters. @@ -85,18 +72,19 @@ public class PiscesRenderingEngine extends RenderingEngine { strokeTo(src, null, width, + NormMode.OFF, caps, join, miterlimit, dashes, dashphase, new LineSink() { - public void moveTo(int x0, int y0) { - p2d.moveTo(S15_16ToFloat(x0), S15_16ToFloat(y0)); + public void moveTo(float x0, float y0) { + p2d.moveTo(x0, y0); } public void lineJoin() {} - public void lineTo(int x1, int y1) { - p2d.lineTo(S15_16ToFloat(x1), S15_16ToFloat(y1)); + public void lineTo(float x1, float y1) { + p2d.lineTo(x1, y1); } public void close() { p2d.closePath(); @@ -142,14 +130,17 @@ public class PiscesRenderingEngine extends RenderingEngine { boolean antialias, final PathConsumer2D consumer) { - strokeTo(src, at, bs, thin, normalize, antialias, + NormMode norm = (normalize) ? + ((antialias) ? NormMode.ON_WITH_AA : NormMode.ON_NO_AA) + : NormMode.OFF; + strokeTo(src, at, bs, thin, norm, antialias, new LineSink() { - public void moveTo(int x0, int y0) { - consumer.moveTo(S15_16ToFloat(x0), S15_16ToFloat(y0)); + public void moveTo(float x0, float y0) { + consumer.moveTo(x0, y0); } public void lineJoin() {} - public void lineTo(int x1, int y1) { - consumer.lineTo(S15_16ToFloat(x1), S15_16ToFloat(y1)); + public void lineTo(float x1, float y1) { + consumer.lineTo(x1, y1); } public void close() { consumer.closePath(); @@ -164,7 +155,7 @@ public class PiscesRenderingEngine extends RenderingEngine { AffineTransform at, BasicStroke bs, boolean thin, - boolean normalize, + NormMode normalize, boolean antialias, LineSink lsink) { @@ -181,6 +172,7 @@ public class PiscesRenderingEngine extends RenderingEngine { strokeTo(src, at, lw, + normalize, bs.getEndCap(), bs.getLineJoin(), bs.getMiterLimit(), @@ -258,6 +250,7 @@ public class PiscesRenderingEngine extends RenderingEngine { void strokeTo(Shape src, AffineTransform at, float width, + NormMode normalize, int caps, int join, float miterlimit, @@ -265,36 +258,139 @@ public class PiscesRenderingEngine extends RenderingEngine { float dashphase, LineSink lsink) { - Transform4 t4; - - if (at == null || at.isIdentity()) { - t4 = IdentT4; - } else { - t4 = new Transform4(FloatToS15_16((float) at.getScaleX()), - FloatToS15_16((float) at.getShearX()), - FloatToS15_16((float) at.getShearY()), - FloatToS15_16((float) at.getScaleY())); + float a00 = 1f, a01 = 0f, a10 = 0f, a11 = 1f; + if (at != null && !at.isIdentity()) { + a00 = (float)at.getScaleX(); + a01 = (float)at.getShearX(); + a10 = (float)at.getShearY(); + a11 = (float)at.getScaleY(); } - - lsink = new Stroker(lsink, - FloatToS15_16(width), - caps, - join, - FloatToS15_16(miterlimit), - t4); + lsink = new Stroker(lsink, width, caps, join, miterlimit, a00, a01, a10, a11); if (dashes != null) { - int fdashes[] = new int[dashes.length]; - for (int i = 0; i < dashes.length; i++) { - fdashes[i] = FloatToS15_16(dashes[i]); + lsink = new Dasher(lsink, dashes, dashphase, a00, a01, a10, a11); + } + PathIterator pi; + if (normalize != NormMode.OFF) { + pi = new FlatteningPathIterator( + new NormalizingPathIterator(src.getPathIterator(at), normalize), + defaultFlat); + } else { + pi = src.getPathIterator(at, defaultFlat); + } + pathTo(pi, lsink); + } + + private static class NormalizingPathIterator implements PathIterator { + + private final PathIterator src; + + // the adjustment applied to the current position. + private float curx_adjust, cury_adjust; + // the adjustment applied to the last moveTo position. + private float movx_adjust, movy_adjust; + + // constants used in normalization computations + private final float lval, rval; + + NormalizingPathIterator(PathIterator src, NormMode mode) { + this.src = src; + switch (mode) { + case ON_NO_AA: + // round to nearest (0.25, 0.25) pixel + lval = rval = 0.25f; + break; + case ON_WITH_AA: + // round to nearest pixel center + lval = 0f; + rval = 0.5f; + break; + case OFF: + throw new InternalError("A NormalizingPathIterator should " + + "not be created if no normalization is being done"); + default: + throw new InternalError("Unrecognized normalization mode"); } - lsink = new Dasher(lsink, - fdashes, - FloatToS15_16(dashphase), - t4); } - PathIterator pi = src.getPathIterator(at, defaultFlat); - pathTo(pi, lsink); + public int currentSegment(float[] coords) { + int type = src.currentSegment(coords); + + int lastCoord; + switch(type) { + case PathIterator.SEG_CUBICTO: + lastCoord = 4; + break; + case PathIterator.SEG_QUADTO: + lastCoord = 2; + break; + case PathIterator.SEG_LINETO: + case PathIterator.SEG_MOVETO: + lastCoord = 0; + break; + case PathIterator.SEG_CLOSE: + // we don't want to deal with this case later. We just exit now + curx_adjust = movx_adjust; + cury_adjust = movy_adjust; + return type; + default: + throw new InternalError("Unrecognized curve type"); + } + + // normalize endpoint + float x_adjust = (float)Math.floor(coords[lastCoord] + lval) + rval - + coords[lastCoord]; + float y_adjust = (float)Math.floor(coords[lastCoord+1] + lval) + rval - + coords[lastCoord + 1]; + + coords[lastCoord ] += x_adjust; + coords[lastCoord + 1] += y_adjust; + + // now that the end points are done, normalize the control points + switch(type) { + case PathIterator.SEG_CUBICTO: + coords[0] += curx_adjust; + coords[1] += cury_adjust; + coords[2] += x_adjust; + coords[3] += y_adjust; + break; + case PathIterator.SEG_QUADTO: + coords[0] += (curx_adjust + x_adjust) / 2; + coords[1] += (cury_adjust + y_adjust) / 2; + break; + case PathIterator.SEG_LINETO: + break; + case PathIterator.SEG_MOVETO: + movx_adjust = x_adjust; + movy_adjust = y_adjust; + break; + case PathIterator.SEG_CLOSE: + throw new InternalError("This should be handled earlier."); + } + curx_adjust = x_adjust; + cury_adjust = y_adjust; + return type; + } + + public int currentSegment(double[] coords) { + float[] tmp = new float[6]; + int type = this.currentSegment(tmp); + for (int i = 0; i < 6; i++) { + coords[i] = (float) tmp[i]; + } + return type; + } + + public int getWindingRule() { + return src.getWindingRule(); + } + + public boolean isDone() { + return src.isDone(); + } + + public void next() { + src.next(); + } } void pathTo(PathIterator pi, LineSink lsink) { @@ -302,13 +398,11 @@ public class PiscesRenderingEngine extends RenderingEngine { while (!pi.isDone()) { switch (pi.currentSegment(coords)) { case PathIterator.SEG_MOVETO: - lsink.moveTo(FloatToS15_16(coords[0]), - FloatToS15_16(coords[1])); + lsink.moveTo(coords[0], coords[1]); break; case PathIterator.SEG_LINETO: lsink.lineJoin(); - lsink.lineTo(FloatToS15_16(coords[0]), - FloatToS15_16(coords[1])); + lsink.lineTo(coords[0], coords[1]); break; case PathIterator.SEG_CLOSE: lsink.lineJoin(); @@ -378,18 +472,28 @@ public class PiscesRenderingEngine extends RenderingEngine { int bbox[]) { PiscesCache pc = PiscesCache.createInstance(); - Renderer r = new Renderer(); - r.setCache(pc); - r.setAntialiasing(3, 3); - r.beginRendering(clip.getLoX(), clip.getLoY(), - clip.getWidth(), clip.getHeight()); + Renderer r; + NormMode norm = (normalize) ? NormMode.ON_WITH_AA : NormMode.OFF; if (bs == null) { - PathIterator pi = s.getPathIterator(at, defaultFlat); - r.setWindingRule(pi.getWindingRule()); + PathIterator pi; + if (normalize) { + pi = new FlatteningPathIterator( + new NormalizingPathIterator(s.getPathIterator(at), norm), + defaultFlat); + } else { + pi = s.getPathIterator(at, defaultFlat); + } + r = new Renderer(3, 3, + clip.getLoX(), clip.getLoY(), + clip.getWidth(), clip.getHeight(), + pi.getWindingRule(), pc); pathTo(pi, r); } else { - r.setWindingRule(PathIterator.WIND_NON_ZERO); - strokeTo(s, at, bs, thin, normalize, true, r); + r = new Renderer(3, 3, + clip.getLoX(), clip.getLoY(), + clip.getWidth(), clip.getHeight(), + PathIterator.WIND_NON_ZERO, pc); + strokeTo(s, at, bs, thin, norm, true, r); } r.endRendering(); PiscesTileGenerator ptg = new PiscesTileGenerator(pc, r.MAX_AA_ALPHA); @@ -420,3 +524,4 @@ public class PiscesRenderingEngine extends RenderingEngine { } } } + diff --git a/jdk/src/share/classes/sun/java2d/pisces/Renderer.java b/jdk/src/share/classes/sun/java2d/pisces/Renderer.java index fa58146a5ad..9768e90a77b 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/Renderer.java +++ b/jdk/src/share/classes/sun/java2d/pisces/Renderer.java @@ -25,447 +25,441 @@ package sun.java2d.pisces; -public class Renderer extends LineSink { +import java.util.Arrays; + +public class Renderer implements LineSink { + +/////////////////////////////////////////////////////////////////////////////// +// Scan line iterator and edge crossing data. +////////////////////////////////////////////////////////////////////////////// + + private int[] crossings; + + // This is an array of indices into the edge array. It is initialized to + // [i * SIZEOF_STRUCT_EDGE for i in range(0, edgesSize/SIZEOF_STRUCT_EDGE)] + // (where range(i, j) is i,i+1,...,j-1 -- just like in python). + // The reason for keeping this is because we need the edges array sorted + // by y0, but we don't want to move all that data around, so instead we + // sort the indices into the edge array, and use edgeIndices to access + // the edges array. This is meant to simulate a pointer array (hence the name) + private int[] edgePtrs; + + // crossing bounds. The bounds are not necessarily tight (the scan line + // at minY, for example, might have no crossings). The x bounds will + // be accumulated as crossings are computed. + private int minY, maxY; + private int minX, maxX; + private int nextY; + + // indices into the edge pointer list. They indicate the "active" sublist in + // the edge list (the portion of the list that contains all the edges that + // cross the next scan line). + private int lo, hi; + + private static final int INIT_CROSSINGS_SIZE = 50; + private void ScanLineItInitialize() { + crossings = new int[INIT_CROSSINGS_SIZE]; + edgePtrs = new int[edgesSize / SIZEOF_STRUCT_EDGE]; + for (int i = 0; i < edgePtrs.length; i++) { + edgePtrs[i] = i * SIZEOF_STRUCT_EDGE; + } + + qsort(0, edgePtrs.length - 1); + + // We don't care if we clip some of the line off with ceil, since + // no scan line crossings will be eliminated (in fact, the ceil is + // the y of the first scan line crossing). + nextY = minY = Math.max(boundsMinY, (int)Math.ceil(edgeMinY)); + maxY = Math.min(boundsMaxY, (int)Math.ceil(edgeMaxY)); + + for (lo = 0; lo < edgePtrs.length && edges[edgePtrs[lo]+Y1] <= nextY; lo++) + ; + for (hi = lo; hi < edgePtrs.length && edges[edgePtrs[hi]+CURY] <= nextY; hi++) + ; // the active list is *edgePtrs[lo] (inclusive) *edgePtrs[hi] (exclusive) + for (int i = lo; i < hi; i++) { + setCurY(edgePtrs[i], nextY); + } + + // We accumulate X in the iterator because accumulating it in addEdge + // like we do with Y does not do much good: if there's an edge + // (0,0)->(1000,10000), and if y gets clipped to 1000, then the x + // bound should be 100, but the accumulator from addEdge would say 1000, + // so we'd still have to accumulate the X bounds as we add crossings. + minX = boundsMinX; + maxX = boundsMaxX; + } + + private int ScanLineItCurrentY() { + return nextY - 1; + } + + private int ScanLineItGoToNextYAndComputeCrossings() { + // we go through the active list and remove the ones that don't cross + // the nextY scanline. + int crossingIdx = 0; + for (int i = lo; i < hi; i++) { + if (edges[edgePtrs[i]+Y1] <= nextY) { + edgePtrs[i] = edgePtrs[lo++]; + } + } + if (hi - lo > crossings.length) { + int newSize = Math.max(hi - lo, crossings.length * 2); + crossings = Arrays.copyOf(crossings, newSize); + } + // Now every edge between lo and hi crosses nextY. Compute it's + // crossing and put it in the crossings array. + for (int i = lo; i < hi; i++) { + addCrossing(nextY, getCurCrossing(edgePtrs[i]), (int)edges[edgePtrs[i]+OR], crossingIdx); + gotoNextY(edgePtrs[i]); + crossingIdx++; + } + + nextY++; + // Expand active list to include new edges. + for (; hi < edgePtrs.length && edges[edgePtrs[hi]+CURY] <= nextY; hi++) { + setCurY(edgePtrs[hi], nextY); + } + + Arrays.sort(crossings, 0, crossingIdx); + return crossingIdx; + } + + private boolean ScanLineItHasNext() { + return nextY < maxY; + } + + private void addCrossing(int y, int x, int or, int idx) { + if (x < minX) { + minX = x; + } + if (x > maxX) { + maxX = x; + } + x <<= 1; + crossings[idx] = ((or == 1) ? (x | 0x1) : x); + } + + + // quicksort implementation for sorting the edge indices ("pointers") + // by increasing y0. first, last are indices into the "pointer" array + // It sorts the pointer array from first (inclusive) to last (inclusive) + private void qsort(int first, int last) { + if (last > first) { + int p = partition(first, last); + if (first < p - 1) { + qsort(first, p - 1); + } + if (p < last) { + qsort(p, last); + } + } + } + + // i, j are indices into edgePtrs. + private int partition(int i, int j) { + int pivotVal = edgePtrs[i]; + while (i <= j) { + // edges[edgePtrs[i]+1] is equivalent to (*(edgePtrs[i])).y0 in C + while (edges[edgePtrs[i]+CURY] < edges[pivotVal+CURY]) { i++; } + while (edges[edgePtrs[j]+CURY] > edges[pivotVal+CURY]) { j--; } + if (i <= j) { + int tmp = edgePtrs[i]; + edgePtrs[i] = edgePtrs[j]; + edgePtrs[j] = tmp; + i++; + j--; + } + } + return i; + } + +//============================================================================ + + +////////////////////////////////////////////////////////////////////////////// +// EDGE LIST +////////////////////////////////////////////////////////////////////////////// + + private static final int INIT_NUM_EDGES = 1000; + private static final int SIZEOF_STRUCT_EDGE = 5; + + // The following array is a poor man's struct array: + // it simulates a struct array by having + // edges[SIZEOF_STRUCT_EDGE * i + j] be the jth field in the ith element + // of an array of edge structs. + private float[] edges; + private int edgesSize; // size of the edge list. + private static final int Y1 = 0; + private static final int SLOPE = 1; + private static final int OR = 2; // the orientation. This can be -1 or 1. + // -1 means up, 1 means down. + private static final int CURY = 3; // j = 5 corresponds to the "current Y". + // Each edge keeps track of the last scanline + // crossing it computed, and this is the y coord of + // that scanline. + private static final int CURX = 4; //the x coord of the current crossing. + + // Note that while the array is declared as a float[] not all of it's + // elements should be floats. currentY and Orientation should be ints (or int and + // byte respectively), but they all need to be the same type. This isn't + // really a problem because floats can represent exactly all 23 bit integers, + // which should be more than enough. + // Note, also, that we only need x1 for slope computation, so we don't need + // to store it. x0, y0 don't need to be stored either. They can be put into + // curx, cury, and it's ok if they're lost when curx and cury are changed. + // We take this undeniably ugly and error prone approach (instead of simply + // making an Edge class) for performance reasons. Also, it would probably be nicer + // to have one array for each field, but that would defeat the purpose because + // it would make poor use of the processor cache, since we tend to access + // all the fields for one edge at a time. + + private float edgeMinY; + private float edgeMaxY; + + + private void addEdge(float x0, float y0, float x1, float y1) { + float or = (y0 < y1) ? 1f : -1f; // orientation: 1 = UP; -1 = DOWN + if (or == -1) { + float tmp = y0; + y0 = y1; + y1 = tmp; + tmp = x0; + x0 = x1; + x1 = tmp; + } + // skip edges that don't cross a scanline + if (Math.ceil(y0) >= Math.ceil(y1)) { + return; + } + + int newSize = edgesSize + SIZEOF_STRUCT_EDGE; + if (edges.length < newSize) { + edges = Arrays.copyOf(edges, newSize * 2); + } + edges[edgesSize+CURX] = x0; + edges[edgesSize+CURY] = y0; + edges[edgesSize+Y1] = y1; + edges[edgesSize+SLOPE] = (x1 - x0) / (y1 - y0); + edges[edgesSize+OR] = or; + // the crossing values can't be initialized meaningfully yet. This + // will have to wait until setCurY is called + edgesSize += SIZEOF_STRUCT_EDGE; + + // Accumulate edgeMinY and edgeMaxY + if (y0 < edgeMinY) { edgeMinY = y0; } + if (y1 > edgeMaxY) { edgeMaxY = y1; } + } + + // As far as the following methods care, this edges extends to infinity. + // They can compute the x intersect of any horizontal line. + // precondition: idx is the index to the start of the desired edge. + // So, if the ith edge is wanted, idx should be SIZEOF_STRUCT_EDGE * i + private void setCurY(int idx, int y) { + // compute the x crossing of edge at idx and horizontal line y + // currentXCrossing = (y - y0)*slope + x0 + edges[idx + CURX] = (y - edges[idx + CURY]) * edges[idx + SLOPE] + edges[idx+CURX]; + edges[idx + CURY] = (float)y; + } + + private void gotoNextY(int idx) { + edges[idx + CURY] += 1f; // i.e. curY += 1 + edges[idx + CURX] += edges[idx + SLOPE]; // i.e. curXCrossing += slope + } + + private int getCurCrossing(int idx) { + return (int)edges[idx + CURX]; + } +//==================================================================================== + public static final int WIND_EVEN_ODD = 0; public static final int WIND_NON_ZERO = 1; - // Initial edge list size - // IMPL_NOTE - restore size after growth - public static final int INITIAL_EDGES = 1000; - - // Recommended maximum scratchpad sizes. The arrays will grow - // larger if needed, but when finished() is called they will be released - // if they have grown larger than these sizes. - public static final int DEFAULT_INDICES_SIZE = 8192; - public static final int DEFAULT_CROSSINGS_SIZE = 32*1024; - // Antialiasing - private int SUBPIXEL_LG_POSITIONS_X; - private int SUBPIXEL_LG_POSITIONS_Y; - private int SUBPIXEL_MASK_X; - private int SUBPIXEL_MASK_Y; - private int SUBPIXEL_POSITIONS_X; - private int SUBPIXEL_POSITIONS_Y; - int MAX_AA_ALPHA; - private int MAX_AA_ALPHA_DENOM; - private int HALF_MAX_AA_ALPHA_DENOM; - private int XSHIFT; - private int YSHIFT; - private int YSTEP; - private int HYSTEP; - private int YMASK; - - private static final int MIN_QUAD_OPT_WIDTH = 100 << 16; + final private int SUBPIXEL_LG_POSITIONS_X; + final private int SUBPIXEL_LG_POSITIONS_Y; + final private int SUBPIXEL_POSITIONS_X; + final private int SUBPIXEL_POSITIONS_Y; + final private int SUBPIXEL_MASK_X; + final private int SUBPIXEL_MASK_Y; + final int MAX_AA_ALPHA; // Cache to store RLE-encoded coverage mask of the current primitive - PiscesCache cache; + final PiscesCache cache; - // Bounds of the drawing region, at S15.16 precsion - private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY; - - // Bounds of the current primitive, at subsample precision - private int rasterMinX, rasterMaxX, rasterMinY, rasterMaxY; + // Bounds of the drawing region, at subpixel precision. + final private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY; // Pixel bounding box for current primitive - private int bboxX0, bboxY0, bboxX1, bboxY1; + private int pix_bboxX0, pix_bboxY0, pix_bboxX1, pix_bboxY1; // Current winding rule - private int windingRule; + final private int windingRule; // Current drawing position, i.e., final point of last segment - private int x0, y0; + private float x0, y0; // Position of most recent 'moveTo' command - private int sx0, sy0; + private float pix_sx0, pix_sy0; - // Buffer to be filled with one row's worth of alpha values - private byte[] rowAA; // needs to be short if 16x16 subsampling - - // Track the number of vertical extrema of the incoming edge list - // in order to determine the maximum number of crossings of a - // scanline - private int firstOrientation; - private int lastOrientation; - private int flips; - - // Parameters for emitRow - private int alphaWidth; - - public Renderer() { - } - - public void setAntialiasing(int subpixelLgPositionsX, - int subpixelLgPositionsY) { + public Renderer(int subpixelLgPositionsX, int subpixelLgPositionsY, + int pix_boundsX, int pix_boundsY, + int pix_boundsWidth, int pix_boundsHeight, + int windingRule, + PiscesCache cache) { this.SUBPIXEL_LG_POSITIONS_X = subpixelLgPositionsX; this.SUBPIXEL_LG_POSITIONS_Y = subpixelLgPositionsY; + this.SUBPIXEL_MASK_X = (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1; + this.SUBPIXEL_MASK_Y = (1 << (SUBPIXEL_LG_POSITIONS_Y)) - 1; + this.SUBPIXEL_POSITIONS_X = 1 << (SUBPIXEL_LG_POSITIONS_X); + this.SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y); + this.MAX_AA_ALPHA = (SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y); - this.SUBPIXEL_MASK_X = - (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1; - this.SUBPIXEL_MASK_Y = - (1 << (SUBPIXEL_LG_POSITIONS_Y)) - 1; - this.SUBPIXEL_POSITIONS_X = - 1 << (SUBPIXEL_LG_POSITIONS_X); - this.SUBPIXEL_POSITIONS_Y = - 1 << (SUBPIXEL_LG_POSITIONS_Y); - this.MAX_AA_ALPHA = - (SUBPIXEL_POSITIONS_X*SUBPIXEL_POSITIONS_Y); - this.MAX_AA_ALPHA_DENOM = 255*MAX_AA_ALPHA; - this.HALF_MAX_AA_ALPHA_DENOM = MAX_AA_ALPHA_DENOM/2; - this.XSHIFT = 16 - SUBPIXEL_LG_POSITIONS_X; - this.YSHIFT = 16 - SUBPIXEL_LG_POSITIONS_Y; - this.YSTEP = 1 << YSHIFT; - this.HYSTEP = 1 << (YSHIFT - 1); - this.YMASK = ~(YSTEP - 1); - } + this.edges = new float[SIZEOF_STRUCT_EDGE * INIT_NUM_EDGES]; + edgeMinY = Float.POSITIVE_INFINITY; + edgeMaxY = Float.NEGATIVE_INFINITY; + edgesSize = 0; - public int getSubpixelLgPositionsX() { - return SUBPIXEL_LG_POSITIONS_X; - } - - public int getSubpixelLgPositionsY() { - return SUBPIXEL_LG_POSITIONS_Y; - } - - public void setWindingRule(int windingRule) { this.windingRule = windingRule; + this.cache = cache; + + this.boundsMinX = pix_boundsX * SUBPIXEL_POSITIONS_X; + this.boundsMinY = pix_boundsY * SUBPIXEL_POSITIONS_Y; + this.boundsMaxX = (pix_boundsX + pix_boundsWidth) * SUBPIXEL_POSITIONS_X; + this.boundsMaxY = (pix_boundsY + pix_boundsHeight) * SUBPIXEL_POSITIONS_Y; + + this.pix_bboxX0 = pix_boundsX; + this.pix_bboxY0 = pix_boundsY; + this.pix_bboxX1 = pix_boundsX + pix_boundsWidth; + this.pix_bboxY1 = pix_boundsY + pix_boundsHeight; } - public int getWindingRule() { - return windingRule; + private float tosubpixx(float pix_x) { + return pix_x * SUBPIXEL_POSITIONS_X; + } + private float tosubpixy(float pix_y) { + return pix_y * SUBPIXEL_POSITIONS_Y; } - public void beginRendering(int boundsX, int boundsY, - int boundsWidth, int boundsHeight) { - lastOrientation = 0; - flips = 0; - - resetEdges(); - - this.boundsMinX = boundsX << 16; - this.boundsMinY = boundsY << 16; - this.boundsMaxX = (boundsX + boundsWidth) << 16; - this.boundsMaxY = (boundsY + boundsHeight) << 16; - - this.bboxX0 = boundsX; - this.bboxY0 = boundsY; - this.bboxX1 = boundsX + boundsWidth; - this.bboxY1 = boundsY + boundsHeight; - } - - public void moveTo(int x0, int y0) { - // System.out.println("Renderer: moveTo " + x0/65536.0 + " " + y0/65536.0); + public void moveTo(float pix_x0, float pix_y0) { close(); - this.sx0 = this.x0 = x0; - this.sy0 = this.y0 = y0; - this.lastOrientation = 0; + this.pix_sx0 = pix_x0; + this.pix_sy0 = pix_y0; + this.y0 = tosubpixy(pix_y0); + this.x0 = tosubpixx(pix_x0); } - public void lineJoin() { - // System.out.println("Renderer: lineJoin"); - // do nothing - } + public void lineJoin() { /* do nothing */ } - public void lineTo(int x1, int y1) { - // System.out.println("Renderer: lineTo " + x1/65536.0 + " " + y1/65536.0); + public void lineTo(float pix_x1, float pix_y1) { + float x1 = tosubpixx(pix_x1); + float y1 = tosubpixy(pix_y1); // Ignore horizontal lines - // Next line will count flip if (y0 == y1) { this.x0 = x1; return; } - int orientation = (y0 < y1) ? 1 : -1; - if (lastOrientation == 0) { - firstOrientation = orientation; - } else if (orientation != lastOrientation) { - ++flips; - } - lastOrientation = orientation; - - // Bias Y by 1 ULP so endpoints never lie on a scanline - addEdge(x0, y0 | 0x1, x1, y1 | 0x1); + addEdge(x0, y0, x1, y1); this.x0 = x1; this.y0 = y1; } public void close() { - // System.out.println("Renderer: close"); - - int orientation = lastOrientation; - if (y0 != sy0) { - orientation = (y0 < sy0) ? 1 : -1; - } - if (orientation != firstOrientation) { - ++flips; - } - lineTo(sx0, sy0); + // lineTo expects its input in pixel coordinates. + lineTo(pix_sx0, pix_sy0); } public void end() { close(); - // System.out.println("Renderer: end"); - // do nothing - } - - // Scan convert a single edge - private void computeCrossingsForEdge(int index, - int boundsMinY, int boundsMaxY) { - int iy0 = edges[index + 1]; - int iy1 = edges[index + 3]; - - // Clip to valid Y range - int clipy0 = (iy0 > boundsMinY) ? iy0 : boundsMinY; - int clipy1 = (iy1 < boundsMaxY) ? iy1 : boundsMaxY; - - int minY = ((clipy0 + HYSTEP) & YMASK) + HYSTEP; - int maxY = ((clipy1 - HYSTEP) & YMASK) + HYSTEP; - - // IMPL_NOTE - If line falls outside the valid X range, could - // draw a vertical line instead - - // Exit if no scanlines are crossed - if (minY > maxY) { - return; - } - - // Scan convert line using a DDA approach - - int ix0 = edges[index]; - int ix1 = edges[index + 2]; - long dx = ((long) ix1) - ix0; - long dy = ((long) iy1) - iy0; - - // Compute first crossing point at y = minY - int orientation = edges[index + 4]; - int y = minY; - long lx = (((long) y) - iy0)*dx/dy + ix0; - addCrossing(y >> YSHIFT, (int)(lx >> XSHIFT), orientation); - - // Advance y to next scanline, exit if past endpoint - y += YSTEP; - if (y > maxY) { - return; - } - - // Compute xstep only if additional scanlines are crossed - // For each scanline, add xstep to lx and YSTEP to y and - // emit the new crossing - long xstep = ((long)YSTEP*dx)/dy; - for (; y <= maxY; y += YSTEP) { - lx += xstep; - addCrossing(y >> YSHIFT, (int)(lx >> XSHIFT), orientation); - } - } - - private void computeBounds() { - rasterMinX = crossingMinX & ~SUBPIXEL_MASK_X; - rasterMaxX = crossingMaxX | SUBPIXEL_MASK_X; - rasterMinY = crossingMinY & ~SUBPIXEL_MASK_Y; - rasterMaxY = crossingMaxY | SUBPIXEL_MASK_Y; - - // If nothing was drawn, we have: - // minX = Integer.MAX_VALUE and maxX = Integer.MIN_VALUE - // so nothing to render - if (rasterMinX > rasterMaxX || rasterMinY > rasterMaxY) { - rasterMinX = 0; - rasterMaxX = -1; - rasterMinY = 0; - rasterMaxY = -1; - return; - } - - if (rasterMinX < boundsMinX >> XSHIFT) { - rasterMinX = boundsMinX >> XSHIFT; - } - if (rasterMinY < boundsMinY >> YSHIFT) { - rasterMinY = boundsMinY >> YSHIFT; - } - if (rasterMaxX > boundsMaxX >> XSHIFT) { - rasterMaxX = boundsMaxX >> XSHIFT; - } - if (rasterMaxY > boundsMaxY >> YSHIFT) { - rasterMaxY = boundsMaxY >> YSHIFT; - } - } - - private int clamp(int x, int min, int max) { - if (x < min) { - return min; - } else if (x > max) { - return max; - } - return x; } private void _endRendering() { - if (flips == 0) { - bboxX0 = bboxY0 = 0; - bboxX1 = bboxY1 = -1; - return; - } + // Mask to determine the relevant bit of the crossing sum + // 0x1 if EVEN_ODD, all bits if NON_ZERO + int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0; - // Special case for filling a single rect with a flat, opaque color - // REMIND: This special case was not originally written to fill a - // cache object and called directly to a Blit - it needs some code - // to fill the cache instead to be useful for this usage... - if (false /* Does not work with cache (yet?) */ && - edgeIdx == 10 && - edges[0] == edges[2] && - edges[1] == edges[6] && - edges[3] == edges[8] && - edges[5] == edges[7] && - Math.abs(edges[0] - edges[5]) > MIN_QUAD_OPT_WIDTH) - { + // add 1 to better deal with the last pixel in a pixel row. + int width = ((boundsMaxX - boundsMinX) >> SUBPIXEL_LG_POSITIONS_X) + 1; + byte[] alpha = new byte[width+1]; - int x0 = edges[0] >> XSHIFT; - int y0 = edges[1] >> YSHIFT; - int x1 = edges[5] >> XSHIFT; - int y1 = edges[3] >> YSHIFT; + // Now we iterate through the scanlines. We must tell emitRow the coord + // of the first non-transparent pixel, so we must keep accumulators for + // the first and last pixels of the section of the current pixel row + // that we will emit. + // We also need to accumulate pix_bbox*, but the iterator does it + // for us. We will just get the values from it once this loop is done + int pix_maxX = Integer.MIN_VALUE; + int pix_minX = Integer.MAX_VALUE; - if (x0 > x1) { - int tmp = x0; - x0 = x1; - x1 = tmp; - } - if (y0 > y1) { - int tmp = y0; - y0 = y1; - y1 = tmp; + int y = boundsMinY; // needs to be declared here so we emit the last row properly. + ScanLineItInitialize(); + for ( ; ScanLineItHasNext(); ) { + int numCrossings = ScanLineItGoToNextYAndComputeCrossings(); + y = ScanLineItCurrentY(); + + if (numCrossings > 0) { + int lowx = crossings[0] >> 1; + int highx = crossings[numCrossings - 1] >> 1; + int x0 = Math.max(lowx, boundsMinX); + int x1 = Math.min(highx, boundsMaxX); + + pix_minX = Math.min(pix_minX, x0 >> SUBPIXEL_LG_POSITIONS_X); + pix_maxX = Math.max(pix_maxX, x1 >> SUBPIXEL_LG_POSITIONS_X); } - int bMinX = this.boundsMinX >> XSHIFT; - int bMinY = this.boundsMinY >> YSHIFT; - int bMaxX = this.boundsMaxX >> XSHIFT; - int bMaxY = this.boundsMaxY >> YSHIFT; + int sum = 0; + int prev = boundsMinX; + for (int i = 0; i < numCrossings; i++) { + int curxo = crossings[i]; + int curx = curxo >> 1; + int crorientation = ((curxo & 0x1) == 0x1) ? 1 : -1; + if ((sum & mask) != 0) { + int x0 = Math.max(prev, boundsMinX); + int x1 = Math.min(curx, boundsMaxX); + if (x0 < x1) { + x0 -= boundsMinX; // turn x0, x1 from coords to indeces + x1 -= boundsMinX; // in the alpha array. - // Clip to image bounds in supersampled coordinates - x0 = clamp(x0, bMinX, bMaxX); - x1 = clamp(x1, bMinX, bMaxX); - y0 = clamp(y0, bMinY, bMaxY); - y1 = clamp(y1, bMinY, bMaxY); + int pix_x = x0 >> SUBPIXEL_LG_POSITIONS_X; + int pix_xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X; - /* - * REMIND: Need to fill the cache here instead... - Blit.fillRectSrcOver(this, - imageData, imageType, - imageOffset, - imageScanlineStride, imagePixelStride, - width, height, - x0, y0, x1, y1, - cred, cgreen, cblue); - */ - - bboxX0 = x0 >> SUBPIXEL_LG_POSITIONS_X; - bboxY0 = y0 >> SUBPIXEL_LG_POSITIONS_Y; - bboxX1 = (x1 + SUBPIXEL_POSITIONS_X - 1) - >> SUBPIXEL_LG_POSITIONS_X; - bboxY1 = (y1 + SUBPIXEL_POSITIONS_Y - 1) - >> SUBPIXEL_LG_POSITIONS_Y; - - return; - } - - int minY = (edgeMinY > boundsMinY) ? edgeMinY : boundsMinY; - int maxY = (edgeMaxY < boundsMaxY) ? edgeMaxY : boundsMaxY; - - // Check for empty intersection of primitive with the drawing area - if (minY > maxY) { - bboxX0 = bboxY0 = 0; - bboxX1 = bboxY1 = -1; - return; - } - - // Compute Y extent in subpixel coordinates - int iminY = (minY >> YSHIFT) & ~SUBPIXEL_MASK_Y; - int imaxY = (maxY >> YSHIFT) | SUBPIXEL_MASK_Y; - int yextent = (imaxY - iminY) + 1; - - // Maximum number of crossings - int size = flips*yextent; - - int bmax = (boundsMaxY >> YSHIFT) - 1; - if (imaxY > bmax) { - imaxY = bmax; - } - - // Initialize X bounds, will be refined for each strip - bboxX0 = Integer.MAX_VALUE; - bboxX1 = Integer.MIN_VALUE; - - // Set Y bounds - bboxY0 = iminY >> SUBPIXEL_LG_POSITIONS_Y; - bboxY1 = (imaxY + SUBPIXEL_POSITIONS_Y - 1) >> SUBPIXEL_LG_POSITIONS_Y; - - // Compute number of rows that can be processing using - // a crossings table no larger than DEFAULT_CROSSINGS_SIZE. - // However, we must process at least one row, so we grow the table - // temporarily if needed. This would require an object with a - // huge number of flips. - int rows = DEFAULT_CROSSINGS_SIZE/(flips*SUBPIXEL_POSITIONS_Y); - rows = Math.min(rows, yextent); - rows = Math.max(rows, 1); - for (int i = iminY; i <= imaxY; i += rows*SUBPIXEL_POSITIONS_Y) { - // Compute index of last scanline to be processed in this pass - int last = Math.min(i + rows*SUBPIXEL_POSITIONS_Y - 1, imaxY); - setCrossingsExtents(i, last, flips); - - int bminY = i << YSHIFT; - int bmaxY = (last << YSHIFT) | ~YMASK; - - // Process edges from the edge list - int maxIdx = edgeIdx; - for (int index = 0; index < maxIdx; index += 5) { - // Test y1 < min: - // - // If edge lies entirely above current strip, - // discard it - if (edges[index + 3] < bminY) { - // Overwrite the edge with the last edge - edgeIdx -= 5; - int fidx = edgeIdx; - int tidx = index; - edges[tidx++] = edges[fidx++]; - edges[tidx++] = edges[fidx++]; - edges[tidx++] = edges[fidx++]; - edges[tidx++] = edges[fidx++]; - edges[tidx ] = edges[fidx ]; - - maxIdx -= 5; - index -= 5; - continue; + if (pix_x == pix_xmaxm1) { + // Start and end in same pixel + alpha[pix_x] += (x1 - x0); + alpha[pix_x+1] -= (x1 - x0); + } else { + int pix_xmax = x1 >> SUBPIXEL_LG_POSITIONS_X; + alpha[pix_x] += SUBPIXEL_POSITIONS_X - (x0 & SUBPIXEL_MASK_X); + alpha[pix_x+1] += (x0 & SUBPIXEL_MASK_X); + alpha[pix_xmax] -= SUBPIXEL_POSITIONS_X - (x1 & SUBPIXEL_MASK_X); + alpha[pix_xmax+1] -= (x1 & SUBPIXEL_MASK_X); + } + } } - - // Test y0 > max: - // - // If edge lies entirely below current strip, - // skip it for now - if (edges[index + 1] > bmaxY) { - continue; - } - - computeCrossingsForEdge(index, bminY, bmaxY); + sum += crorientation; + prev = curx; } - computeBounds(); - if (rasterMaxX < rasterMinX) { - continue; + if ((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) { + emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX); + pix_minX = Integer.MAX_VALUE; + pix_maxX = Integer.MIN_VALUE; } - - bboxX0 = Math.min(bboxX0, - rasterMinX >> SUBPIXEL_LG_POSITIONS_X); - bboxX1 = Math.max(bboxX1, - (rasterMaxX + SUBPIXEL_POSITIONS_X - 1) - >> SUBPIXEL_LG_POSITIONS_X); - renderStrip(); } - // Free up any unusually large scratchpad memory used by the - // preceding primitive - crossingListFinished(); + // Emit final row + if (pix_maxX >= pix_minX) { + emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX); + } + pix_bboxX0 = minX >> SUBPIXEL_LG_POSITIONS_X; + pix_bboxX1 = maxX >> SUBPIXEL_LG_POSITIONS_X; + pix_bboxY0 = minY >> SUBPIXEL_LG_POSITIONS_Y; + pix_bboxY1 = maxY >> SUBPIXEL_LG_POSITIONS_Y; } + public void endRendering() { // Set up the cache to accumulate the bounding box if (cache != null) { @@ -478,176 +472,31 @@ public class Renderer extends LineSink { _endRendering(); } - public void getBoundingBox(int[] bbox) { - bbox[0] = bboxX0; - bbox[1] = bboxY0; - bbox[2] = bboxX1 - bboxX0; - bbox[3] = bboxY1 - bboxY0; + public void getBoundingBox(int[] pix_bbox) { + pix_bbox[0] = pix_bboxX0; + pix_bbox[1] = pix_bboxY0; + pix_bbox[2] = pix_bboxX1 - pix_bboxX0; + pix_bbox[3] = pix_bboxY1 - pix_bboxY0; } - private void renderStrip() { - // Grow rowAA according to the raster width - int width = (rasterMaxX - rasterMinX + 1) >> SUBPIXEL_LG_POSITIONS_X; - alphaWidth = width; - - // Allocate one extra entry in rowAA to avoid a conditional in - // the rendering loop - int bufLen = width + 1; - if (this.rowAA == null || this.rowAA.length < bufLen) { - this.rowAA = new byte[bufLen]; - } - - // Mask to determine the relevant bit of the crossing sum - // 0x1 if EVEN_ODD, all bits if NON_ZERO - int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0; - - int y = 0; - int prevY = rasterMinY - 1; - - int minX = Integer.MAX_VALUE; - int maxX = Integer.MIN_VALUE; - - iterateCrossings(); - while (hasMoreCrossingRows()) { - y = crossingY; - - // Emit any skipped rows - for (int j = prevY + 1; j < y; j++) { - if (((j & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) || - (j == rasterMaxY)) { - emitRow(j >> SUBPIXEL_LG_POSITIONS_Y, 0, -1); - } - } - prevY = y; - - if (crossingRowIndex < crossingRowCount) { - int lx = crossings[crossingRowOffset + crossingRowIndex]; - lx >>= 1; - int hx = crossings[crossingRowOffset + crossingRowCount - 1]; - hx >>= 1; - int x0 = lx > rasterMinX ? lx : rasterMinX; - int x1 = hx < rasterMaxX ? hx : rasterMaxX; - x0 -= rasterMinX; - x1 -= rasterMinX; - - minX = Math.min(minX, x0 >> SUBPIXEL_LG_POSITIONS_X); - maxX = Math.max(maxX, x1 >> SUBPIXEL_LG_POSITIONS_X); - } - - int sum = 0; - int prev = rasterMinX; - while (crossingRowIndex < crossingRowCount) { - int crxo = crossings[crossingRowOffset + crossingRowIndex]; - crossingRowIndex++; - - int crx = crxo >> 1; - int crorientation = ((crxo & 0x1) == 0x1) ? 1 : -1; - - if ((sum & mask) != 0) { - // Clip to active X range, if x1 < x0 loop will - // have no effect - int x0 = prev > rasterMinX ? prev : rasterMinX; - int x1 = crx < rasterMaxX ? crx : rasterMaxX; - - // Empty spans - if (x1 > x0) { - x0 -= rasterMinX; - x1 -= rasterMinX; - - // Accumulate alpha, equivalent to: - // for (int x = x0; x < x1; x++) { - // ++rowAA[x >> SUBPIXEL_LG_POSITIONS_X]; - // } - // - // In the middle of the span, we can update a full - // pixel at a time (i.e., SUBPIXEL_POSITIONS_X - // subpixels) - - int x = x0 >> SUBPIXEL_LG_POSITIONS_X; - int xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X; - if (x == xmaxm1) { - // Start and end in same pixel - rowAA[x] += x1 - x0; - } else { - // Start and end in different pixels - rowAA[x++] += SUBPIXEL_POSITIONS_X - - (x0 & SUBPIXEL_MASK_X); - int xmax = x1 >> SUBPIXEL_LG_POSITIONS_X; - while (x < xmax) { - rowAA[x++] += SUBPIXEL_POSITIONS_X; - } - // Note - at this point it is possible that - // x == width, which implies that - // x1 & SUBPIXEL_MASK_X == 0. We allocate - // one extra entry in rowAA so this - // assignment will be harmless. The alternative - // is an extra conditional here, or some other - // scheme to deal with the last pixel better. - rowAA[x] += x1 & SUBPIXEL_MASK_X; - } - } - } - sum += crorientation; - prev = crx; - } - - // Every SUBPIXEL_POSITIONS rows, output an antialiased row - if (((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) || - (y == rasterMaxY)) { - emitRow(y >> SUBPIXEL_LG_POSITIONS_Y, minX, maxX); - minX = Integer.MAX_VALUE; - maxX = Integer.MIN_VALUE; - } - } - - // Emit final row - for (int j = prevY + 1; j <= rasterMaxY; j++) { - if (((j & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) || - (j == rasterMaxY)) { - emitRow(j >> SUBPIXEL_LG_POSITIONS_Y, minX, maxX); - minX = Integer.MAX_VALUE; - maxX = Integer.MIN_VALUE; - } - } - } - - private void clearAlpha(byte[] alpha, - int width, - int minX, int maxX) { - if (maxX >= minX) { - int w = maxX - minX + 1; - if (w + minX > width) { - w = width - minX; - } - - int aidx = minX; - for (int i = 0; i < w; i++, aidx++) { - alpha[aidx] = (byte)0; - } - } - } - - private void emitRow(int y, int minX, int maxX) { + private void emitRow(byte[] alphaRow, int pix_y, int pix_from, int pix_to) { // Copy rowAA data into the cache if one is present if (cache != null) { - if (maxX >= minX) { - int x0 = minX + (rasterMinX >> SUBPIXEL_LG_POSITIONS_X); - int x1 = maxX + (rasterMinX >> SUBPIXEL_LG_POSITIONS_X); + if (pix_to >= pix_from) { + cache.startRow(pix_y, pix_from, pix_to); - cache.startRow(y, x0, x1); - int srcIdx = minX; + // Perform run-length encoding and store results in the cache + int from = pix_from - (boundsMinX >> SUBPIXEL_LG_POSITIONS_X); + int to = pix_to - (boundsMinX >> SUBPIXEL_LG_POSITIONS_X); - // Perform run-length encoding - // and store results in the cache - byte startVal = rowAA[srcIdx++]; int runLen = 1; - while (srcIdx <= maxX) { - byte nextVal = rowAA[srcIdx++]; + byte startVal = alphaRow[from]; + for (int i = from + 1; i <= to; i++) { + byte nextVal = (byte)(startVal + alphaRow[i]); if (nextVal == startVal && runLen < 255) { - ++runLen; + runLen++; } else { cache.addRLERun(startVal, runLen); - runLen = 1; startVal = nextVal; } @@ -656,190 +505,6 @@ public class Renderer extends LineSink { cache.addRLERun((byte)0, 0); } } - - clearAlpha(rowAA, - alphaWidth, - minX, maxX); - } - - public void setCache(PiscesCache cache) { - this.cache = cache; - } - - // Edge list data - - private int[] edges = new int[5*INITIAL_EDGES]; - private int edgeIdx = 0; - private int edgeMinY = Integer.MAX_VALUE; - private int edgeMaxY = Integer.MIN_VALUE; - - private void addEdge(int x0, int y0, int x1, int y1) { - int newLen = edgeIdx + 5; - if (edges.length < newLen) { - int[] tmp = new int[Math.max(11*edges.length/10, newLen)]; - System.arraycopy(edges, 0, tmp, 0, edgeIdx); - this.edges = tmp; - } - - int orientation = 1; - if (y0 > y1) { - int tmp = y0; - y0 = y1; - y1 = tmp; - - orientation = -1; - } - - // Skip edges that don't cross a subsampled scanline - int eminY = ((y0 + HYSTEP) & YMASK); - int emaxY = ((y1 - HYSTEP) & YMASK); - if (eminY > emaxY) { - return; - } - - if (orientation == -1) { - int tmp = x0; - x0 = x1; - x1 = tmp; - } - - edges[edgeIdx++] = x0; - edges[edgeIdx++] = y0; - edges[edgeIdx++] = x1; - edges[edgeIdx++] = y1; - edges[edgeIdx++] = orientation; - - // Update Y bounds of primitive - if (y0 < edgeMinY) { - edgeMinY = y0; - } - if (y1 > edgeMaxY) { - edgeMaxY = y1; - } - } - - private void resetEdges() { - this.edgeIdx = 0; - this.edgeMinY = Integer.MAX_VALUE; - this.edgeMaxY = Integer.MIN_VALUE; - } - - // Crossing list data - - private int[] crossingIndices; - private int[] crossings; - private int crossingMinY; - private int crossingMaxY; - private int crossingMinX = Integer.MAX_VALUE; - private int crossingMaxX = Integer.MIN_VALUE; - private int crossingMaxXEntries; - private int numCrossings = 0; - private boolean crossingsSorted = false; - - private int crossingY; - private int crossingRowCount; - private int crossingRowOffset; - private int crossingRowIndex; - - private void setCrossingsExtents(int minY, int maxY, int maxXEntries) { - int yextent = maxY - minY + 1; - - // Grow indices array as needed - if (crossingIndices == null || crossingIndices.length < yextent) { - this.crossingIndices = - new int[Math.max(yextent, DEFAULT_INDICES_SIZE)]; - } - // Grow crossings array as needed - if (crossings == null || crossings.length < yextent*maxXEntries) { - this.crossings = new int[Math.max(yextent*maxXEntries, - DEFAULT_CROSSINGS_SIZE)]; - } - this.crossingMinY = minY; - this.crossingMaxY = maxY; - this.crossingMaxXEntries = maxXEntries; - resetCrossings(); - } - - private void resetCrossings() { - int yextent = crossingMaxY - crossingMinY + 1; - int start = 0; - for (int i = 0; i < yextent; i++) { - crossingIndices[i] = start; - start += crossingMaxXEntries; - } - crossingMinX = Integer.MAX_VALUE; - crossingMaxX = Integer.MIN_VALUE; - numCrossings = 0; - crossingsSorted = false; - } - - // Free sorting arrays if larger than maximum size - private void crossingListFinished() { - if (crossings != null && crossings.length > DEFAULT_CROSSINGS_SIZE) { - crossings = new int[DEFAULT_CROSSINGS_SIZE]; - } - if (crossingIndices != null && - crossingIndices.length > DEFAULT_INDICES_SIZE) - { - crossingIndices = new int[DEFAULT_INDICES_SIZE]; - } - } - - private void sortCrossings(int[] x, int off, int len) { - for (int i = off + 1; i < off + len; i++) { - int j = i; - int xj = x[j]; - int xjm1; - - while (j > off && (xjm1 = x[j - 1]) > xj) { - x[j] = xjm1; - x[j - 1] = xj; - j--; - } - } - } - - private void sortCrossings() { - int start = 0; - for (int i = 0; i <= crossingMaxY - crossingMinY; i++) { - sortCrossings(crossings, start, crossingIndices[i] - start); - start += crossingMaxXEntries; - } - } - - private void addCrossing(int y, int x, int orientation) { - if (x < crossingMinX) { - crossingMinX = x; - } - if (x > crossingMaxX) { - crossingMaxX = x; - } - - int index = crossingIndices[y - crossingMinY]++; - x <<= 1; - crossings[index] = (orientation == 1) ? (x | 0x1) : x; - - ++numCrossings; - } - - private void iterateCrossings() { - if (!crossingsSorted) { - sortCrossings(); - crossingsSorted = true; - } - crossingY = crossingMinY - 1; - crossingRowOffset = -crossingMaxXEntries; - } - - private boolean hasMoreCrossingRows() { - if (++crossingY <= crossingMaxY) { - crossingRowOffset += crossingMaxXEntries; - int y = crossingY - crossingMinY; - crossingRowCount = crossingIndices[y] - y*crossingMaxXEntries; - crossingRowIndex = 0; - return true; - } else { - return false; - } + java.util.Arrays.fill(alphaRow, (byte)0); } } diff --git a/jdk/src/share/classes/sun/java2d/pisces/Stroker.java b/jdk/src/share/classes/sun/java2d/pisces/Stroker.java index e17283a3bdc..574c460fea9 100644 --- a/jdk/src/share/classes/sun/java2d/pisces/Stroker.java +++ b/jdk/src/share/classes/sun/java2d/pisces/Stroker.java @@ -25,7 +25,7 @@ package sun.java2d.pisces; -public class Stroker extends LineSink { +public class Stroker implements LineSink { private static final int MOVE_TO = 0; private static final int LINE_TO = 1; @@ -61,19 +61,15 @@ public class Stroker extends LineSink { */ public static final int CAP_SQUARE = 2; - LineSink output; + private final LineSink output; - int lineWidth; - int capStyle; - int joinStyle; - int miterLimit; + private final int capStyle; + private final int joinStyle; - Transform4 transform; - int m00, m01; - int m10, m11; + private final float m00, m01, m10, m11, det; - int lineWidth2; - long scaledLineWidth2; + private final float lineWidth2; + private final float scaledLineWidth2; // For any pen offset (pen_dx, pen_dy) that does not depend on // the line orientation, the pen should be transformed so that: @@ -88,143 +84,86 @@ public class Stroker extends LineSink { // // pen_dx'(r, theta) = r*(m00*cos(theta) + m01*sin(theta)) // pen_dy'(r, theta) = r*(m10*cos(theta) + m11*sin(theta)) - int numPenSegments; - int[] pen_dx; - int[] pen_dy; - boolean[] penIncluded; - int[] join; + private int numPenSegments; + private final float[] pen_dx; + private final float[] pen_dy; + private boolean[] penIncluded; + private final float[] join; - int[] offset = new int[2]; - int[] reverse = new int[100]; - int[] miter = new int[2]; - long miterLimitSq; + private final float[] offset = new float[2]; + private float[] reverse = new float[100]; + private final float[] miter = new float[2]; + private final float miterLimitSq; - int prev; - int rindex; - boolean started; - boolean lineToOrigin; - boolean joinToOrigin; + private int prev; + private int rindex; + private boolean started; + private boolean lineToOrigin; + private boolean joinToOrigin; - int sx0, sy0, sx1, sy1, x0, y0, x1, y1; - int mx0, my0, mx1, my1, omx, omy; - int lx0, ly0, lx1, ly1, lx0p, ly0p, px0, py0; + private float sx0, sy0, sx1, sy1, x0, y0, px0, py0; + private float mx0, my0, omx, omy; - double m00_2_m01_2; - double m10_2_m11_2; - double m00_m10_m01_m11; - - /** - * Empty constructor. setOutput and - * setParameters must be called prior to calling any - * other methods. - */ - public Stroker() {} + private float m00_2_m01_2; + private float m10_2_m11_2; + private float m00_m10_m01_m11; /** * Constructs a Stroker. * * @param output an output LineSink. - * @param lineWidth the desired line width in pixels, in S15.16 - * format. + * @param lineWidth the desired line width in pixels * @param capStyle the desired end cap style, one of * CAP_BUTT, CAP_ROUND or * CAP_SQUARE. * @param joinStyle the desired line join style, one of * JOIN_MITER, JOIN_ROUND or * JOIN_BEVEL. - * @param miterLimit the desired miter limit, in S15.16 format. + * @param miterLimit the desired miter limit * @param transform a Transform4 object indicating * the transform that has been previously applied to all incoming * coordinates. This is required in order to produce consistently * shaped end caps and joins. */ public Stroker(LineSink output, - int lineWidth, + float lineWidth, int capStyle, int joinStyle, - int miterLimit, - Transform4 transform) { - setOutput(output); - setParameters(lineWidth, capStyle, joinStyle, miterLimit, transform); - } - - /** - * Sets the output LineSink of this - * Stroker. - * - * @param output an output LineSink. - */ - public void setOutput(LineSink output) { + float miterLimit, + float m00, float m01, float m10, float m11) { this.output = output; - } - /** - * Sets the parameters of this Stroker. - * @param lineWidth the desired line width in pixels, in S15.16 - * format. - * @param capStyle the desired end cap style, one of - * CAP_BUTT, CAP_ROUND or - * CAP_SQUARE. - * @param joinStyle the desired line join style, one of - * JOIN_MITER, JOIN_ROUND or - * JOIN_BEVEL. - * @param miterLimit the desired miter limit, in S15.16 format. - * @param transform a Transform4 object indicating - * the transform that has been previously applied to all incoming - * coordinates. This is required in order to produce consistently - * shaped end caps and joins. - */ - public void setParameters(int lineWidth, - int capStyle, - int joinStyle, - int miterLimit, - Transform4 transform) { - this.lineWidth = lineWidth; - this.lineWidth2 = lineWidth >> 1; - this.scaledLineWidth2 = ((long)transform.m00*lineWidth2) >> 16; + this.lineWidth2 = lineWidth / 2; + this.scaledLineWidth2 = m00 * lineWidth2; this.capStyle = capStyle; this.joinStyle = joinStyle; - this.miterLimit = miterLimit; - this.transform = transform; - this.m00 = transform.m00; - this.m01 = transform.m01; - this.m10 = transform.m10; - this.m11 = transform.m11; + m00_2_m01_2 = m00*m00 + m01*m01; + m10_2_m11_2 = m10*m10 + m11*m11; + m00_m10_m01_m11 = m00*m10 + m01*m11; - this.m00_2_m01_2 = (double)m00*m00 + (double)m01*m01; - this.m10_2_m11_2 = (double)m10*m10 + (double)m11*m11; - this.m00_m10_m01_m11 = (double)m00*m10 + (double)m01*m11; + this.m00 = m00; + this.m01 = m01; + this.m10 = m10; + this.m11 = m11; + det = m00*m11 - m01*m10; - double dm00 = m00/65536.0; - double dm01 = m01/65536.0; - double dm10 = m10/65536.0; - double dm11 = m11/65536.0; - double determinant = dm00*dm11 - dm01*dm10; + float limit = miterLimit * lineWidth2 * det; + this.miterLimitSq = limit*limit; - if (joinStyle == JOIN_MITER) { - double limit = - (miterLimit/65536.0)*(lineWidth2/65536.0)*determinant; - double limitSq = limit*limit; - this.miterLimitSq = (long)(limitSq*65536.0*65536.0); - } - - this.numPenSegments = (int)(3.14159f*lineWidth/65536.0f); - if (pen_dx == null || pen_dx.length < numPenSegments) { - this.pen_dx = new int[numPenSegments]; - this.pen_dy = new int[numPenSegments]; - this.penIncluded = new boolean[numPenSegments]; - this.join = new int[2*numPenSegments]; - } + this.numPenSegments = (int)(3.14159f * lineWidth); + this.pen_dx = new float[numPenSegments]; + this.pen_dy = new float[numPenSegments]; + this.penIncluded = new boolean[numPenSegments]; + this.join = new float[2*numPenSegments]; for (int i = 0; i < numPenSegments; i++) { - double r = lineWidth/2.0; - double theta = (double)i*2.0*Math.PI/numPenSegments; + double theta = (i * 2.0 * Math.PI)/numPenSegments; double cos = Math.cos(theta); double sin = Math.sin(theta); - pen_dx[i] = (int)(r*(dm00*cos + dm01*sin)); - pen_dy[i] = (int)(r*(dm10*cos + dm11*sin)); + pen_dx[i] = (float)(lineWidth2 * (m00*cos + m01*sin)); + pen_dy[i] = (float)(lineWidth2 * (m10*cos + m11*sin)); } prev = CLOSE; @@ -233,32 +172,31 @@ public class Stroker extends LineSink { lineToOrigin = false; } - private void computeOffset(int x0, int y0, int x1, int y1, int[] m) { - long lx = (long)x1 - (long)x0; - long ly = (long)y1 - (long)y0; + private void computeOffset(float x0, float y0, + float x1, float y1, float[] m) { + float lx = x1 - x0; + float ly = y1 - y0; - int dx, dy; + float dx, dy; if (m00 > 0 && m00 == m11 && m01 == 0 & m10 == 0) { - long ilen = PiscesMath.hypot(lx, ly); + float ilen = (float)Math.hypot(lx, ly); if (ilen == 0) { dx = dy = 0; } else { - dx = (int)( (ly*scaledLineWidth2)/ilen); - dy = (int)(-(lx*scaledLineWidth2)/ilen); + dx = (ly * scaledLineWidth2)/ilen; + dy = -(lx * scaledLineWidth2)/ilen; } } else { - double dlx = x1 - x0; - double dly = y1 - y0; - double det = (double)m00*m11 - (double)m01*m10; int sdet = (det > 0) ? 1 : -1; - double a = dly*m00 - dlx*m10; - double b = dly*m01 - dlx*m11; - double dh = PiscesMath.hypot(a, b); - double div = sdet*lineWidth2/(65536.0*dh); - double ddx = dly*m00_2_m01_2 - dlx*m00_m10_m01_m11; - double ddy = dly*m00_m10_m01_m11 - dlx*m10_2_m11_2; - dx = (int)(ddx*div); - dy = (int)(ddy*div); + float a = ly * m00 - lx * m10; + float b = ly * m01 - lx * m11; + float dh = (float)Math.hypot(a, b); + float div = sdet * lineWidth2/dh; + + float ddx = ly * m00_2_m01_2 - lx * m00_m10_m01_m11; + float ddy = ly * m00_m10_m01_m11 - lx * m10_2_m11_2; + dx = ddx*div; + dy = ddy*div; } m[0] = dx; @@ -267,58 +205,43 @@ public class Stroker extends LineSink { private void ensureCapacity(int newrindex) { if (reverse.length < newrindex) { - int[] tmp = new int[Math.max(newrindex, 6*reverse.length/5)]; - System.arraycopy(reverse, 0, tmp, 0, rindex); - this.reverse = tmp; + reverse = java.util.Arrays.copyOf(reverse, 6*reverse.length/5); } } - private boolean isCCW(int x0, int y0, - int x1, int y1, - int x2, int y2) { - int dx0 = x1 - x0; - int dy0 = y1 - y0; - int dx1 = x2 - x1; - int dy1 = y2 - y1; - return (long)dx0*dy1 < (long)dy0*dx1; + private boolean isCCW(float x0, float y0, + float x1, float y1, + float x2, float y2) { + return (x1 - x0) * (y2 - y1) < (y1 - y0) * (x2 - x1); } - private boolean side(int x, int y, int x0, int y0, int x1, int y1) { - long lx = x; - long ly = y; - long lx0 = x0; - long ly0 = y0; - long lx1 = x1; - long ly1 = y1; - - return (ly0 - ly1)*lx + (lx1 - lx0)*ly + (lx0*ly1 - lx1*ly0) > 0; + private boolean side(float x, float y, + float x0, float y0, + float x1, float y1) { + return (y0 - y1)*x + (x1 - x0)*y + (x0*y1 - x1*y0) > 0; } - private int computeRoundJoin(int cx, int cy, - int xa, int ya, - int xb, int yb, + private int computeRoundJoin(float cx, float cy, + float xa, float ya, + float xb, float yb, int side, boolean flip, - int[] join) { - int px, py; + float[] join) { + float px, py; int ncoords = 0; boolean centerSide; if (side == 0) { centerSide = side(cx, cy, xa, ya, xb, yb); } else { - centerSide = (side == 1) ? true : false; + centerSide = (side == 1); } for (int i = 0; i < numPenSegments; i++) { px = cx + pen_dx[i]; py = cy + pen_dy[i]; boolean penSide = side(px, py, xa, ya, xb, yb); - if (penSide != centerSide) { - penIncluded[i] = true; - } else { - penIncluded[i] = false; - } + penIncluded[i] = (penSide != centerSide); } int start = -1, end = -1; @@ -338,10 +261,10 @@ public class Stroker extends LineSink { } if (start != -1 && end != -1) { - long dxa = cx + pen_dx[start] - xa; - long dya = cy + pen_dy[start] - ya; - long dxb = cx + pen_dx[start] - xb; - long dyb = cy + pen_dy[start] - yb; + float dxa = cx + pen_dx[start] - xa; + float dya = cy + pen_dy[start] - ya; + float dxb = cx + pen_dx[start] - xb; + float dyb = cy + pen_dy[start] - yb; boolean rev = (dxa*dxa + dya*dya > dxb*dxb + dyb*dyb); int i = rev ? end : start; @@ -362,22 +285,25 @@ public class Stroker extends LineSink { return ncoords/2; } - private static final long ROUND_JOIN_THRESHOLD = 1000L; - private static final long ROUND_JOIN_INTERNAL_THRESHOLD = 1000000000L; + // pisces used to use fixed point arithmetic with 16 decimal digits. I + // didn't want to change the values of the constants below when I converted + // it to floating point, so that's why the divisions by 2^16 are there. + private static final float ROUND_JOIN_THRESHOLD = 1000/65536f; + private static final float ROUND_JOIN_INTERNAL_THRESHOLD = 1000000000/65536f; - private void drawRoundJoin(int x, int y, - int omx, int omy, int mx, int my, + private void drawRoundJoin(float x, float y, + float omx, float omy, float mx, float my, int side, boolean flip, boolean rev, - long threshold) { + float threshold) { if ((omx == 0 && omy == 0) || (mx == 0 && my == 0)) { return; } - long domx = (long)omx - mx; - long domy = (long)omy - my; - long len = domx*domx + domy*domy; + float domx = omx - mx; + float domy = omy - my; + float len = domx*domx + domy*domy; if (len < threshold) { return; } @@ -389,10 +315,10 @@ public class Stroker extends LineSink { my = -my; } - int bx0 = x + omx; - int by0 = y + omy; - int bx1 = x + mx; - int by1 = y + my; + float bx0 = x + omx; + float by0 = y + omy; + float bx1 = x + mx; + float by1 = y + my; int npoints = computeRoundJoin(x, y, bx0, by0, bx1, by1, side, flip, @@ -404,40 +330,30 @@ public class Stroker extends LineSink { // Return the intersection point of the lines (ix0, iy0) -> (ix1, iy1) // and (ix0p, iy0p) -> (ix1p, iy1p) in m[0] and m[1] - private void computeMiter(int ix0, int iy0, int ix1, int iy1, - int ix0p, int iy0p, int ix1p, int iy1p, - int[] m) { - long x0 = ix0; - long y0 = iy0; - long x1 = ix1; - long y1 = iy1; + private void computeMiter(float x0, float y0, float x1, float y1, + float x0p, float y0p, float x1p, float y1p, + float[] m) { + float x10 = x1 - x0; + float y10 = y1 - y0; + float x10p = x1p - x0p; + float y10p = y1p - y0p; - long x0p = ix0p; - long y0p = iy0p; - long x1p = ix1p; - long y1p = iy1p; - - long x10 = x1 - x0; - long y10 = y1 - y0; - long x10p = x1p - x0p; - long y10p = y1p - y0p; - - long den = (x10*y10p - x10p*y10) >> 16; + float den = x10*y10p - x10p*y10; if (den == 0) { - m[0] = ix0; - m[1] = iy0; + m[0] = x0; + m[1] = y0; return; } - long t = (x1p*(y0 - y0p) - x0*y10p + x0p*(y1p - y0)) >> 16; - m[0] = (int)(x0 + (t*x10)/den); - m[1] = (int)(y0 + (t*y10)/den); + float t = x1p*(y0 - y0p) - x0*y10p + x0p*(y1p - y0); + m[0] = x0 + (t*x10)/den; + m[1] = y0 + (t*y10)/den; } - private void drawMiter(int px0, int py0, - int x0, int y0, - int x1, int y1, - int omx, int omy, int mx, int my, + private void drawMiter(float px0, float py0, + float x0, float y0, + float x1, float y1, + float omx, float omy, float mx, float my, boolean rev) { if (mx == omx && my == omy) { return; @@ -461,11 +377,11 @@ public class Stroker extends LineSink { miter); // Compute miter length in untransformed coordinates - long dx = (long)miter[0] - x0; - long dy = (long)miter[1] - y0; - long a = (dy*m00 - dx*m10) >> 16; - long b = (dy*m01 - dx*m11) >> 16; - long lenSq = a*a + b*b; + float dx = miter[0] - x0; + float dy = miter[1] - y0; + float a = dy*m00 - dx*m10; + float b = dy*m01 - dx*m11; + float lenSq = a*a + b*b; if (lenSq < miterLimitSq) { emitLineTo(miter[0], miter[1], rev); @@ -473,7 +389,7 @@ public class Stroker extends LineSink { } - public void moveTo(int x0, int y0) { + public void moveTo(float x0, float y0) { // System.out.println("Stroker.moveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")"); if (lineToOrigin) { @@ -501,7 +417,7 @@ public class Stroker extends LineSink { this.joinSegment = true; } - public void lineTo(int x1, int y1) { + public void lineTo(float x1, float y1) { // System.out.println("Stroker.lineTo(" + x1/65536.0 + ", " + y1/65536.0 + ")"); if (lineToOrigin) { @@ -526,10 +442,10 @@ public class Stroker extends LineSink { joinSegment = false; } - private void lineToImpl(int x1, int y1, boolean joinSegment) { + private void lineToImpl(float x1, float y1, boolean joinSegment) { computeOffset(x0, y0, x1, y1, offset); - int mx = offset[0]; - int my = offset[1]; + float mx = offset[0]; + float my = offset[1]; if (!started) { emitMoveTo(x0 + mx, y0 + my); @@ -567,10 +483,6 @@ public class Stroker extends LineSink { emitLineTo(x0 - mx, y0 - my, true); emitLineTo(x1 - mx, y1 - my, true); - lx0 = x1 + mx; ly0 = y1 + my; - lx0p = x1 - mx; ly0p = y1 - my; - lx1 = x1; ly1 = y1; - this.omx = mx; this.omy = my; this.px0 = x0; @@ -594,8 +506,8 @@ public class Stroker extends LineSink { } computeOffset(x0, y0, sx0, sy0, offset); - int mx = offset[0]; - int my = offset[1]; + float mx = offset[0]; + float my = offset[1]; // Draw penultimate join boolean ccw = isCCW(px0, py0, x0, y0, sx0, sy0); @@ -678,12 +590,10 @@ public class Stroker extends LineSink { this.prev = MOVE_TO; } - long lineLength(long ldx, long ldy) { - long ldet = ((long)m00*m11 - (long)m01*m10) >> 16; - long la = ((long)ldy*m00 - (long)ldx*m10)/ldet; - long lb = ((long)ldy*m01 - (long)ldx*m11)/ldet; - long llen = (int)PiscesMath.hypot(la, lb); - return llen; + double userSpaceLineLength(double dx, double dy) { + double a = (dy*m00 - dx*m10)/det; + double b = (dy*m01 - dx*m11)/det; + return Math.hypot(a, b); } private void finish() { @@ -692,13 +602,13 @@ public class Stroker extends LineSink { omx, omy, -omx, -omy, 1, false, false, ROUND_JOIN_THRESHOLD); } else if (capStyle == CAP_SQUARE) { - long ldx = (long)(px0 - x0); - long ldy = (long)(py0 - y0); - long llen = lineLength(ldx, ldy); - long s = (long)lineWidth2*65536/llen; + float dx = px0 - x0; + float dy = py0 - y0; + float len = (float)userSpaceLineLength(dx, dy); + float s = lineWidth2/len; - int capx = x0 - (int)(ldx*s >> 16); - int capy = y0 - (int)(ldy*s >> 16); + float capx = x0 - dx*s; + float capy = y0 - dy*s; emitLineTo(capx + omx, capy + omy); emitLineTo(capx - omx, capy - omy); @@ -714,13 +624,13 @@ public class Stroker extends LineSink { -mx0, -my0, mx0, my0, 1, false, false, ROUND_JOIN_THRESHOLD); } else if (capStyle == CAP_SQUARE) { - long ldx = (long)(sx1 - sx0); - long ldy = (long)(sy1 - sy0); - long llen = lineLength(ldx, ldy); - long s = (long)lineWidth2*65536/llen; + float dx = sx1 - sx0; + float dy = sy1 - sy0; + float len = (float)userSpaceLineLength(dx, dy); + float s = lineWidth2/len; - int capx = sx0 - (int)(ldx*s >> 16); - int capy = sy0 - (int)(ldy*s >> 16); + float capx = sx0 - dx*s; + float capy = sy0 - dy*s; emitLineTo(capx - mx0, capy - my0); emitLineTo(capx + mx0, capy + my0); @@ -730,17 +640,17 @@ public class Stroker extends LineSink { this.joinSegment = false; } - private void emitMoveTo(int x0, int y0) { + private void emitMoveTo(float x0, float y0) { // System.out.println("Stroker.emitMoveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")"); output.moveTo(x0, y0); } - private void emitLineTo(int x1, int y1) { + private void emitLineTo(float x1, float y1) { // System.out.println("Stroker.emitLineTo(" + x0/65536.0 + ", " + y0/65536.0 + ")"); output.lineTo(x1, y1); } - private void emitLineTo(int x1, int y1, boolean rev) { + private void emitLineTo(float x1, float y1, boolean rev) { if (rev) { ensureCapacity(rindex + 2); reverse[rindex++] = x1; @@ -755,3 +665,4 @@ public class Stroker extends LineSink { output.close(); } } + diff --git a/jdk/src/share/classes/sun/java2d/pisces/Transform4.java b/jdk/src/share/classes/sun/java2d/pisces/Transform4.java deleted file mode 100644 index bd79b762dba..00000000000 --- a/jdk/src/share/classes/sun/java2d/pisces/Transform4.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.java2d.pisces; - -public class Transform4 { - - public int m00, m01, m10, m11; -// double det; // det*65536 - - public Transform4() { - this(1 << 16, 0, 0, 1 << 16); - } - - public Transform4(int m00, int m01, - int m10, int m11) { - this.m00 = m00; - this.m01 = m01; - this.m10 = m10; - this.m11 = m11; - -// this.det = (double)m00*m11 - (double)m01*m10; - } - -// public Transform4 createInverse() { -// double dm00 = m00/65536.0; -// double dm01 = m01/65536.0; -// double dm10 = m10/65536.0; -// double dm11 = m11/65536.0; - -// double invdet = 65536.0/(dm00*dm11 - dm01*dm10); - -// int im00 = (int)( dm11*invdet); -// int im01 = (int)(-dm01*invdet); -// int im10 = (int)(-dm10*invdet); -// int im11 = (int)( dm00*invdet); - -// return new Transform4(im00, im01, im10, im11); -// } - -// public void transform(int[] point) { -// } - -// /** -// * Returns the length of the line segment obtained by inverse -// * transforming the points (x0, y0) and (x1, -// * y1). -// */ -// public int getTransformedLength(int x0, int x1, int y0, int y1) { -// int lx = x1 - x0; -// int ly = y1 - y0; - -// double a = (double)m00*ly - (double)m10*lx; -// double b = (double)m01*ly - (double)m11*lx; -// double len = PiscesMath.sqrt((a*a + b*b)/(det*det)); -// return (int)(len*65536.0); -// } - -// public int getType() { -// } - -} diff --git a/jdk/src/share/classes/sun/net/www/protocol/file/FileURLConnection.java b/jdk/src/share/classes/sun/net/www/protocol/file/FileURLConnection.java index 3298546e7b5..787282b823d 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/file/FileURLConnection.java +++ b/jdk/src/share/classes/sun/net/www/protocol/file/FileURLConnection.java @@ -59,7 +59,7 @@ public class FileURLConnection extends URLConnection { String filename; boolean isDirectory = false; boolean exists = false; - List files; + List files; long length = -1; long lastModified = 0; @@ -81,7 +81,10 @@ public class FileURLConnection extends URLConnection { filename = file.toString(); isDirectory = file.isDirectory(); if (isDirectory) { - files = (List) Arrays.asList(file.list()); + String[] fileList = file.list(); + if (fileList == null) + throw new FileNotFoundException(filename + " exists, but is not accessible"); + files = Arrays.asList(fileList); } else { is = new BufferedInputStream(new FileInputStream(filename)); @@ -197,7 +200,7 @@ public class FileURLConnection extends URLConnection { Collections.sort(files, Collator.getInstance()); for (int i = 0 ; i < files.size() ; i++) { - String fileName = (String)files.get(i); + String fileName = files.get(i); buf.append(fileName); buf.append("\n"); } diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 713c7d85c21..e888abe26e8 100644 --- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -1768,6 +1768,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection { // Not really necessary for a tunnel, but can't hurt requests.setIfNotSet("Accept", acceptString); + if (http.getHttpKeepAliveSet()) { + requests.setIfNotSet("Proxy-Connection", "keep-alive"); + } + setPreemptiveProxyAuthentication(requests); /* Log the CONNECT request */ diff --git a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java index 41b37c9e960..1d7d6758d8e 100644 --- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -536,9 +536,11 @@ class DatagramChannelImpl } } - private long read0(ByteBuffer[] bufs) throws IOException { - if (bufs == null) - throw new NullPointerException(); + public long read(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) + throw new IndexOutOfBoundsException(); synchronized (readLock) { synchronized (stateLock) { ensureOpen(); @@ -552,7 +554,7 @@ class DatagramChannelImpl return 0; readerThread = NativeThread.current(); do { - n = IOUtil.read(fd, bufs, nd); + n = IOUtil.read(fd, dsts, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -563,15 +565,6 @@ class DatagramChannelImpl } } - public long read(ByteBuffer[] dsts, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return read0(Util.subsequence(dsts, offset, length)); - } - public int write(ByteBuffer buf) throws IOException { if (buf == null) throw new NullPointerException(); @@ -599,9 +592,11 @@ class DatagramChannelImpl } } - private long write0(ByteBuffer[] bufs) throws IOException { - if (bufs == null) - throw new NullPointerException(); + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) + throw new IndexOutOfBoundsException(); synchronized (writeLock) { synchronized (stateLock) { ensureOpen(); @@ -615,7 +610,7 @@ class DatagramChannelImpl return 0; writerThread = NativeThread.current(); do { - n = IOUtil.write(fd, bufs, nd); + n = IOUtil.write(fd, srcs, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -626,15 +621,6 @@ class DatagramChannelImpl } } - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return write0(Util.subsequence(srcs, offset, length)); - } - protected void implConfigureBlocking(boolean block) throws IOException { IOUtil.configureBlocking(fd, block); } diff --git a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java index 1bbd5e025ef..9a52fa4555c 100644 --- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java @@ -143,7 +143,11 @@ public class FileChannelImpl } } - private long read0(ByteBuffer[] dsts) throws IOException { + public long read(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) + throw new IndexOutOfBoundsException(); ensureOpen(); if (!readable) throw new NonReadableChannelException(); @@ -156,7 +160,7 @@ public class FileChannelImpl if (!isOpen()) return 0; do { - n = IOUtil.read(fd, dsts, nd); + n = IOUtil.read(fd, dsts, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -167,15 +171,6 @@ public class FileChannelImpl } } - public long read(ByteBuffer[] dsts, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return read0(Util.subsequence(dsts, offset, length)); - } - public int write(ByteBuffer src) throws IOException { ensureOpen(); if (!writable) @@ -200,7 +195,11 @@ public class FileChannelImpl } } - private long write0(ByteBuffer[] srcs) throws IOException { + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) + throw new IndexOutOfBoundsException(); ensureOpen(); if (!writable) throw new NonWritableChannelException(); @@ -213,7 +212,7 @@ public class FileChannelImpl if (!isOpen()) return 0; do { - n = IOUtil.write(fd, srcs, nd); + n = IOUtil.write(fd, srcs, offset, length, nd); } while ((n == IOStatus.INTERRUPTED) && isOpen()); return IOStatus.normalize(n); } finally { @@ -224,16 +223,6 @@ public class FileChannelImpl } } - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return write0(Util.subsequence(srcs, offset, length)); - } - - // -- Other operations -- public long position() throws IOException { @@ -440,24 +429,45 @@ public class FileChannelImpl } } - private long transferToTrustedChannel(long position, int icount, + // Maximum size to map when using a mapped buffer + private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L; + + private long transferToTrustedChannel(long position, long count, WritableByteChannel target) throws IOException { - if ( !((target instanceof FileChannelImpl) - || (target instanceof SelChImpl))) + boolean isSelChImpl = (target instanceof SelChImpl); + if (!((target instanceof FileChannelImpl) || isSelChImpl)) return IOStatus.UNSUPPORTED; // Trusted target: Use a mapped buffer - MappedByteBuffer dbb = null; - try { - dbb = map(MapMode.READ_ONLY, position, icount); - // ## Bug: Closing this channel will not terminate the write - return target.write(dbb); - } finally { - if (dbb != null) - unmap(dbb); + long remaining = count; + while (remaining > 0L) { + long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); + try { + MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size); + try { + // ## Bug: Closing this channel will not terminate the write + int n = target.write(dbb); + assert n >= 0; + remaining -= n; + if (isSelChImpl) { + // one attempt to write to selectable channel + break; + } + assert n > 0; + position += n; + } finally { + unmap(dbb); + } + } catch (IOException ioe) { + // Only throw exception if no bytes have been written + if (remaining == count) + throw ioe; + break; + } } + return count - remaining; } private long transferToArbitraryChannel(long position, int icount, @@ -535,20 +545,34 @@ public class FileChannelImpl long position, long count) throws IOException { - // Note we could loop here to accumulate more at once synchronized (src.positionLock) { - long p = src.position(); - int icount = (int)Math.min(Math.min(count, Integer.MAX_VALUE), - src.size() - p); - // ## Bug: Closing this channel will not terminate the write - MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, icount); - try { - long n = write(bb, position); - src.position(p + n); - return n; - } finally { - unmap(bb); + long pos = src.position(); + long max = Math.min(count, src.size() - pos); + + long remaining = max; + long p = pos; + while (remaining > 0L) { + long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); + // ## Bug: Closing this channel will not terminate the write + MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size); + try { + long n = write(bb, position); + assert n > 0; + p += n; + position += n; + remaining -= n; + } catch (IOException ioe) { + // Only throw exception if no bytes have been written + if (remaining == max) + throw ioe; + break; + } finally { + unmap(bb); + } } + long nwritten = max - remaining; + src.position(pos + nwritten); + return nwritten; } } diff --git a/jdk/src/share/classes/sun/nio/ch/IOUtil.java b/jdk/src/share/classes/sun/nio/ch/IOUtil.java index 5b1dd95cddc..86acff63566 100644 --- a/jdk/src/share/classes/sun/nio/ch/IOUtil.java +++ b/jdk/src/share/classes/sun/nio/ch/IOUtil.java @@ -38,34 +38,6 @@ class IOUtil { private IOUtil() { } // No instantiation - /* - * Returns the index of first buffer in bufs with remaining, - * or -1 if there is nothing left - */ - private static int remaining(ByteBuffer[] bufs) { - int numBufs = bufs.length; - for (int i=0; i 0) - bufs = skipBufs(bufs, nextWithRemaining); + return write(fd, bufs, 0, bufs.length, nd); + } - int numBufs = bufs.length; + static long write(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, + NativeDispatcher nd) + throws IOException + { + IOVecWrapper vec = IOVecWrapper.get(length); - // Create shadow to ensure DirectByteBuffers are used - ByteBuffer[] shadow = new ByteBuffer[numBufs]; + boolean completed = false; + int iov_len = 0; try { - for (int i=0; i 0) { + vec.setBuffer(iov_len, buf, pos, rem); + + // allocate shadow buffer to ensure I/O is done with direct buffer + if (!(buf instanceof DirectBuffer)) { + ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem); + shadow.put(buf); + shadow.flip(); + vec.setShadow(iov_len, shadow); + buf.position(pos); // temporarily restore position in user buffer + buf = shadow; + pos = shadow.position(); + } + + vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos); + vec.putLen(iov_len, rem); + iov_len++; } } + if (iov_len == 0) + return 0L; - IOVecWrapper vec = null; - long bytesWritten = 0; - try { - // Create a native iovec array - vec= new IOVecWrapper(numBufs); - - // Fill in the iovec array with appropriate data - for (int i=0; i= len) { - bytesWritten -= len; - int newPosition = pos + len; - nextBuffer.position(newPosition); - } else { // Buffers not completely filled - if (bytesWritten > 0) { - assert(pos + bytesWritten < (long)Integer.MAX_VALUE); - int newPosition = (int)(pos + bytesWritten); - nextBuffer.position(newPosition); - } - break; + long left = bytesWritten; + for (int j=0; j 0) { + ByteBuffer buf = vec.getBuffer(j); + int pos = vec.getPosition(j); + int rem = vec.getRemaining(j); + int n = (left > rem) ? rem : (int)left; + buf.position(pos + n); + left -= n; } + // return shadow buffers to buffer pool + ByteBuffer shadow = vec.getShadow(j); + if (shadow != null) + Util.offerLastTemporaryDirectBuffer(shadow); + vec.clearRefs(j); } - return returnVal; + + completed = true; + return bytesWritten; + } finally { - // return any substituted buffers to cache - for (int i=0; i 0) - bufs = skipBufs(bufs, nextWithRemaining); + return read(fd, bufs, 0, bufs.length, nd); + } - int numBufs = bufs.length; + static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length, + NativeDispatcher nd) + throws IOException + { + IOVecWrapper vec = IOVecWrapper.get(length); - // Read into the shadow to ensure DirectByteBuffers are used - ByteBuffer[] shadow = new ByteBuffer[numBufs]; - boolean usingSlowBuffers = false; + boolean completed = false; + int iov_len = 0; try { - for (int i=0; i 0) { + vec.setBuffer(iov_len, buf, pos, rem); + + // allocate shadow buffer to ensure I/O is done with direct buffer + if (!(buf instanceof DirectBuffer)) { + ByteBuffer shadow = Util.getTemporaryDirectBuffer(rem); + vec.setShadow(iov_len, shadow); + buf = shadow; + pos = shadow.position(); + } + + vec.putBase(iov_len, ((DirectBuffer)buf).address() + pos); + vec.putLen(iov_len, rem); + iov_len++; } } + if (iov_len == 0) + return 0L; - IOVecWrapper vec = null; - long bytesRead = 0; - try { - // Create a native iovec array - vec = new IOVecWrapper(numBufs); - - // Fill in the iovec array with appropriate data - for (int i=0; i= len) { - bytesRead -= len; - int newPosition = pos + len; - nextBuffer.position(newPosition); - } else { // Buffers not completely filled - if (bytesRead > 0) { - assert(pos + bytesRead < (long)Integer.MAX_VALUE); - int newPosition = (int)(pos + bytesRead); - nextBuffer.position(newPosition); + long left = bytesRead; + for (int j=0; j 0) { + ByteBuffer buf = vec.getBuffer(j); + int rem = vec.getRemaining(j); + int n = (left > rem) ? rem : (int)left; + if (shadow == null) { + int pos = vec.getPosition(j); + buf.position(pos + n); + } else { + shadow.limit(shadow.position() + n); + buf.put(shadow); } - break; + left -= n; } + if (shadow != null) + Util.offerLastTemporaryDirectBuffer(shadow); + vec.clearRefs(j); } - // Put results from shadow into the slow buffers - if (usingSlowBuffers) { - for (int i=0; i cached = + new ThreadLocal(); + + private IOVecWrapper(int size) { + this.size = size; + this.buf = new ByteBuffer[size]; + this.position = new int[size]; + this.remaining = new int[size]; + this.shadow = new ByteBuffer[size]; + this.vecArray = new AllocatedNativeObject(size * SIZE_IOVEC, false); + this.address = vecArray.address(); + } + + static IOVecWrapper get(int size) { + IOVecWrapper wrapper = cached.get(); + if (wrapper != null && wrapper.size < size) { + // not big enough; eagerly release memory + wrapper.vecArray.free(); + wrapper = null; + } + if (wrapper == null) { + wrapper = new IOVecWrapper(size); + Cleaner.create(wrapper, new Deallocator(wrapper.vecArray)); + cached.set(wrapper); + } + return wrapper; + } + + void setBuffer(int i, ByteBuffer buf, int pos, int rem) { + this.buf[i] = buf; + this.position[i] = pos; + this.remaining[i] = rem; + } + + void setShadow(int i, ByteBuffer buf) { + shadow[i] = buf; + } + + ByteBuffer getBuffer(int i) { + return buf[i]; + } + + int getPosition(int i) { + return position[i]; + } + + int getRemaining(int i) { + return remaining[i]; + } + + ByteBuffer getShadow(int i) { + return shadow[i]; + } + + void clearRefs(int i) { + buf[i] = null; + shadow[i] = null; } void putBase(int i, long base) { @@ -78,10 +154,6 @@ class IOVecWrapper { vecArray.putLong(offset, len); } - void free() { - vecArray.free(); - } - static { addressSize = Util.unsafe().addressSize(); LEN_OFFSET = addressSize; diff --git a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java index ee84a0e626c..7d42d7d0096 100644 --- a/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/jdk/src/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -385,9 +385,11 @@ class SocketChannelImpl } } - private long read0(ByteBuffer[] bufs) throws IOException { - if (bufs == null) - throw new NullPointerException(); + public long read(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) + throw new IndexOutOfBoundsException(); synchronized (readLock) { if (!ensureReadOpen()) return -1; @@ -401,7 +403,7 @@ class SocketChannelImpl } for (;;) { - n = IOUtil.read(fd, bufs, nd); + n = IOUtil.read(fd, dsts, offset, length, nd); if ((n == IOStatus.INTERRUPTED) && isOpen()) continue; return IOStatus.normalize(n); @@ -418,15 +420,6 @@ class SocketChannelImpl } } - public long read(ByteBuffer[] dsts, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return read0(Util.subsequence(dsts, offset, length)); - } - public int write(ByteBuffer buf) throws IOException { if (buf == null) throw new NullPointerException(); @@ -458,9 +451,11 @@ class SocketChannelImpl } } - public long write0(ByteBuffer[] bufs) throws IOException { - if (bufs == null) - throw new NullPointerException(); + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) + throw new IndexOutOfBoundsException(); synchronized (writeLock) { ensureWriteOpen(); long n = 0; @@ -472,7 +467,7 @@ class SocketChannelImpl writerThread = NativeThread.current(); } for (;;) { - n = IOUtil.write(fd, bufs, nd); + n = IOUtil.write(fd, srcs, offset, length, nd); if ((n == IOStatus.INTERRUPTED) && isOpen()) continue; return IOStatus.normalize(n); @@ -489,15 +484,6 @@ class SocketChannelImpl } } - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) - throw new IndexOutOfBoundsException(); - // ## Fix IOUtil.write so that we can avoid this array copy - return write0(Util.subsequence(srcs, offset, length)); - } - // package-private int sendOutOfBandData(byte b) throws IOException { synchronized (writeLock) { diff --git a/jdk/src/share/classes/sun/nio/ch/Util.java b/jdk/src/share/classes/sun/nio/ch/Util.java index b17801cbed7..50d280865cd 100644 --- a/jdk/src/share/classes/sun/nio/ch/Util.java +++ b/jdk/src/share/classes/sun/nio/ch/Util.java @@ -41,67 +41,180 @@ import sun.security.action.GetPropertyAction; class Util { - // -- Caches -- // The number of temp buffers in our pool - private static final int TEMP_BUF_POOL_SIZE = 3; + private static final int TEMP_BUF_POOL_SIZE = 8; - // Per-thread soft cache of the last temporary direct buffer - private static ThreadLocal>[] bufferPool; + // Per-thread cache of temporary direct buffers + private static ThreadLocal bufferCache = + new ThreadLocal() + { + @Override + protected BufferCache initialValue() { + return new BufferCache(); + } + }; - @SuppressWarnings("unchecked") - static ThreadLocal>[] createThreadLocalBufferPool() { - return new ThreadLocal[TEMP_BUF_POOL_SIZE]; - } - - static { - bufferPool = createThreadLocalBufferPool(); - for (int i=0; i>(); + /** + * A simple cache of direct buffers. + */ + private static class BufferCache { + // the array of buffers + private ByteBuffer[] buffers; + + // the number of buffers in the cache + private int count; + + // the index of the first valid buffer (undefined if count == 0) + private int start; + + private int next(int i) { + return (i + 1) % TEMP_BUF_POOL_SIZE; + } + + BufferCache() { + buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE]; + } + + /** + * Removes and returns a buffer from the cache of at least the given + * size (or null if no suitable buffer is found). + */ + ByteBuffer get(int size) { + if (count == 0) + return null; // cache is empty + + ByteBuffer[] buffers = this.buffers; + + // search for suitable buffer (often the first buffer will do) + ByteBuffer buf = buffers[start]; + if (buf.capacity() < size) { + buf = null; + int i = start; + while ((i = next(i)) != start) { + ByteBuffer bb = buffers[i]; + if (bb == null) + break; + if (bb.capacity() >= size) { + buf = bb; + break; + } + } + if (buf == null) + return null; + // move first element to here to avoid re-packing + buffers[i] = buffers[start]; + } + + // remove first element + buffers[start] = null; + start = next(start); + count--; + + // prepare the buffer and return it + buf.rewind(); + buf.limit(size); + return buf; + } + + boolean offerFirst(ByteBuffer buf) { + if (count >= TEMP_BUF_POOL_SIZE) { + return false; + } else { + start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE; + buffers[start] = buf; + count++; + return true; + } + } + + boolean offerLast(ByteBuffer buf) { + if (count >= TEMP_BUF_POOL_SIZE) { + return false; + } else { + int next = (start + count) % TEMP_BUF_POOL_SIZE; + buffers[next] = buf; + count++; + return true; + } + } + + boolean isEmpty() { + return count == 0; + } + + ByteBuffer removeFirst() { + assert count > 0; + ByteBuffer buf = buffers[start]; + buffers[start] = null; + start = next(start); + count--; + return buf; + } } + /** + * Returns a temporary buffer of at least the given size + */ static ByteBuffer getTemporaryDirectBuffer(int size) { - ByteBuffer buf = null; - // Grab a buffer if available - for (int i=0; i ref = bufferPool[i].get(); - if ((ref != null) && ((buf = ref.get()) != null) && - (buf.capacity() >= size)) { - buf.rewind(); - buf.limit(size); - bufferPool[i].set(null); - return buf; + BufferCache cache = bufferCache.get(); + ByteBuffer buf = cache.get(size); + if (buf != null) { + return buf; + } else { + // No suitable buffer in the cache so we need to allocate a new + // one. To avoid the cache growing then we remove the first + // buffer from the cache and free it. + if (!cache.isEmpty()) { + buf = cache.removeFirst(); + free(buf); } + return ByteBuffer.allocateDirect(size); } - - // Make a new one - return ByteBuffer.allocateDirect(size); } + /** + * Releases a temporary buffer by returning to the cache or freeing it. + */ static void releaseTemporaryDirectBuffer(ByteBuffer buf) { - if (buf == null) - return; - // Put it in an empty slot if such exists - for (int i=0; i ref = bufferPool[i].get(); - if ((ref == null) || (ref.get() == null)) { - bufferPool[i].set(new SoftReference(buf)); - return; - } - } - // Otherwise replace a smaller one in the cache if such exists - for (int i=0; i ref = bufferPool[i].get(); - ByteBuffer inCacheBuf = ref.get(); - if ((inCacheBuf == null) || (buf.capacity() > inCacheBuf.capacity())) { - bufferPool[i].set(new SoftReference(buf)); - return; - } - } + offerFirstTemporaryDirectBuffer(buf); + } - // release memory - ((DirectBuffer)buf).cleaner().clean(); + /** + * Releases a temporary buffer by returning to the cache or freeing it. If + * returning to the cache then insert it at the start so that it is + * likely to be returned by a subsequent call to getTemporaryDirectBuffer. + */ + static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { + assert buf != null; + BufferCache cache = bufferCache.get(); + if (!cache.offerFirst(buf)) { + // cache is full + free(buf); + } + } + + /** + * Releases a temporary buffer by returning to the cache or freeing it. If + * returning to the cache then insert it at the end. This makes it + * suitable for scatter/gather operations where the buffers are returned to + * cache in same order that they were obtained. + */ + static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { + assert buf != null; + BufferCache cache = bufferCache.get(); + if (!cache.offerLast(buf)) { + // cache is full + free(buf); + } + } + + /** + * Frees the memory for the given direct buffer + */ + private static void free(ByteBuffer buf) { + ((DirectBuffer)buf).cleaner().clean(); } private static class SelectorWrapper { diff --git a/jdk/src/share/classes/sun/tools/jconsole/resources/JConsoleResources.java b/jdk/src/share/classes/sun/tools/jconsole/resources/JConsoleResources.java index bce3f2ad799..c9e8ac07c63 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/resources/JConsoleResources.java +++ b/jdk/src/share/classes/sun/tools/jconsole/resources/JConsoleResources.java @@ -46,8 +46,6 @@ import static java.awt.event.KeyEvent.*; */ public class JConsoleResources extends ListResourceBundle { - private static final String cr = System.getProperty("line.separator"); - /** * Returns the contents of this ResourceBundle. * @@ -56,8 +54,8 @@ public class JConsoleResources extends ListResourceBundle { * @return the contents of this ResourceBundle. */ protected Object[][] getContents0() { - return new Object[][] { - // NOTE 1: The value strings in this file containing "{0}" are + Object[][] temp = new Object[][] { + // NOTE 1: The value strings in this file containing "{0}" are // processed by the java.text.MessageFormat class. Any // single quotes appearing in these strings need to be // doubled up. @@ -98,7 +96,7 @@ public class JConsoleResources extends ListResourceBundle { {"Attributes","Attributes"}, {"Blank", "Blank"}, {"BlockedCount WaitedCount", - "Total blocked: {0} Total waited: {1}" + cr}, + "Total blocked: {0} Total waited: {1}\n"}, {"Boot class path","Boot class path"}, {"BorderedComponent.moreOrLessButton.toolTip", "Toggle to show more or less information"}, {"CPU Usage","CPU Usage"}, @@ -271,21 +269,21 @@ public class JConsoleResources extends ListResourceBundle { {"Minimize All.mnemonic", 'M'}, {"Minus Version", "This is {0} version {1}"}, {"Monitor locked", - " - locked {0}" + cr}, + " - locked {0}\n"}, {"Motif","Motif"}, {"Name Build and Mode","{0} (build {1}, {2})"}, {"Name and Build","{0} (build {1})"}, {"Name","Name"}, {"Name: ","Name: "}, {"Name State", - "Name: {0}" + cr + - "State: {1}" + cr}, + "Name: {0}\n" + + "State: {1}\n"}, {"Name State LockName", - "Name: {0}" + cr + - "State: {1} on {2}" + cr}, + "Name: {0}\n" + + "State: {1} on {2}\n"}, {"Name State LockName LockOwner", - "Name: {0}" + cr + - "State: {1} on {2} owned by: {3}" + cr}, + "Name: {0}\n" + + "State: {1} on {2} owned by: {3}\n"}, {"New Connection...", "New Connection..."}, {"New Connection....mnemonic", 'N'}, {"New value applied","New value applied"}, @@ -351,7 +349,7 @@ public class JConsoleResources extends ListResourceBundle { {"Size Mb","{0} Mb"}, {"Source","Source"}, {"Stack trace", - cr + "Stack trace: " + cr}, + "\nStack trace: \n"}, {"Success:","Success:"}, // Note: SummaryTab.headerDateTimeFormat can be one the following: // 1. A combination of two styles for date and time, using the @@ -433,22 +431,27 @@ public class JConsoleResources extends ListResourceBundle { {"plot", "plot"}, {"visualize","visualize"}, {"zz usage text", - "Usage: {0} [ -interval=n ] [ -notile ] [ -pluginpath ] [ -version ] [ connection ... ]" + cr + - cr + - " -interval Set the update interval to n seconds (default is 4 seconds)" + cr + - " -notile Do not tile windows initially (for two or more connections)" + cr + - " -pluginpath Specify the path that jconsole uses to look up the plugins" + cr + - " -version Print program version" + cr + - cr + - " connection = pid || host:port || JMX URL (service:jmx:://...)" + cr + - " pid The process id of a target process" + cr + - " host A remote host name or IP address" + cr + - " port The port number for the remote connection" + cr + - cr + - " -J Specify the input arguments to the Java virtual machine" + cr + + "Usage: {0} [ -interval=n ] [ -notile ] [ -pluginpath ] [ -version ] [ connection ... ]\n\n" + + " -interval Set the update interval to n seconds (default is 4 seconds)\n" + + " -notile Do not tile windows initially (for two or more connections)\n" + + " -pluginpath Specify the path that jconsole uses to look up the plugins\n\n" + + " -version Print program version\n" + + " connection = pid || host:port || JMX URL (service:jmx:://...)\n" + + " pid The process id of a target process\n" + + " host A remote host name or IP address\n" + + " port The port number for the remote connection\n\n" + + " -J Specify the input arguments to the Java virtual machine\n" + " on which jconsole is running"}, // END OF MATERIAL TO LOCALIZE }; + + String ls = System.getProperty("line.separator"); + for(int i=0;i (int)sizeof(buffer_space)) { buffer = malloc(length + 1); check_and_push(context, buffer, VM_MALLOC_BLK); diff --git a/jdk/src/solaris/classes/java/io/UnixFileSystem.java b/jdk/src/solaris/classes/java/io/UnixFileSystem.java index df070bd0039..2c0feb2d5ef 100644 --- a/jdk/src/solaris/classes/java/io/UnixFileSystem.java +++ b/jdk/src/solaris/classes/java/io/UnixFileSystem.java @@ -187,7 +187,6 @@ class UnixFileSystem extends FileSystem { } } } - assert canonicalize0(path).equals(res) || path.startsWith(javaHome); return res; } } diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java index 75a000b7058..53a32c14a64 100644 --- a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java @@ -1141,6 +1141,13 @@ class UnixPath } result = result.resolve(element); } + + // check file exists (without following links) + try { + UnixFileAttributes.get(result, false); + } catch (UnixException x) { + x.rethrowAsIOException(result); + } return result; } diff --git a/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c b/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c index e717322c6ea..48d0d8ecfa8 100644 --- a/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c +++ b/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c @@ -1052,30 +1052,38 @@ JNIEXPORT void JNICALL Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env, jobject this) { jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID); - int fd; - - int t = 1; + int fd, t = 1; +#ifdef AF_INET6 + int domain = ipv6_available() ? AF_INET6 : AF_INET; +#else + int domain = AF_INET; +#endif if (IS_NULL(fdObj)) { JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed"); return; - } else { -#ifdef AF_INET6 - if (ipv6_available()) { - fd = JVM_Socket(AF_INET6, SOCK_DGRAM, 0); - } else -#endif /* AF_INET6 */ - { - fd = JVM_Socket(AF_INET, SOCK_DGRAM, 0); - } } - if (fd == JVM_IO_ERR) { + + if ((fd = JVM_Socket(domain, SOCK_DGRAM, 0)) == JVM_IO_ERR) { NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException", "Error creating socket"); return; } +#ifdef AF_INET6 + /* Disable IPV6_V6ONLY to ensure dual-socket support */ + if (domain == AF_INET6) { + int arg = 0; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, + sizeof(int)) < 0) { + NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6"); + close(fd); + return; + } + } +#endif /* AF_INET6 */ + setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int)); #ifdef __linux__ @@ -1088,7 +1096,7 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env, * On Linux for IPv6 sockets we must set the hop limit * to 1 to be compatible with default ttl of 1 for IPv4 sockets. */ - if (ipv6_available()) { + if (domain == AF_INET6) { int ttl = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&ttl, sizeof(ttl)); diff --git a/jdk/src/solaris/native/java/net/PlainSocketImpl.c b/jdk/src/solaris/native/java/net/PlainSocketImpl.c index 254a1497ff6..060dacdac86 100644 --- a/jdk/src/solaris/native/java/net/PlainSocketImpl.c +++ b/jdk/src/solaris/native/java/net/PlainSocketImpl.c @@ -181,6 +181,12 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this, jboolean stream) { jobject fdObj, ssObj; int fd; + int type = (stream ? SOCK_STREAM : SOCK_DGRAM); +#ifdef AF_INET6 + int domain = ipv6_available() ? AF_INET6 : AF_INET; +#else + int domain = AF_INET; +#endif if (socketExceptionCls == NULL) { jclass c = (*env)->FindClass(env, "java/net/SocketException"); @@ -194,25 +200,29 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this, (*env)->ThrowNew(env, socketExceptionCls, "null fd object"); return; } -#ifdef AF_INET6 - if (ipv6_available()) { - fd = JVM_Socket(AF_INET6, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); - } else -#endif /* AF_INET6 */ - { - fd = JVM_Socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0); - } - if (fd == JVM_IO_ERR) { + + if ((fd = JVM_Socket(domain, type, 0)) == JVM_IO_ERR) { /* note: if you run out of fds, you may not be able to load * the exception class, and get a NoClassDefFoundError * instead. */ NET_ThrowNew(env, errno, "can't create socket"); return; - } else { - (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); } +#ifdef AF_INET6 + /* Disable IPV6_V6ONLY to ensure dual-socket support */ + if (domain == AF_INET6) { + int arg = 0; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, + sizeof(int)) < 0) { + NET_ThrowNew(env, errno, "cannot set IPPROTO_IPV6"); + close(fd); + return; + } + } +#endif /* AF_INET6 */ + /* * If this is a server socket then enable SO_REUSEADDR * automatically and set to non blocking. @@ -221,9 +231,15 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this, if (ssObj != NULL) { int arg = 1; SET_NONBLOCKING(fd); - JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, - sizeof(arg)); + if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, + sizeof(arg)) < 0) { + NET_ThrowNew(env, errno, "cannot set SO_REUSEADDR"); + close(fd); + return; + } } + + (*env)->SetIntField(env, fdObj, IO_fd_fdID, fd); } /* diff --git a/jdk/src/solaris/native/sun/nio/ch/Net.c b/jdk/src/solaris/native/sun/nio/ch/Net.c index e0b3d1c1152..dc3d7c4ac34 100644 --- a/jdk/src/solaris/native/sun/nio/ch/Net.c +++ b/jdk/src/solaris/native/sun/nio/ch/Net.c @@ -170,6 +170,22 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6, if (fd < 0) { return handleSocketError(env, errno); } + +#ifdef AF_INET6 + /* Disable IPV6_V6ONLY to ensure dual-socket support */ + if (domain == AF_INET6) { + int arg = 0; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&arg, + sizeof(int)) < 0) { + JNU_ThrowByNameWithLastError(env, + JNU_JAVANETPKG "SocketException", + "sun.nio.ch.Net.setIntOption"); + close(fd); + return -1; + } + } +#endif + if (reuse) { int arg = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, diff --git a/jdk/src/windows/classes/java/io/Win32FileSystem.java b/jdk/src/windows/classes/java/io/Win32FileSystem.java index 510b84abf62..490c411b072 100644 --- a/jdk/src/windows/classes/java/io/Win32FileSystem.java +++ b/jdk/src/windows/classes/java/io/Win32FileSystem.java @@ -424,7 +424,6 @@ class Win32FileSystem extends FileSystem { } } } - assert canonicalize0(path).equalsIgnoreCase(res); return res; } } diff --git a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh index 47367f7de82..71e07441ce2 100644 --- a/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh +++ b/jdk/test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh @@ -55,7 +55,7 @@ case "$OS" in Linux ) FS="/" ;; - Windows* ) + Windows* | CYGWIN* ) FS="\\" ;; esac diff --git a/jdk/test/java/net/URI/Test.java b/jdk/test/java/net/URI/Test.java index 449f7d1c19e..39b5b9487d1 100644 --- a/jdk/test/java/net/URI/Test.java +++ b/jdk/test/java/net/URI/Test.java @@ -1536,6 +1536,7 @@ public class Test { serial(); urls(); npes(); + bugs(); } @@ -1572,6 +1573,19 @@ public class Test { } + // miscellaneous bugs/rfes that don't fit in with the test framework + + static void bugs() { + // 6339649 - include detail message from nested exception + try { + URI uri = URI.create("http://nowhere.net/should not be permitted"); + } catch (IllegalArgumentException e) { + if ("".equals(e.getMessage()) || e.getMessage() == null) { + throw new RuntimeException ("No detail message"); + } + } + } + public static void main(String[] args) throws Exception { switch (args.length) { diff --git a/jdk/test/java/nio/file/Path/Misc.java b/jdk/test/java/nio/file/Path/Misc.java index 8b2223b2389..3b24c786261 100644 --- a/jdk/test/java/nio/file/Path/Misc.java +++ b/jdk/test/java/nio/file/Path/Misc.java @@ -260,6 +260,21 @@ public class Misc { */ assertTrue(file.toRealPath(true).isSameFile(file.toRealPath(false))); + /** + * Test: toRealPath should fail if file does not exist + */ + Path doesNotExist = dir.resolve("DoesNotExist"); + try { + doesNotExist.toRealPath(true); + throw new RuntimeException("IOException expected"); + } catch (IOException expected) { + } + try { + doesNotExist.toRealPath(false); + throw new RuntimeException("IOException expected"); + } catch (IOException expected) { + } + /** * Test: toRealPath(true) should resolve links */ diff --git a/jdk/test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh b/jdk/test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh index 917f1c22833..49d5f44be71 100644 --- a/jdk/test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh +++ b/jdk/test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh @@ -23,6 +23,7 @@ # # @test +# @ignore until 6543856 is fixed # @bug 4990825 # @summary attach to external but local JVM processes # @library ../../testlibrary diff --git a/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.java b/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.java new file mode 100644 index 00000000000..7ffe3a1d67c --- /dev/null +++ b/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.net.URL; +import java.net.URLConnection; +import java.io.IOException; + +public class DirPermissionDenied { + public static void main(String[] args) throws Exception { + URL url = new URL("file:" + args[0]); + + try { + URLConnection uc = url.openConnection(); + uc.connect(); + } catch (IOException e) { + // OK + } catch (Exception e) { + throw new RuntimeException("Failed " + e); + } + + try { + URLConnection uc = url.openConnection(); + uc.getInputStream(); + } catch (IOException e) { + // OK + } catch (Exception e) { + throw new RuntimeException("Failed " + e); + } + + try { + URLConnection uc = url.openConnection(); + uc.getContentLengthLong(); + } catch (IOException e) { + // OK + } catch (Exception e) { + throw new RuntimeException("Failed " + e); + } + } +} diff --git a/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.sh b/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.sh new file mode 100644 index 00000000000..67930b02bd4 --- /dev/null +++ b/jdk/test/sun/net/www/protocol/file/DirPermissionDenied.sh @@ -0,0 +1,41 @@ +# +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please 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 6977851 +# @summary NPE from FileURLConnection.connect +# @build DirPermissionDenied +# @run shell DirPermissionDenied.sh + +TESTDIR="${TESTCLASSES}/DirPermissionDeniedDirectory" +echo ${TESTDIR} + +rm -rf ${TESTDIR} +mkdir -p ${TESTDIR} +chmod 333 ${TESTDIR} + +$TESTJAVA/bin/java -classpath $TESTCLASSES DirPermissionDenied ${TESTDIR} +result=$? +rm -rf ${TESTDIR} +exit $result diff --git a/jdk/test/sun/security/krb5/BadKdcDefaultValue.java b/jdk/test/sun/security/krb5/BadKdcDefaultValue.java new file mode 100644 index 00000000000..1235cce4b9d --- /dev/null +++ b/jdk/test/sun/security/krb5/BadKdcDefaultValue.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 6976536 + * @summary Solaris JREs do not have the krb5.kdc.bad.policy configured by default. + * @run main/othervm BadKdcDefaultValue + */ + +import java.security.Security; + +public class BadKdcDefaultValue { + public static void main(String[] args) throws Exception { + if (!"tryLast".equalsIgnoreCase( + Security.getProperty("krb5.kdc.bad.policy"))) { + throw new Exception("Default value not correct"); + } + } +} + diff --git a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java index 3856ef7ebe1..7481a6cbf04 100644 --- a/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java +++ b/jdk/test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6226610 + * @bug 6226610 6973030 * @run main/othervm B6226610 * @summary HTTP tunnel connections send user headers to proxy */ @@ -36,45 +36,23 @@ import java.io.*; import java.net.*; -import javax.net.ssl.*; -import javax.net.ServerSocketFactory; -import sun.net.www.*; -import java.util.Enumeration; +import sun.net.www.MessageHeader; public class B6226610 { static HeaderCheckerProxyTunnelServer proxy; - // it seems there's no proxy ever if a url points to 'localhost', - // even if proxy related properties are set. so we need to bind - // our simple http proxy and http server to a non-loopback address - static InetAddress firstNonLoAddress = null; - - public static void main(String[] args) + public static void main(String[] args) throws Exception { - try { - proxy = new HeaderCheckerProxyTunnelServer(); - proxy.start(); - } catch (Exception e) { - System.out.println("Cannot create proxy: " + e); - } + proxy = new HeaderCheckerProxyTunnelServer(); + proxy.start(); - try { - firstNonLoAddress = getNonLoAddress(); - - if (firstNonLoAddress == null) { - System.out.println("The test needs at least one non-loopback address to run. Quit now."); - System.exit(0); - } - } catch (Exception e) { - e.printStackTrace(); - } - - System.setProperty( "https.proxyHost", firstNonLoAddress.getHostAddress()); - System.setProperty( "https.proxyPort", (new Integer(proxy.getLocalPort())).toString() ); + String hostname = InetAddress.getLocalHost().getHostName(); try { - URL u = new URL("https://" + firstNonLoAddress.getHostAddress()); - java.net.URLConnection c = u.openConnection(); + URL u = new URL("https://" + hostname + "/"); + System.out.println("Connecting to " + u); + InetSocketAddress proxyAddr = new InetSocketAddress(hostname, proxy.getLocalPort()); + java.net.URLConnection c = u.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddr)); /* I want this header to go to the destination server only, protected * by SSL @@ -89,33 +67,15 @@ public class B6226610 { } else System.out.println(e); - + } finally { + if (proxy != null) proxy.shutdown(); } if (HeaderCheckerProxyTunnelServer.failed) - throw new RuntimeException("Test failed: Proxy should not receive user defined headers for tunneled requests"); + throw new RuntimeException("Test failed; see output"); } - - public static InetAddress getNonLoAddress() throws Exception { - NetworkInterface loNIC = NetworkInterface.getByInetAddress(InetAddress.getByName("localhost")); - Enumeration nics = NetworkInterface.getNetworkInterfaces(); - while (nics.hasMoreElements()) { - NetworkInterface nic = nics.nextElement(); - if (!nic.getName().equalsIgnoreCase(loNIC.getName())) { - Enumeration addrs = nic.getInetAddresses(); - while (addrs.hasMoreElements()) { - InetAddress addr = addrs.nextElement(); - if (!addr.isLoopbackAddress()) - return addr; - } - } - } - return null; - } - } - class HeaderCheckerProxyTunnelServer extends Thread { public static boolean failed = false; @@ -139,6 +99,10 @@ class HeaderCheckerProxyTunnelServer extends Thread } } + void shutdown() { + try { ss.close(); } catch (IOException e) {} + } + public void run() { try { @@ -178,6 +142,15 @@ class HeaderCheckerProxyTunnelServer extends Thread retrieveConnectInfo(statusLine); if (mheader.findValue("X-TestHeader") != null) { + System.out.println("Proxy should not receive user defined headers for tunneled requests"); + failed = true; + } + + // 6973030 + String value; + if ((value = mheader.findValue("Proxy-Connection")) == null || + !value.equals("keep-alive")) { + System.out.println("Proxy-Connection:keep-alive not being sent"); failed = true; } diff --git a/jdk/test/tools/jar/JarEntryTime.java b/jdk/test/tools/jar/JarEntryTime.java index 525d6b9032d..2998b29bc8a 100644 --- a/jdk/test/tools/jar/JarEntryTime.java +++ b/jdk/test/tools/jar/JarEntryTime.java @@ -23,7 +23,7 @@ /** * @test - * @bug 4225317 + * @bug 4225317 6969651 * @summary Check extracted files have date as per those in the .jar file */ @@ -68,17 +68,9 @@ public class JarEntryTime { } public static void realMain(String[] args) throws Throwable { - final long now = System.currentTimeMillis(); - final long earlier = now - (60L * 60L * 6L * 1000L); - final long yesterday = now - (60L * 60L * 24L * 1000L); - - // ZipEntry's mod date has 2 seconds precision: give extra time to - // allow for e.g. rounding/truncation and networked/samba drives. - final long PRECISION = 10000L; File dirOuter = new File("outer"); File dirInner = new File(dirOuter, "inner"); - File jarFile = new File("JarEntryTime.jar"); // Remove any leftovers from prior run @@ -99,6 +91,17 @@ public class JarEntryTime { PrintWriter pw = new PrintWriter(fileInner); pw.println("hello, world"); pw.close(); + + // Get the "now" from the "last-modified-time" of the last file we + // just created, instead of the "System.currentTimeMillis()", to + // workaround the possible "time difference" due to nfs. + final long now = fileInner.lastModified(); + final long earlier = now - (60L * 60L * 6L * 1000L); + final long yesterday = now - (60L * 60L * 24L * 1000L); + // ZipEntry's mod date has 2 seconds precision: give extra time to + // allow for e.g. rounding/truncation and networked/samba drives. + final long PRECISION = 10000L; + dirOuter.setLastModified(now); dirInner.setLastModified(yesterday); fileInner.setLastModified(earlier); diff --git a/jdk/test/tools/pack200/CommandLineTests.java b/jdk/test/tools/pack200/CommandLineTests.java new file mode 100644 index 00000000000..fefefd2a860 --- /dev/null +++ b/jdk/test/tools/pack200/CommandLineTests.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2007, 2010 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 CommandLineTests.sh + * @bug 6521334 6965836 6965836 + * @compile -XDignore.symbol.file CommandLineTests.java Pack200Test.java + * @run main/timeout=1200 CommandLineTests + * @summary An ad hoc test to verify the behavior of pack200/unpack200 CLIs, + * and a simulation of pack/unpacking in the install repo. + * @author ksrini + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +/* + * We try a potpouri of things ie. we have pack.conf to setup some + * options as well as a couple of command line options. We also test + * the packing and unpacking mechanism using the Java APIs. This also + * simulates pack200 the install workspace, noting that this is a simulation + * and can only test jars that are guaranteed to be available, also the + * configuration may not be in sync with the installer workspace. + */ + +public class CommandLineTests { + private static final File CWD = new File("."); + private static final File EXP_SDK = new File(CWD, "exp-sdk-image"); + private static final File EXP_SDK_LIB_DIR = new File(EXP_SDK, "lib"); + private static final File EXP_SDK_BIN_DIR = new File(EXP_SDK, "bin"); + private static final File EXP_JRE_DIR = new File(EXP_SDK, "jre"); + private static final File EXP_JRE_LIB_DIR = new File(EXP_JRE_DIR, "lib"); + private static final File RtJar = new File(EXP_JRE_LIB_DIR, "rt.jar"); + private static final File CharsetsJar = new File(EXP_JRE_LIB_DIR, "charsets.jar"); + private static final File JsseJar = new File(EXP_JRE_LIB_DIR, "jsse.jar"); + private static final File ToolsJar = new File(EXP_SDK_LIB_DIR, "tools.jar"); + private static final File javaCmd; + private static final File javacCmd; + private static final File ConfigFile = new File("pack.conf"); + private static final List jarList; + + static { + javaCmd = Utils.IsWindows + ? new File(EXP_SDK_BIN_DIR, "java.exe") + : new File(EXP_SDK_BIN_DIR, "java"); + + javacCmd = Utils.IsWindows + ? new File(EXP_SDK_BIN_DIR, "javac.exe") + : new File(EXP_SDK_BIN_DIR, "javac"); + + jarList = new ArrayList(); + jarList.add(RtJar); + jarList.add(CharsetsJar); + jarList.add(JsseJar); + jarList.add(ToolsJar); + } + + // init test area with a copy of the sdk + static void init() throws IOException { + Utils.recursiveCopy(Utils.JavaSDK, EXP_SDK); + creatConfigFile(); + } + + // Hopefully, this should be kept in sync with what the installer does. + static void creatConfigFile() throws IOException { + FileOutputStream fos = null; + PrintStream ps = null; + try { + fos = new FileOutputStream(ConfigFile); + ps = new PrintStream(fos); + ps.println("com.sun.java.util.jar.pack.debug.verbose=0"); + ps.println("pack.modification.time=keep"); + ps.println("pack.keep.class.order=true"); + ps.println("pack.deflate.hint=false"); + // Fail the build, if new or unknown attributes are introduced. + ps.println("pack.unknown.attribute=error"); + ps.println("pack.segment.limit=-1"); + // BugId: 6328502, These files will be passed-through as-is. + ps.println("pack.pass.file.0=java/lang/Error.class"); + ps.println("pack.pass.file.1=java/lang/LinkageError.class"); + ps.println("pack.pass.file.2=java/lang/Object.class"); + ps.println("pack.pass.file.3=java/lang/Throwable.class"); + ps.println("pack.pass.file.4=java/lang/VerifyError.class"); + ps.println("pack.pass.file.5=com/sun/demo/jvmti/hprof/Tracker.class"); + } finally { + Utils.close(ps); + Utils.close(fos); + } + } + + static void runPack200(boolean jre) throws IOException { + List cmdsList = new ArrayList(); + for (File f : jarList) { + if (jre && f.getName().equals("tools.jar")) { + continue; // need not worry about tools.jar for JRE + } + // make a backup copy for re-use + File bakFile = new File(f.getName() + ".bak"); + if (!bakFile.exists()) { // backup + Utils.copyFile(f.getAbsoluteFile(), bakFile.getAbsoluteFile()); + } else { // restore + Utils.copyFile(bakFile.getAbsoluteFile(), f.getAbsoluteFile()); + } + cmdsList.clear(); + cmdsList.add(Utils.getPack200Cmd()); + cmdsList.add("-J-esa"); + cmdsList.add("-J-ea"); + cmdsList.add(Utils.Is64Bit ? "-J-Xmx1g" : "-J-Xmx512m"); + cmdsList.add("--repack"); + cmdsList.add("--config-file=" + ConfigFile.getAbsolutePath()); + if (jre) { + cmdsList.add("--strip-debug"); + } + // NOTE: commented until 6965836 is fixed + // cmdsList.add("--code-attribute=StackMapTable=strip"); + cmdsList.add(f.getAbsolutePath()); + Utils.runExec(cmdsList); + } + } + + static void testJRE() throws IOException { + runPack200(true); + // the speciment JRE + List cmdsList = new ArrayList(); + cmdsList.add(javaCmd.getAbsolutePath()); + cmdsList.add("-verify"); + cmdsList.add("-version"); + Utils.runExec(cmdsList); + } + + static void testJDK() throws IOException { + runPack200(false); + // test the specimen JDK + List cmdsList = new ArrayList(); + cmdsList.add(javaCmd.getAbsolutePath()); + cmdsList.add("-verify"); + cmdsList.add("-version"); + Utils.runExec(cmdsList); + + // invoke javac to test the tools.jar + cmdsList.clear(); + cmdsList.add(javacCmd.getAbsolutePath()); + cmdsList.add("-J-verify"); + cmdsList.add("-help"); + Utils.runExec(cmdsList); + } + public static void main(String... args) { + try { + init(); + testJRE(); + testJDK(); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } +} diff --git a/jdk/test/tools/pack200/Pack200Props.java b/jdk/test/tools/pack200/Pack200Props.java new file mode 100644 index 00000000000..61b718ea9d9 --- /dev/null +++ b/jdk/test/tools/pack200/Pack200Props.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6575373 6969063 + * @summary verify default properties of the packer/unpacker and segment limit + * @compile -XDignore.symbol.file Utils.java Pack200Props.java + * @run main Pack200Props + * @author ksrini + */ + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.jar.Pack200; +import java.util.jar.Pack200.Packer; + +/* + * Run this against a large jar file, by default the packer should generate only + * one segment, parse the output of the packer to verify if this is indeed true. + */ + +public class Pack200Props { + + public static void main(String... args) { + verifyDefaults(); + File out = new File("test" + Utils.PACK_FILE_EXT); + out.delete(); + verifySegmentLimit(out); + } + + static void verifySegmentLimit(File outFile) { + File sdkHome = Utils.JavaSDK; + File testJar = new File(new File(sdkHome, "lib"), "tools.jar"); + + System.out.println("using pack200: " + Utils.getPack200Cmd()); + + List cmdsList = new ArrayList<>(); + cmdsList.add(Utils.getPack200Cmd()); + cmdsList.add("--effort=1"); + cmdsList.add("--verbose"); + cmdsList.add("--no-gzip"); + cmdsList.add(outFile.getName()); + cmdsList.add(testJar.getAbsolutePath()); + List outList = Utils.runExec(cmdsList); + + int count = 0; + for (String line : outList) { + System.out.println(line); + if (line.matches(".*Transmitted.*files of.*input bytes in a segment of.*bytes")) { + count++; + } + } + if (count == 0) { + throw new RuntimeException("no segments or no output ????"); + } else if (count > 1) { + throw new RuntimeException("multiple segments detected, expected 1"); + } + } + + private static void verifyDefaults() { + Map expectedDefaults = new HashMap<>(); + Packer p = Pack200.newPacker(); + expectedDefaults.put("com.sun.java.util.jar.pack.default.timezone", + p.FALSE); + expectedDefaults.put("com.sun.java.util.jar.pack.disable.native", + p.FALSE); + expectedDefaults.put("com.sun.java.util.jar.pack.verbose", "0"); + expectedDefaults.put(p.CLASS_ATTRIBUTE_PFX + "CompilationID", "RUH"); + expectedDefaults.put(p.CLASS_ATTRIBUTE_PFX + "SourceID", "RUH"); + expectedDefaults.put(p.CODE_ATTRIBUTE_PFX + "CharacterRangeTable", + "NH[PHPOHIIH]"); + expectedDefaults.put(p.CODE_ATTRIBUTE_PFX + "CoverageTable", + "NH[PHHII]"); + expectedDefaults.put(p.DEFLATE_HINT, p.KEEP); + expectedDefaults.put(p.EFFORT, "5"); + expectedDefaults.put(p.KEEP_FILE_ORDER, p.TRUE); + expectedDefaults.put(p.MODIFICATION_TIME, p.KEEP); + expectedDefaults.put(p.SEGMENT_LIMIT, "-1"); + expectedDefaults.put(p.UNKNOWN_ATTRIBUTE, p.PASS); + + Map props = p.properties(); + int errors = 0; + for (String key : expectedDefaults.keySet()) { + String def = expectedDefaults.get(key); + String x = props.get(key); + if (x == null) { + System.out.println("Error: key not found:" + key); + errors++; + } else { + if (!def.equals(x)) { + System.out.println("Error: key " + key + + "\n value expected: " + def + + "\n value obtained: " + x); + errors++; + } + } + } + if (errors > 0) { + throw new RuntimeException(errors + + " error(s) encountered in default properties verification"); + } + } +} + diff --git a/jdk/test/tools/pack200/Pack200Simple.sh b/jdk/test/tools/pack200/Pack200Simple.sh deleted file mode 100644 index 71b9611c963..00000000000 --- a/jdk/test/tools/pack200/Pack200Simple.sh +++ /dev/null @@ -1,197 +0,0 @@ -# -# Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# @test Pack200Simple.sh -# @bug 6521334 -# @build Pack200Test -# @run shell/timeout=1200 Pack200Simple.sh -# @summary An ad hoc test to verify class-file format. -# @author Kumar Srinivasan - -# The goal of this test is to assist javac or other developers -# who modify class file formats, to quickly test those modifications -# without having to build the install workspace. However it must -# be noted that building the install workspace is the only know -# way to prevent build breakages. - -# Pack200 developers could use this as a basic smoke-test, however -# please note, there are other more elaborate and thorough tests for -# this very purpose. - -# We try a potpouri of things ie. we have pack.conf to setup some -# options as well as a couple of command line options. We also test -# the packing and unpacking mechanism using the Java APIs. - -# print error and exit with a message -errorOut() { - if [ "x$1" = "x" ]; then - printf "Error: Unknown error\n" - else - printf "Error: %s\n" "$1" - fi - - exit 1 -} - -# Verify directory context variables are set -if [ "${TESTJAVA}" = "" ]; then - errorOut "TESTJAVA not set. Test cannot execute. Failed." -fi - -if [ "${TESTSRC}" = "" ]; then - errorOut "TESTSRC not set. Test cannot execute. Failed." -fi - - -if [ "${TESTCLASSES}" = "" ]; then - errorOut "TESTCLASSES not set. Test cannot execute. Failed." -fi - -# The common java utils we need -PACK200=${TESTJAVA}/bin/pack200 -UNPACK200=${TESTJAVA}/bin/unpack200 -JAR=${TESTJAVA}/bin/jar - -# For Windows and Linux needs the heap to be set, for others ergonomics -# will do the rest. It is important to use ea, which can expose class -# format errors much earlier than later. - -OS=`uname -s` - - -case "$OS" in - Windows*|CYGWIN* ) - PackOptions="-J-Xmx512m -J-ea" - break - ;; - - Linux ) - PackOptions="-J-Xmx512m -J-ea" - break - ;; - - * ) - PackOptions="-J-ea" - ;; -esac - -# Creates a packfile of choice expects 1 argument the filename -createConfigFile() { - # optimize for speed - printf "pack.effort=1\n" > $1 - # we DO want to know about new attributes - printf "pack.unknown.attribute=error\n" >> $1 - # optimize for speed - printf "pack.deflate.hint=false\n" >> $1 - # keep the ordering for easy compare - printf "pack.keep.class.order=true\n" >> $1 -} - - -# Tests a given jar, expects 1 argument the fully qualified -# name to a test jar, it writes all output to the current -# directory which is a scratch area. -testAJar() { - PackConf="pack.conf" - createConfigFile $PackConf - - # Try some command line options - CLIPackOptions="$PackOptions -v --no-gzip --segment-limit=10000 --config-file=$PackConf" - - jfName=`basename $1` - - ${PACK200} $CLIPackOptions ${jfName}.pack $1 > ${jfName}.pack.log 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName packing failed" - fi - - # We want to test unpack200, therefore we dont use -r with pack - ${UNPACK200} -v ${jfName}.pack $jfName > ${jfName}.unpack.log 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName unpacking failed" - fi - - # A quick crc compare test to ensure a well formed zip - # archive, this is a critical unpack200 behaviour. - - unzip -t $jfName > ${jfName}.unzip.log 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName unzip -t test failed" - fi - - # The PACK200 signature should be at the top of the log - # this tag is critical for deployment related tools. - - head -5 ${jfName}.unzip.log | grep PACK200 > /dev/null 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName PACK200 signature missing" - fi - - - # we know the size fields don't match, strip 'em out, its - # extremely important to ensure that the date stamps match up. - # Don't EVER sort the output we are checking for correct ordering. - - ${JAR} -tvf $1 | sed -e 's/^ *[0-9]* //g'> ${jfName}.ref.txt - ${JAR} -tvf $jfName | sed -e 's/^ *[0-9]* //g'> ${jfName}.cmp.txt - - diff ${jfName}.ref.txt ${jfName}.cmp.txt > ${jfName}.diff.log 2>&1 - if [ $? != 0 ]; then - errorOut "$jfName files missing" - fi -} - -# These JARs are the largest and also the most likely specimens to -# expose class format issues and stress the packer as well. - -JLIST="${TESTJAVA}/lib/tools.jar ${TESTJAVA}/jre/lib/rt.jar" - - -# Test the Command Line Interfaces (CLI). -mkdir cliTestDir -_pwd=`pwd` -cd cliTestDir - -for jarfile in $JLIST ; do - if [ -f $jarfile ]; then - testAJar $jarfile - else - errorOut "Error: '$jarFile' does not exist\nTest requires a j2sdk-image\n" - fi -done -cd $_pwd - -# Test the Java APIs. -mkdir apiTestDir -_pwd=`pwd` -cd apiTestDir - -# Strip out the -J prefixes. -JavaPackOptions=`printf %s "$PackOptions" | sed -e 's/-J//g'` - -# Test the Java APIs now. -$TESTJAVA/bin/java $JavaPackOptions -cp $TESTCLASSES Pack200Test $JLIST || exit 1 - -cd $_pwd - -exit 0 diff --git a/jdk/test/tools/pack200/Pack200Test.java b/jdk/test/tools/pack200/Pack200Test.java index 631b50709da..04dbf7327c2 100644 --- a/jdk/test/tools/pack200/Pack200Test.java +++ b/jdk/test/tools/pack200/Pack200Test.java @@ -24,111 +24,97 @@ import java.util.*; import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; import java.util.jar.*; -import java.util.zip.*; -/* - * Pack200Test.java - * - * @author ksrini - */ + /* + * @test + * @bug 6521334 6712743 + * @summary check for memory leaks, test general packer/unpacker functionality\ + * using native and java unpackers + * @compile -XDignore.symbol.file Utils.java Pack200Test.java + * @run main/othervm/timeout=1200 -Xmx512m Pack200Test + * @author ksrini + */ /** - * These tests are very rudimentary smoke tests to ensure that the packing - * unpacking process works on a select set of JARs. + * Tests the packing/unpacking via the APIs. */ public class Pack200Test { private static ArrayList jarList = new ArrayList(); - static final String PACKEXT = ".pack"; + static final MemoryMXBean mmxbean = ManagementFactory.getMemoryMXBean(); + static final long m0 = getUsedMemory(); + static final int LEAK_TOLERANCE = 20000; // OS and GC related variations. /** Creates a new instance of Pack200Test */ private Pack200Test() {} + static long getUsedMemory() { + mmxbean.gc(); + mmxbean.gc(); + mmxbean.gc(); + return mmxbean.getHeapMemoryUsage().getUsed()/1024; + } + + private static void leakCheck() throws Exception { + long diff = getUsedMemory() - m0; + System.out.println(" Info: memory diff = " + diff + "K"); + if ( diff > LEAK_TOLERANCE) { + throw new Exception("memory leak detected " + diff); + } + } + private static void doPackUnpack() { for (File in : jarList) { - Pack200.Packer packer = Pack200.newPacker(); - Map p = packer.properties(); - // Take the time optimization vs. space - p.put(packer.EFFORT, "1"); // CAUTION: do not use 0. - // Make the memory consumption as effective as possible - p.put(packer.SEGMENT_LIMIT,"10000"); - // throw an error if an attribute is unrecognized - p.put(packer.UNKNOWN_ATTRIBUTE, packer.ERROR); - // ignore all JAR deflation requests to save time - p.put(packer.DEFLATE_HINT, packer.FALSE); - // save the file ordering of the original JAR - p.put(packer.KEEP_FILE_ORDER, packer.TRUE); - + JarOutputStream javaUnpackerStream = null; + JarOutputStream nativeUnpackerStream = null; + JarFile jarFile = null; try { - JarFile jarFile = new JarFile(in); + jarFile = new JarFile(in); // Write out to a jtreg scratch area - FileOutputStream fos = new FileOutputStream(in.getName() + PACKEXT); + File packFile = new File(in.getName() + Utils.PACK_FILE_EXT); - System.out.print("Packing [" + in.toString() + "]..."); + System.out.println("Packing [" + in.toString() + "]"); // Call the packer - packer.pack(jarFile, fos); + Utils.pack(jarFile, packFile); jarFile.close(); - fos.close(); - - System.out.print("Unpacking..."); - File f = new File(in.getName() + PACKEXT); + leakCheck(); + System.out.println(" Unpacking using java unpacker"); + File javaUnpackedJar = new File("java-" + in.getName()); // Write out to current directory, jtreg will setup a scratch area - JarOutputStream jostream = new JarOutputStream(new FileOutputStream(in.getName())); - - // Unpack the files - Pack200.Unpacker unpacker = Pack200.newUnpacker(); - // Call the unpacker - unpacker.unpack(f, jostream); - // Must explicitly close the output. - jostream.close(); - System.out.print("Testing..."); + javaUnpackerStream = new JarOutputStream( + new FileOutputStream(javaUnpackedJar)); + Utils.unpackj(packFile, javaUnpackerStream); + javaUnpackerStream.close(); + System.out.println(" Testing...java unpacker"); + leakCheck(); // Ok we have unpacked the file, lets test it. - doTest(in); + Utils.doCompareVerify(in.getAbsoluteFile(), javaUnpackedJar); + + System.out.println(" Unpacking using native unpacker"); + // Write out to current directory + File nativeUnpackedJar = new File("native-" + in.getName()); + nativeUnpackerStream = new JarOutputStream( + new FileOutputStream(nativeUnpackedJar)); + Utils.unpackn(packFile, nativeUnpackerStream); + nativeUnpackerStream.close(); + System.out.println(" Testing...native unpacker"); + leakCheck(); + // the unpackers (native and java) should produce identical bits + // so we use use bit wise compare, the verification compare is + // very expensive wrt. time. + Utils.doCompareBitWise(javaUnpackedJar, nativeUnpackedJar); System.out.println("Done."); } catch (Exception e) { - System.out.println("ERROR: " + e.getMessage()); - System.exit(1); - } - } - } - - private static ArrayList getZipFileEntryNames(ZipFile z) { - ArrayList out = new ArrayList(); - for (ZipEntry ze : Collections.list(z.entries())) { - out.add(ze.getName()); - } - return out; - } - - private static void doTest(File in) throws Exception { - // make sure all the files in the original jar exists in the other - ArrayList refList = getZipFileEntryNames(new ZipFile(in)); - ArrayList cmpList = getZipFileEntryNames(new ZipFile(in.getName())); - - System.out.print(refList.size() + "/" + cmpList.size() + " entries..."); - - if (refList.size() != cmpList.size()) { - throw new Exception("Missing: files ?, entries don't match"); - } - - for (String ename: refList) { - if (!cmpList.contains(ename)) { - throw new Exception("Does not contain : " + ename); - } - } - } - - private static void doSanity(String[] args) { - for (String s: args) { - File f = new File(s); - if (f.exists()) { - jarList.add(f); - } else { - System.out.println("Warning: The JAR file " + f.toString() + " does not exist,"); - System.out.println(" this test requires a JDK image, this file will be skipped."); + throw new RuntimeException(e); + } finally { + Utils.close(nativeUnpackerStream); + Utils.close(javaUnpackerStream); + Utils.close((Closeable) jarFile); } } } @@ -137,11 +123,12 @@ public class Pack200Test { * @param args the command line arguments */ public static void main(String[] args) { - if (args.length < 1) { - System.out.println("Usage: jar1 jar2 jar3 ....."); - System.exit(1); - } - doSanity(args); + // select the jars carefully, adding more jars will increase the + // testing time, especially for jprt. + jarList.add(Utils.locateJar("tools.jar")); + jarList.add(Utils.locateJar("rt.jar")); + jarList.add(Utils.locateJar("golden.jar")); + System.out.println(jarList); doPackUnpack(); } } diff --git a/jdk/test/tools/pack200/PackageVersionTest.java b/jdk/test/tools/pack200/PackageVersionTest.java index 0cd9ca26453..344aadd6b61 100644 --- a/jdk/test/tools/pack200/PackageVersionTest.java +++ b/jdk/test/tools/pack200/PackageVersionTest.java @@ -22,13 +22,14 @@ * questions. */ -/** - * @test - * @bug 6712743 - * @summary verify package versioning - * @compile -XDignore.symbol.file PackageVersionTest.java - * @run main PackageVersionTest - */ +/* + * @test + * @bug 6712743 + * @summary verify package versions + * @compile -XDignore.symbol.file Utils.java PackageVersionTest.java + * @run main PackageVersionTest + * @author ksrini + */ import java.io.ByteArrayOutputStream; import java.io.Closeable; @@ -74,14 +75,6 @@ public class PackageVersionTest { JAVA5_PACKAGE_MINOR_VERSION); } - static void close(Closeable c) { - if (c == null) { - return; - } - try { - c.close(); - } catch (IOException ignore) {} - } static void createClassFile(String name) { createJavaFile(name); @@ -93,7 +86,7 @@ public class PackageVersionTest { name.substring(name.length() - 1), name + ".java" }; - compileJava(javacCmds); + Utils.compiler(javacCmds); } static void createJavaFile(String name) { @@ -108,22 +101,8 @@ public class PackageVersionTest { } catch (IOException ioe) { throw new RuntimeException("creation of test file failed"); } finally { - close(ps); - close(fos); - } - } - - static void compileJava(String... javacCmds) { - if (com.sun.tools.javac.Main.compile(javacCmds) != 0) { - throw new RuntimeException("compilation failed"); - } - } - - static void makeJar(String... jargs) { - sun.tools.jar.Main jarTool = - new sun.tools.jar.Main(System.out, System.err, "jartool"); - if (!jarTool.run(jargs)) { - throw new RuntimeException("jar command failed"); + Utils.close(ps); + Utils.close(fos); } } @@ -136,7 +115,7 @@ public class PackageVersionTest { jarFileName.getName(), filename }; - makeJar(jargs); + Utils.jar(jargs); JarFile jfin = null; try { @@ -163,7 +142,7 @@ public class PackageVersionTest { } catch (IOException ioe) { throw new RuntimeException(ioe.getMessage()); } finally { - close(jfin); + Utils.close((Closeable) jfin); } } } diff --git a/jdk/test/tools/pack200/SegmentLimit.java b/jdk/test/tools/pack200/SegmentLimit.java deleted file mode 100644 index 249e47b032f..00000000000 --- a/jdk/test/tools/pack200/SegmentLimit.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 6575373 - * @summary verify default segment limit - * @compile SegmentLimit.java - * @run main SegmentLimit - */ - -import java.io.BufferedReader; -import java.io.Closeable; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintStream; - -/* - * Run this against a large jar file, by default the packer should generate only - * one segment, parse the output of the packer to verify if this is indeed true. - */ - -public class SegmentLimit { - - private static final File javaHome = new File(System.getProperty("java.home")); - - public static void main(String... args) { - if (!javaHome.getName().endsWith("jre")) { - throw new RuntimeException("Error: requires an SDK to run"); - } - - File out = new File("test" + Pack200Test.PACKEXT); - out.delete(); - runPack200(out); - } - - static void close(Closeable c) { - if (c == null) { - return; - } - try { - c.close(); - } catch (IOException ignore) {} - } - - static void runPack200(File outFile) { - File binDir = new File(javaHome, "bin"); - File pack200Exe = System.getProperty("os.name").startsWith("Windows") - ? new File(binDir, "pack200.exe") - : new File(binDir, "pack200"); - File sdkHome = javaHome.getParentFile(); - File testJar = new File(new File(sdkHome, "lib"), "tools.jar"); - - System.out.println("using pack200: " + pack200Exe.getAbsolutePath()); - - String[] cmds = { pack200Exe.getAbsolutePath(), - "--effort=1", - "--verbose", - "--no-gzip", - outFile.getName(), - testJar.getAbsolutePath() - }; - InputStream is = null; - BufferedReader br = null; - InputStreamReader ir = null; - - FileOutputStream fos = null; - PrintStream ps = null; - - try { - ProcessBuilder pb = new ProcessBuilder(cmds); - pb.redirectErrorStream(true); - Process p = pb.start(); - is = p.getInputStream(); - ir = new InputStreamReader(is); - br = new BufferedReader(ir); - - File logFile = new File("pack200.log"); - fos = new FileOutputStream(logFile); - ps = new PrintStream(fos); - - String line = br.readLine(); - int count = 0; - while (line != null) { - line = line.trim(); - if (line.matches(".*Transmitted.*files of.*input bytes in a segment of.*bytes")) { - count++; - } - ps.println(line); - line=br.readLine(); - } - p.waitFor(); - if (p.exitValue() != 0) { - throw new RuntimeException("pack200 failed"); - } - p.destroy(); - if (count > 1) { - throw new Error("test fails: check for multiple segments(" + - count + ") in: " + logFile.getAbsolutePath()); - } - } catch (IOException ex) { - throw new RuntimeException(ex.getMessage()); - } catch (InterruptedException ignore){ - } finally { - close(is); - close(ps); - close(fos); - } - } -} - diff --git a/jdk/test/tools/pack200/TimeStamp.java b/jdk/test/tools/pack200/TimeStamp.java new file mode 100644 index 00000000000..3d099e2141c --- /dev/null +++ b/jdk/test/tools/pack200/TimeStamp.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.TimeZone; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; + +/* + * @test + * @bug 6966740 + * @summary verify identical timestamps, unpacked in any timezone + * @compile -XDignore.symbol.file Utils.java TimeStamp.java + * @run main/othervm TimeStamp + * @author ksrini + */ + +/** + * First we pack the file in some time zone say India, then we unpack the file + * in the current time zone, and ensure the timestamp recorded in the unpacked + * jar are the same. + */ +public class TimeStamp { + static final TimeZone tz = TimeZone.getDefault(); + + + public static void main(String... args) throws IOException { + + // make a local copy of our test file + File srcFile = Utils.locateJar("golden.jar"); + File goldenFile = new File("golden.jar"); + Utils.copyFile(srcFile, goldenFile.getAbsoluteFile()); + + JarFile goldenJarFile = new JarFile(goldenFile); + File packFile = new File("golden.pack"); + + // set the test timezone and pack the file + TimeZone.setDefault(TimeZone.getTimeZone("IST")); + Utils.pack(goldenJarFile, packFile); + TimeZone.setDefault(tz); // reset the timezone + + // unpack in the test timezone + File istFile = new File("golden.jar.java.IST"); + unpackJava(packFile, istFile); + verifyJar(goldenFile, istFile); + istFile.delete(); + + // unpack in some other timezone + File pstFile = new File("golden.jar.java.PST"); + unpackJava(packFile, pstFile); + verifyJar(goldenFile, pstFile); + pstFile.delete(); + + // repeat the test for unpack200 tool. + istFile = new File("golden.jar.native.IST"); + unpackNative(packFile, istFile); + verifyJar(goldenFile, istFile); + istFile.delete(); + + pstFile = new File("golden.jar.native.PST"); + unpackNative(packFile, pstFile); + verifyJar(goldenFile, pstFile); + pstFile.delete(); + } + + static void unpackNative(File packFile, File outFile) { + String name = outFile.getName(); + String tzname = name.substring(name.lastIndexOf(".") + 1); + HashMap env = new HashMap<>(); + switch(tzname) { + case "PST": + env.put("TZ", "US/Pacific"); + break; + case "IST": + env.put("TZ", "Asia/Calcutta"); + break; + default: + throw new RuntimeException("not implemented: " + tzname); + } + List cmdsList = new ArrayList<>(); + cmdsList.add(Utils.getUnpack200Cmd()); + cmdsList.add(packFile.getName()); + cmdsList.add(outFile.getName()); + Utils.runExec(cmdsList, env); + } + + static void unpackJava(File packFile, File outFile) throws IOException { + String name = outFile.getName(); + String tzname = name.substring(name.lastIndexOf(".") + 1); + JarOutputStream jos = null; + try { + TimeZone.setDefault(TimeZone.getTimeZone(tzname)); + jos = new JarOutputStream(new FileOutputStream(outFile)); + System.out.println("Using timezone: " + TimeZone.getDefault()); + Utils.unpackj(packFile, jos); + } finally { + Utils.close(jos); + TimeZone.setDefault(tz); // always reset + } + } + + static void verifyJar(File f1, File f2) throws IOException { + int errors = 0; + JarFile jf1 = null; + JarFile jf2 = null; + try { + jf1 = new JarFile(f1); + jf2 = new JarFile(f2); + System.out.println("Verifying: " + f1 + " and " + f2); + for (JarEntry je1 : Collections.list(jf1.entries())) { + JarEntry je2 = jf2.getJarEntry(je1.getName()); + if (je1.getTime() != je2.getTime()) { + System.out.println("Error:"); + System.out.println(" expected:" + jf1.getName() + ":" + + je1.getName() + ":" + je1.getTime()); + System.out.println(" obtained:" + jf2.getName() + ":" + + je2.getName() + ":" + je2.getTime()); + errors++; + } + } + } finally { + Utils.close(jf1); + Utils.close(jf2); + } + if (errors > 0) { + throw new RuntimeException("FAIL:" + errors + " error(s) encounted"); + } + } +} diff --git a/jdk/test/tools/pack200/UnpackerMemoryTest.java b/jdk/test/tools/pack200/UnpackerMemoryTest.java new file mode 100644 index 00000000000..fc63d154f90 --- /dev/null +++ b/jdk/test/tools/pack200/UnpackerMemoryTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6531345 + * @summary check for unpacker memory leaks + * @compile -XDignore.symbol.file Utils.java UnpackerMemoryTest.java + * @run main/othervm/timeout=1200 -Xmx32m UnpackerMemoryTest + * @author ksrini + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.io.IOException; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; + +public class UnpackerMemoryTest { + + private static void createPackFile(File packFile) throws IOException { + File tFile = new File("test.dat"); + FileOutputStream fos = null; + PrintStream ps = null; + String jarFileName = Utils.baseName(packFile, Utils.PACK_FILE_EXT) + + Utils.JAR_FILE_EXT; + JarFile jarFile = null; + try { + fos = new FileOutputStream(tFile); + ps = new PrintStream(fos); + ps.println("A quick brown fox"); + Utils.jar("cvf", jarFileName, tFile.getName()); + jarFile = new JarFile(jarFileName); + Utils.pack(jarFile, packFile); + } finally { + Utils.close(ps); + tFile.delete(); + Utils.close(jarFile); + } + } + + public static void main(String[] args) throws Exception { + String name = "foo"; + File packFile = new File(name + Utils.PACK_FILE_EXT); + createPackFile(packFile); + if (!packFile.exists()) { + throw new RuntimeException(packFile + " not found"); + } + File jarOut = new File(name + ".out"); + for (int i = 0; i < 2000; i++) { + JarOutputStream jarOS = null; + FileOutputStream fos = null; + try { + fos = new FileOutputStream(jarOut); + jarOS = new JarOutputStream(fos); + System.out.println("Unpacking[" + i + "]" + packFile); + Utils.unpackn(packFile, jarOS); + } finally { + Utils.close(jarOS); + Utils.close(fos); + } + } + } +} + diff --git a/jdk/test/tools/pack200/Utils.java b/jdk/test/tools/pack200/Utils.java new file mode 100644 index 00000000000..5cf7663d201 --- /dev/null +++ b/jdk/test/tools/pack200/Utils.java @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2007, 2010 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Pack200; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +/** + * + * @author ksrini + */ + +/* + * This class contains all the commonly used utilities used by various tests + * in this directory. + */ +class Utils { + static final String JavaHome = System.getProperty("test.java", + System.getProperty("java.home")); + static final boolean IsWindows = + System.getProperty("os.name").startsWith("Windows"); + static final boolean Is64Bit = + System.getProperty("sun.arch.data.model", "32").equals("64"); + static final File JavaSDK = new File(JavaHome).getParentFile(); + + static final String PACK_FILE_EXT = ".pack"; + static final String JAVA_FILE_EXT = ".java"; + static final String CLASS_FILE_EXT = ".class"; + static final String JAR_FILE_EXT = ".jar"; + + static final File TEST_SRC_DIR = new File(System.getProperty("test.src")); + static final String VERIFIER_DIR_NAME = "pack200-verifier"; + static final File VerifierJar = new File(VERIFIER_DIR_NAME + JAR_FILE_EXT); + + private Utils() {} // all static + + static { + if (!JavaHome.endsWith("jre")) { + throw new RuntimeException("Error: requires an SDK to run"); + } + } + + private static void init() throws IOException { + if (VerifierJar.exists()) { + return; + } + File srcDir = new File(TEST_SRC_DIR, VERIFIER_DIR_NAME); + List javaFileList = findFiles(srcDir, createFilter(JAVA_FILE_EXT)); + File tmpFile = File.createTempFile("javac", ".tmp"); + File classesDir = new File("xclasses"); + classesDir.mkdirs(); + FileOutputStream fos = null; + PrintStream ps = null; + try { + fos = new FileOutputStream(tmpFile); + ps = new PrintStream(fos); + for (File f : javaFileList) { + ps.println(f.getAbsolutePath()); + } + } finally { + close(ps); + close(fos); + } + + compiler("-d", + "xclasses", + "@" + tmpFile.getAbsolutePath()); + + jar("cvfe", + VerifierJar.getName(), + "sun.tools.pack.verify.Main", + "-C", + "xclasses", + "."); + } + + static void dirlist(File dir) { + File[] files = dir.listFiles(); + System.out.println("--listing " + dir.getAbsolutePath() + "---"); + for (File f : files) { + StringBuffer sb = new StringBuffer(); + sb.append(f.isDirectory() ? "d " : "- "); + sb.append(f.getName()); + System.out.println(sb); + } + } + static void doCompareVerify(File reference, File specimen) throws IOException { + init(); + List cmds = new ArrayList(); + cmds.add(getJavaCmd()); + cmds.add("-jar"); + cmds.add(VerifierJar.getName()); + cmds.add(reference.getAbsolutePath()); + cmds.add(specimen.getAbsolutePath()); + cmds.add("-O"); + runExec(cmds); + } + + static void doCompareBitWise(File reference, File specimen) + throws IOException { + init(); + List cmds = new ArrayList(); + cmds.add(getJavaCmd()); + cmds.add("-jar"); + cmds.add(VerifierJar.getName()); + cmds.add(reference.getName()); + cmds.add(specimen.getName()); + cmds.add("-O"); + cmds.add("-b"); + runExec(cmds); + } + + static FileFilter createFilter(final String extension) { + return new FileFilter() { + @Override + public boolean accept(File pathname) { + String name = pathname.getName(); + if (name.endsWith(extension)) { + return true; + } + return false; + } + }; + } + + static final FileFilter DIR_FILTER = new FileFilter() { + public boolean accept(File pathname) { + if (pathname.isDirectory()) { + return true; + } + return false; + } + }; + + static final FileFilter FILE_FILTER = new FileFilter() { + public boolean accept(File pathname) { + if (pathname.isFile()) { + return true; + } + return false; + } + }; + + private static void setFileAttributes(File src, File dst) throws IOException { + dst.setExecutable(src.canExecute()); + dst.setReadable(src.canRead()); + dst.setWritable(src.canWrite()); + dst.setLastModified(src.lastModified()); + } + + static void copyFile(File src, File dst) throws IOException { + if (src.isDirectory()) { + dst.mkdirs(); + setFileAttributes(src, dst); + return; + } else { + File baseDirFile = dst.getParentFile(); + if (!baseDirFile.exists()) { + baseDirFile.mkdirs(); + } + } + FileInputStream in = null; + FileOutputStream out = null; + FileChannel srcChannel = null; + FileChannel dstChannel = null; + try { + in = new FileInputStream(src); + out = new FileOutputStream(dst); + srcChannel = in.getChannel(); + dstChannel = out.getChannel(); + + long retval = srcChannel.transferTo(0, src.length(), dstChannel); + if (src.length() != dst.length()) { + throw new IOException("file copy failed for " + src); + } + } finally { + close(srcChannel); + close(dstChannel); + close(in); + close(out); + } + setFileAttributes(src, dst); + } + + static String baseName(File file, String extension) { + return baseName(file.getAbsolutePath(), extension); + } + + static String baseName(String name, String extension) { + int cut = name.length() - extension.length(); + return name.lastIndexOf(extension) == cut + ? name.substring(0, cut) + : name; + + } + + /* + * Suppose a path is provided which consists of a full path + * this method returns the sub path for a full path ex: /foo/bar/baz/foobar.z + * and the base path is /foo/bar it will will return baz/foobar.z. + */ + private static String getEntryPath(String basePath, String fullPath) { + if (!fullPath.startsWith(basePath)) { + return null; + } + return fullPath.substring(basePath.length()); + } + + static String getEntryPath(File basePathFile, File fullPathFile) { + return getEntryPath(basePathFile.toString(), fullPathFile.toString()); + } + + public static void recursiveCopy(File src, File dest) throws IOException { + if (!src.exists() || !src.canRead()) { + throw new IOException("file not found or readable: " + src); + } + if (dest.exists() && !dest.isDirectory() && !dest.canWrite()) { + throw new IOException("file not found or writeable: " + dest); + } + if (!dest.exists()) { + dest.mkdirs(); + } + List a = directoryList(src); + for (File f : a) { + copyFile(f, new File(dest, getEntryPath(src, f))); + } + } + + static List directoryList(File dirname) { + List dirList = new ArrayList(); + return directoryList(dirname, dirList, null); + } + + private static List directoryList(File dirname, List dirList, + File[] dirs) { + dirList.addAll(Arrays.asList(dirname.listFiles(FILE_FILTER))); + dirs = dirname.listFiles(DIR_FILTER); + for (File f : dirs) { + if (f.isDirectory() && !f.equals(dirname)) { + dirList.add(f); + directoryList(f, dirList, dirs); + } + } + return dirList; + } + + static void recursiveDelete(File dir) throws IOException { + if (dir.isFile()) { + dir.delete(); + } else if (dir.isDirectory()) { + File[] entries = dir.listFiles(); + for (int i = 0; i < entries.length; i++) { + if (entries[i].isDirectory()) { + recursiveDelete(entries[i]); + } + entries[i].delete(); + } + dir.delete(); + } + } + + static List findFiles(File startDir, FileFilter filter) + throws IOException { + List list = new ArrayList(); + findFiles0(startDir, list, filter); + return list; + } + /* + * finds files in the start directory using the the filter, appends + * the files to the dirList. + */ + private static void findFiles0(File startDir, List list, + FileFilter filter) throws IOException { + File[] foundFiles = startDir.listFiles(filter); + list.addAll(Arrays.asList(foundFiles)); + File[] dirs = startDir.listFiles(DIR_FILTER); + for (File dir : dirs) { + findFiles0(dir, list, filter); + } + } + + static void close(Closeable c) { + if (c == null) { + return; + } + try { + c.close(); + } catch (IOException ignore) { + } + } + + static void compiler(String... javacCmds) { + if (com.sun.tools.javac.Main.compile(javacCmds) != 0) { + throw new RuntimeException("compilation failed"); + } + } + + static void jar(String... jargs) { + sun.tools.jar.Main jarTool = + new sun.tools.jar.Main(System.out, System.err, "jartool"); + if (!jarTool.run(jargs)) { + throw new RuntimeException("jar command failed"); + } + } + + // given a jar file foo.jar will write to foo.pack + static void pack(JarFile jarFile, File packFile) throws IOException { + Pack200.Packer packer = Pack200.newPacker(); + Map p = packer.properties(); + // Take the time optimization vs. space + p.put(packer.EFFORT, "1"); // CAUTION: do not use 0. + // Make the memory consumption as effective as possible + p.put(packer.SEGMENT_LIMIT, "10000"); + // ignore all JAR deflation requests to save time + p.put(packer.DEFLATE_HINT, packer.FALSE); + // save the file ordering of the original JAR + p.put(packer.KEEP_FILE_ORDER, packer.TRUE); + FileOutputStream fos = null; + try { + // Write out to a jtreg scratch area + fos = new FileOutputStream(packFile); + // Call the packer + packer.pack(jarFile, fos); + } finally { + close(fos); + } + } + + // uses java unpacker, slow but useful to discover issues with the packer + static void unpackj(File inFile, JarOutputStream jarStream) + throws IOException { + unpack0(inFile, jarStream, true); + + } + + // uses native unpacker using the java APIs + static void unpackn(File inFile, JarOutputStream jarStream) + throws IOException { + unpack0(inFile, jarStream, false); + } + + // given a packed file, create the jar file in the current directory. + private static void unpack0(File inFile, JarOutputStream jarStream, + boolean useJavaUnpack) throws IOException { + // Unpack the files + Pack200.Unpacker unpacker = Pack200.newUnpacker(); + Map props = unpacker.properties(); + if (useJavaUnpack) { + props.put("com.sun.java.util.jar.pack.disable.native", "true"); + } + // Call the unpacker + unpacker.unpack(inFile, jarStream); + } + + static byte[] getBuffer(ZipFile zf, ZipEntry ze) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte buf[] = new byte[8192]; + InputStream is = null; + try { + is = zf.getInputStream(ze); + int n = is.read(buf); + while (n > 0) { + baos.write(buf, 0, n); + n = is.read(buf); + } + return baos.toByteArray(); + } finally { + close(is); + } + } + + static ArrayList getZipFileEntryNames(ZipFile z) { + ArrayList out = new ArrayList(); + for (ZipEntry ze : Collections.list(z.entries())) { + out.add(ze.getName()); + } + return out; + } + static List runExec(List cmdsList) { + return runExec(cmdsList, null); + } + static List runExec(List cmdsList, Map penv) { + ArrayList alist = new ArrayList(); + ProcessBuilder pb = + new ProcessBuilder(cmdsList); + Map env = pb.environment(); + if (penv != null && !penv.isEmpty()) { + env.putAll(penv); + } + pb.directory(new File(".")); + dirlist(new File(".")); + for (String x : cmdsList) { + System.out.print(x + " "); + } + System.out.println(""); + int retval = 0; + Process p = null; + InputStreamReader ir = null; + BufferedReader rd = null; + InputStream is = null; + try { + pb.redirectErrorStream(true); + p = pb.start(); + is = p.getInputStream(); + ir = new InputStreamReader(is); + rd = new BufferedReader(ir, 8192); + + String in = rd.readLine(); + while (in != null) { + alist.add(in); + System.out.println(in); + in = rd.readLine(); + } + retval = p.waitFor(); + if (retval != 0) { + throw new RuntimeException("process failed with non-zero exit"); + } + } catch (Exception ex) { + throw new RuntimeException(ex.getMessage()); + } finally { + close(rd); + close(ir); + close(is); + if (p != null) { + p.destroy(); + } + } + return alist; + } + + static String getUnpack200Cmd() { + return getAjavaCmd("unpack200"); + } + + static String getPack200Cmd() { + return getAjavaCmd("pack200"); + } + + static String getJavaCmd() { + return getAjavaCmd("java"); + } + + static String getAjavaCmd(String cmdStr) { + File binDir = new File(JavaHome, "bin"); + File unpack200File = IsWindows + ? new File(binDir, cmdStr + ".exe") + : new File(binDir, cmdStr); + + String cmd = unpack200File.getAbsolutePath(); + if (!unpack200File.canExecute()) { + throw new RuntimeException("please check" + + cmd + " exists and is executable"); + } + return cmd; + } + + private static List locaterCache = null; + // search the source dir and jdk dir for requested file and returns + // the first location it finds. + static File locateJar(String name) { + try { + if (locaterCache == null) { + locaterCache = new ArrayList(); + locaterCache.addAll(findFiles(TEST_SRC_DIR, createFilter(JAR_FILE_EXT))); + locaterCache.addAll(findFiles(JavaSDK, createFilter(JAR_FILE_EXT))); + } + for (File f : locaterCache) { + if (f.getName().equals(name)) { + return f; + } + } + throw new IOException("file not found: " + name); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/data/README b/jdk/test/tools/pack200/pack200-verifier/data/README new file mode 100644 index 00000000000..64278ab13d6 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/data/README @@ -0,0 +1,45 @@ +The files contained in the golden.jar have been harvested from many +different sources, some are hand-crafted invalid class files (odds directory), +or from random JDK builds. + +Generally these files serve to ensure the integrity of the packer and unpacker +by, + 1. maximizing the test coverage. + 2. exercising all the Bands in the pack200 specification. + 2. testing the behavior of the packer with invalid classes. + 3. testing the archive integrity, ordering and description (date, sizes, + CRC etc.) + +Build: +To rebuild this JAR follow these steps: + 1. unzip the golden.jar to some directory lets call it "example" + 2. now we can add any directories with files into example. + 2. run the script BUILDME.sh as + % sh BUILDME.sh example + +Note: the BUILDME.sh is known to work on all Unix platforms as well as Windows + using Cygwin. + +The above will create two JAR files in the current directory, +example.jar and example-cls.jar, now the example.jar can be used as the +golden.jar. + +To ensure the JAR has been built correctly use jar -tvf and compare the +results of the old jar and the newly built one, note that the compressed sizes +may differ, however the timestamps etc. should be consistent. + +Test: + Basic: + % pack200 --repack test.jar golden.jar + + Advanced: + Create a pack.conf as follows: + % cat pack.conf + com.sun.java.util.jar.pack.dump.bands=true + + % pack200 --no-gzip --config-file=pack.conf \ + --verbose golden.jar.pack golden.jar + + This command will dump the Bands in a unique directory BD_XXXXXX, + one can inspect the directory to ensure all of the bands are being + generated. Familiarity of the Pack200 specification is suggested. \ No newline at end of file diff --git a/jdk/test/tools/pack200/pack200-verifier/data/golden.jar b/jdk/test/tools/pack200/pack200-verifier/data/golden.jar new file mode 100644 index 00000000000..53b77c41dac Binary files /dev/null and b/jdk/test/tools/pack200/pack200-verifier/data/golden.jar differ diff --git a/jdk/test/tools/pack200/pack200-verifier/make/build.xml b/jdk/test/tools/pack200/pack200-verifier/make/build.xml new file mode 100644 index 00000000000..76e5f72cf89 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/make/build.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java new file mode 100644 index 00000000000..63a66f765d6 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.tools.pack.verify; + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import xmlkit.*; + +public class ClassCompare { + + /* + * @author ksrini + */ + private static XMLKit.Element getXMLelement(InputStream is, + boolean ignoreUnkAttrs, + List ignoreElements) throws IOException { + + ClassReader cr = new ClassReader(); + cr.keepOrder = false; + XMLKit.Element e = cr.readFrom(is); + + if (ignoreElements != null) { + XMLKit.Filter filter = XMLKit.elementFilter(ignoreElements); + e.removeAllInTree(filter); + } + + if (ignoreUnkAttrs == true) { + // This removes any unknown attributes + e.removeAllInTree(XMLKit.elementFilter("Attribute")); + } + return e; + } + + private static String getXMLPrettyString(XMLKit.Element e) throws IOException { + StringWriter out = new StringWriter(); + e.writePrettyTo(out); + return out.toString(); + } + + private static boolean compareClass0(JarFile jf1, JarFile jf2, + JarEntry je, boolean ignoreUnkAttrs, + List ignoreElements) + throws IOException { + + InputStream is1 = jf1.getInputStream(je); + InputStream is2 = jf2.getInputStream(je); + + // First we try to compare the bits if they are the same + boolean bCompare = JarFileCompare.compareStreams(is1, is2); + + // If they are the same there is nothing more to do. + if (bCompare) { + Globals.println("+++" + je.getName() + "+++\t" + + "b/b:PASS"); + return bCompare; + } + is1.close(); + is2.close(); + + is1 = jf1.getInputStream(je); + is2 = jf2.getInputStream(je); + + + XMLKit.Element e1 = getXMLelement(is1, ignoreUnkAttrs, ignoreElements); + XMLKit.Element e2 = getXMLelement(is2, ignoreUnkAttrs, ignoreElements); + + Globals.print("+++" + je.getName() + "+++\t" + + e1.size() + "/" + e1.size() + ":"); + + boolean result = true; + + if (e1.equals(e2)) { + Globals.println("PASS"); + } else { + Globals.println("FAIL"); + Globals.log("Strings differs"); + Globals.log(getXMLPrettyString(e1)); + Globals.log("----------"); + Globals.log(getXMLPrettyString(e2)); + result = false; + } + return result; + } + + /* + * Given two Class Paths could be jars the first being a reference + * will execute a series of comparisons on the classname specified + * The className could be null in which case it will iterate through + * all the classes, otherwise it will compare one class and exit. + */ + public static boolean compareClass(String jar1, String jar2, + String className, boolean ignoreUnkAttrs, + List ignoreElements) + throws IOException { + + Globals.println("Unknown attributes ignored:" + ignoreUnkAttrs); + if (ignoreElements != null) { + Globals.println(ignoreElements.toString()); + } + + JarFile jf1 = new JarFile(jar1); + JarFile jf2 = new JarFile(jar2); + + boolean result = true; + + if (className == null) { + for (JarEntry je1 : Collections.list((Enumeration) jf1.entries())) { + if (je1.getName().endsWith(".class")) { + JarEntry je2 = jf2.getJarEntry(je1.getName()); + boolean pf = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements); + if (result == true) { + result = pf; + } + } + } + } else { + JarEntry je1 = jf1.getJarEntry(className); + result = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements); + } + if (result == false) { + throw new RuntimeException("Class structural comparison failure"); + } + return result; + } + + public static boolean compareClass(String jar1, String jar2, + String className) throws IOException { + + Stack s = new Stack(); + if (Globals.ignoreDebugAttributes()) { + s = new Stack(); + s.push("LocalVariable"); + s.push("LocalVariableType"); + s.push("LineNumber"); + s.push("SourceFile"); + } + return compareClass(jar1, jar2, className, Globals.ignoreUnknownAttributes(), s); + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java new file mode 100644 index 00000000000..2a51474bfde --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * A collection of useful global utilities commonly used. + */ +package sun.tools.pack.verify; + +import java.io.*; +import java.util.*; + +/* + * @author ksrini + */ + +class Globals { + + private static int errors = 0; + private static PrintWriter _pw = null; + private static String _logFileName = null; + private static final String DEFAULT_LOG_FILE = "verifier.log"; + private static boolean _verbose = true; + private static boolean _ignoreJarDirectories = false; + private static boolean _checkJarClassOrdering = true; + private static boolean _bitWiseClassCompare = false; + // Ignore Deprecated, SourceFile and Synthetic + private static boolean _ignoreCompileAttributes = false; + // Ignore Debug Attributes LocalVariableTable, LocalVariableType,LineNumberTable + private static boolean _ignoreDebugAttributes = false; + private static boolean _ignoreUnknownAttributes = false; + private static boolean _validateClass = true; + private static Globals _instance = null; + + static Globals getInstance() { + if (_instance == null) { + _instance = new Globals(); + _verbose = (System.getProperty("sun.tools.pack.verify.verbose") == null) + ? false : true; + _ignoreJarDirectories = (System.getProperty("ignoreJarDirectories") == null) + ? false : true; + } + return _instance; + } + + static boolean ignoreCompileAttributes() { + return _ignoreCompileAttributes; + } + + static boolean ignoreDebugAttributes() { + return _ignoreDebugAttributes; + } + + static boolean ignoreUnknownAttributes() { + return _ignoreUnknownAttributes; + } + + static boolean ignoreJarDirectories() { + return _ignoreJarDirectories; + } + + static boolean validateClass() { + return _validateClass; + } + + static void setCheckJarClassOrdering(boolean flag) { + _checkJarClassOrdering = flag; + } + + static boolean checkJarClassOrdering() { + return _checkJarClassOrdering; + } + + static boolean bitWiseClassCompare() { + return _bitWiseClassCompare; + } + + static boolean setBitWiseClassCompare(boolean flag) { + return _bitWiseClassCompare = flag; + } + + public static boolean setIgnoreCompileAttributes(boolean flag) { + return _ignoreCompileAttributes = flag; + } + + static boolean setIgnoreDebugAttributes(boolean flag) { + return _ignoreDebugAttributes = flag; + } + + static boolean setIgnoreUnknownAttributes(boolean flag) { + return _ignoreUnknownAttributes = flag; + } + + static boolean setValidateClass(boolean flag) { + return _validateClass = flag; + } + + static int getErrors() { + return errors; + } + + static void trace(String s) { + if (_verbose) { + println(s); + } + } + + static void print(String s) { + _pw.print(s); + } + + static void println(String s) { + _pw.println(s); + } + + static void log(String s) { + errors++; + _pw.println("ERROR:" + s); + } + + static void lognoln(String s) { + errors++; + _pw.print(s); + } + + private static PrintWriter openFile(String fileName) { + //Lets create the directory if it does not exist. + File f = new File(fileName); + File baseDir = f.getParentFile(); + if (baseDir != null && baseDir.exists() == false) { + baseDir.mkdirs(); + } + try { + return new PrintWriter(new FileWriter(f), true); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void closeFile() { + _pw.flush(); + _pw.close(); + } + + static void printPropsToLog() { + println("Log started " + new Date(System.currentTimeMillis())); + print(System.getProperty("java.vm.version")); + println("\t" + System.getProperty("java.vm.name")); + + println("System properties"); + println("\tjava.home=" + System.getProperty("java.home")); + println("\tjava.class.version=" + System.getProperty("java.class.version")); + println("\tjava.class.path=" + System.getProperty("java.class.path")); + println("\tjava.ext.dirs=" + System.getProperty("java.ext.dirs")); + println("\tos.name=" + System.getProperty("os.name")); + println("\tos.arch=" + System.getProperty("os.arch")); + println("\tos.version=" + System.getProperty("os.version")); + println("\tuser.name=" + System.getProperty("user.name")); + println("\tuser.home=" + System.getProperty("user.home")); + println("\tuser.dir=" + System.getProperty("user.dir")); + println("\tLocale.getDefault=" + Locale.getDefault()); + println("System properties end"); + } + + static void openLog(String s) { + _logFileName = (s != null) ? s : "." + File.separator + DEFAULT_LOG_FILE; + _logFileName = (new File(_logFileName).isDirectory()) + ? _logFileName + File.separator + DEFAULT_LOG_FILE : _logFileName; + _pw = openFile(_logFileName); + printPropsToLog(); + } + + static void closeLog() { + closeFile(); + } + + static String getLogFileName() { + return _logFileName; + } + + static void diffCharData(String s1, String s2) { + boolean diff = false; + char[] c1 = s1.toCharArray(); + char[] c2 = s2.toCharArray(); + if (c1.length != c2.length) { + diff = true; + Globals.log("Length differs: " + (c1.length - c2.length)); + } + // Take the smaller of the two arrays to prevent Array...Exception + int minlen = (c1.length < c2.length) ? c1.length : c2.length; + for (int i = 0; i < c1.length; i++) { + if (c1[i] != c2[i]) { + diff = true; + Globals.lognoln("\t idx[" + i + "] 0x" + Integer.toHexString(c1[i]) + "<>" + "0x" + Integer.toHexString(c2[i])); + Globals.log(" -> " + c1[i] + "<>" + c2[i]); + } + } + } + + static void diffByteData(String s1, String s2) { + boolean diff = false; + byte[] b1 = s1.getBytes(); + byte[] b2 = s2.getBytes(); + + if (b1.length != b2.length) { + diff = true; + //(+) b1 is greater, (-) b2 is greater + Globals.log("Length differs diff: " + (b1.length - b2.length)); + } + // Take the smaller of the two array to prevent Array...Exception + int minlen = (b1.length < b2.length) ? b1.length : b2.length; + for (int i = 0; i < b1.length; i++) { + if (b1[i] != b2[i]) { + diff = true; + Globals.log("\t" + "idx[" + i + "] 0x" + Integer.toHexString(b1[i]) + "<>" + "0x" + Integer.toHexString(b2[i])); + } + } + } + + static void dumpToHex(String s) { + try { + dumpToHex(s.getBytes("UTF-8")); + } catch (UnsupportedEncodingException uce) { + throw new RuntimeException(uce); + } + } + + static void dumpToHex(byte[] buffer) { + int linecount = 0; + byte[] b = new byte[16]; + for (int i = 0; i < buffer.length; i += 16) { + if (buffer.length - i > 16) { + System.arraycopy(buffer, i, b, 0, 16); + print16Bytes(b, linecount); + linecount += 16; + } else { + System.arraycopy(buffer, i, b, 0, buffer.length - i); + for (int n = buffer.length - (i + 1); n < 16; n++) { + b[n] = 0; + } + print16Bytes(b, linecount); + linecount += 16; + } + } + Globals.log("-----------------------------------------------------------------"); + } + + static void print16Bytes(byte[] buffer, int linecount) { + final int MAX = 4; + Globals.lognoln(paddedHexString(linecount, 4) + " "); + + for (int i = 0; i < buffer.length; i += 2) { + int iOut = pack2Bytes2Int(buffer[i], buffer[i + 1]); + Globals.lognoln(paddedHexString(iOut, 4) + " "); + } + + Globals.lognoln("| "); + + StringBuilder sb = new StringBuilder(new String(buffer)); + + for (int i = 0; i < buffer.length; i++) { + if (Character.isISOControl(sb.charAt(i))) { + sb.setCharAt(i, '.'); + } + } + Globals.log(sb.toString()); + } + + static int pack2Bytes2Int(byte b1, byte b2) { + int out = 0x0; + out += b1; + out <<= 8; + out &= 0x0000ffff; + out |= 0x000000ff & b2; + return out; + } + + static String paddedHexString(int n, int max) { + char[] c = Integer.toHexString(n).toCharArray(); + char[] out = new char[max]; + + for (int i = 0; i < max; i++) { + out[i] = '0'; + } + int offset = (max - c.length < 0) ? 0 : max - c.length; + for (int i = 0; i < c.length; i++) { + out[offset + i] = c[i]; + } + return new String(out); + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java new file mode 100644 index 00000000000..419fda1ba23 --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package sun.tools.pack.verify; + +import java.io.*; +import java.util.*; +import java.util.jar.*; + +class JarFileCompare { + /* + * @author ksrini + */ + + private static VerifyTreeSet getVerifyTreeSet(String jarPath) { + VerifyTreeSet vts = new VerifyTreeSet(); + try { + JarFile j = new JarFile(jarPath); + for (JarEntry je : Collections.list((Enumeration) j.entries())) { + if (!je.isDirectory()) { // totally ignore directories + vts.add(je.getName()); + } + } + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + return vts; + } + + private static LinkedList getListOfClasses(String jarPath) { + LinkedList l = new LinkedList(); + try { + JarFile j = new JarFile(jarPath); + for (JarEntry je : Collections.list((Enumeration) j.entries())) { + if (!je.isDirectory() && je.getName().endsWith(".class")) { + l.add(je.getName()); + } + } + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + return l; + } + + private static void jarDirectoryCompare(String jarPath1, String jarPath2) { + VerifyTreeSet vts1 = getVerifyTreeSet(jarPath1); + VerifyTreeSet vts2 = getVerifyTreeSet(jarPath2); + + TreeSet diff1 = vts1.diff(vts2); + if (diff1.size() > 0) { + Globals.log("Left has the following entries that right does not have"); + Globals.log(diff1.toString()); + } + TreeSet diff2 = vts2.diff(vts1); + if (diff2.size() > 0) { + Globals.log("Right has the following entries that left does not have"); + Globals.log(diff2.toString()); + } + if (Globals.checkJarClassOrdering()) { + boolean error = false; + Globals.println("Checking Class Ordering"); + LinkedList l1 = getListOfClasses(jarPath1); + LinkedList l2 = getListOfClasses(jarPath2); + if (l1.size() != l2.size()) { + error = true; + Globals.log("The number of classes differs"); + Globals.log("\t" + l1.size() + "<>" + l2.size()); + } + for (int i = 0; i < l1.size(); i++) { + String s1 = (String) l1.get(i); + String s2 = (String) l2.get(i); + if (s1.compareTo(s2) != 0) { + error = true; + Globals.log("Ordering differs at[" + i + "] = " + s1); + Globals.log("\t" + s2); + } + } + } + } + + /* + * Returns true if the two Streams are bit identical, and false if they + * are not, no further diagnostics + */ + static boolean compareStreams(InputStream is1, InputStream is2) { + + BufferedInputStream bis1 = new BufferedInputStream(is1, 8192); + BufferedInputStream bis2 = new BufferedInputStream(is2, 8192); + try { + int i1, i2; + int count = 0; + while ((i1 = bis1.read()) == (i2 = bis2.read())) { + count++; + if (i1 < 0) { + // System.out.println("bytes read " + count); + return true; // got all the way to EOF + } + } + return false; // reads returned dif + + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + + private static void checkEntry(JarFile jf1, JarFile jf2, JarEntry je) throws IOException { + InputStream is1 = jf1.getInputStream(je); + InputStream is2 = jf2.getInputStream(je); + if (is1 != null && is2 != null) { + if (!compareStreams(jf1.getInputStream(je), jf2.getInputStream(je))) { + Globals.println("+++" + je.getName() + "+++"); + Globals.log("Error: File:" + je.getName() + + " differs, use a diff util for further diagnostics"); + } + } else { + Globals.println("+++" + je.getName() + "+++"); + Globals.log("Error: File:" + je.getName() + " not found in " + jf2.getName()); + } + } + + /* + * Given two jar files we compare and see if the jarfiles have all the + * entries. The property ignoreJarDirectories is set to true by default + * which means that Directory entries in a jar may be ignore. + */ + static void jarCompare(String jarPath1, String jarPath2) { + jarDirectoryCompare(jarPath1, jarPath2); + + try { + JarFile jf1 = new JarFile(jarPath1); + JarFile jf2 = new JarFile(jarPath2); + + int nclasses = 0; + int nentries = 0; + int entries_checked = 0; + int classes_checked = 0; + + for (JarEntry je : Collections.list((Enumeration) jf1.entries())) { + if (!je.isDirectory() && !je.getName().endsWith(".class")) { + nentries++; + } else if (je.getName().endsWith(".class")) { + nclasses++; + } + } + + for (JarEntry je : Collections.list((Enumeration) jf1.entries())) { + if (je.isDirectory()) { + continue; // Ignore directories + } + if (!je.getName().endsWith(".class")) { + entries_checked++; + if (je.getName().compareTo("META-INF/MANIFEST.MF") == 0) { + Manifest mf1 = new Manifest(jf1.getInputStream(je)); + Manifest mf2 = new Manifest(jf2.getInputStream(je)); + if (!mf1.equals(mf2)) { + Globals.log("Error: Manifests differ"); + Globals.log("Manifest1"); + Globals.log(mf1.getMainAttributes().entrySet().toString()); + Globals.log("Manifest2"); + Globals.log(mf2.getMainAttributes().entrySet().toString()); + } + } else { + checkEntry(jf1, jf2, je); + } + } else if (Globals.bitWiseClassCompare() == true) { + checkEntry(jf1, jf2, je); + classes_checked++; + } + } + if (Globals.bitWiseClassCompare()) { + Globals.println("Class entries checked (byte wise)/Total Class entries = " + + classes_checked + "/" + nclasses); + } + Globals.println("Non-class entries checked/Total non-class entries = " + + entries_checked + "/" + nentries); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } +} diff --git a/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java new file mode 100644 index 00000000000..481c67b15ce --- /dev/null +++ b/jdk/test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +// The Main Entry point +package sun.tools.pack.verify; + +import java.io.*; + +/** + * This class provides a convenient entry point to the pack200 verifier. This + * compares two classes, either in path or in an archive. + * @see xmlkit.XMLKit + * @author ksrini + */ +public class Main { + + private static void syntax() { + System.out.println("Usage: "); + System.out.println("\tREFERENCE_CLASSPATH COMPARED_CLASSPATH [Options]"); + System.out.println("\tOptions:"); + System.out.println("\t\t-O check jar ordering"); + System.out.println("\t\t-C ignore compile attributes (Deprecated, SourceFile, Synthetic, )"); + System.out.println("\t\t-D ignore debug attributes (LocalVariable, LineNumber)"); + System.out.println("\t\t-u ignore unknown attributes"); + System.out.println("\t\t-V turn off class validation"); + System.out.println("\t\t-c CLASS, compare CLASS only"); + System.out.println("\t\t-b Compares all entries bitwise only"); + System.out.println("\t\t-l Directory or Log File Name"); + } + + /** + * main entry point to the class file comparator, which compares semantically + * class files in a classpath or an archive. + * @param args String array as described below + * @throws RuntimeException + *

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