diff --git a/make/Makefile b/make/Makefile index c78e4c27e01bde63bb50a6b6f2d17c257cc9e754..04c5a563ee719a83627d57de500d5a41debc648d 100644 --- a/make/Makefile +++ b/make/Makefile @@ -74,6 +74,7 @@ import -- copy in the pre-built components (e.g. VM) \n\ import_product -- copy in the product components \n\ import_fastdebug -- copy in the fastdebug components \n\ import_debug -- copy in the debug components \n\ +modules -- build the jdk and jre module images (experimental) \n\ sccs_get -- make sure all SCCS files are up-to-date (need SCCS) \n\ create_links -- create softlinks in Solaris 32bit build to 64bit dirs \n\ " @@ -257,6 +258,7 @@ docs:: sanity-docs post-sanity-docs # Release engineering targets. # include $(BUILDDIR)/common/Release.gmk +include $(BUILDDIR)/common/Modules.gmk # # Cscope targets. diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk new file mode 100644 index 0000000000000000000000000000000000000000..d277a11920a0f7033d1e3c75820afa17bd8df776 --- /dev/null +++ b/make/common/Modules.gmk @@ -0,0 +1,442 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +JDK_MODULE_IMAGE_DIR = $(ABS_OUTPUTDIR)/jdk-module-image +JRE_MODULE_IMAGE_DIR = $(ABS_OUTPUTDIR)/jre-module-image + +# +# modules Target to build jdk and jre module image +# +# There is one jar file per module containing classes only. +# All module jars are currently placed under jre/lib directory. +# +# Open issues that need further investigation: +# 1. Classes in jre/lib/ext/dnsns.jar are currently put in jre/lib/jndi-dns +# module. +# 2. Signed jars +# For JDK build, signed jars are copied to the build. +# All jars in the module image are unsigned. +# 3. jre/lib/security/US_export_policy.jar and local_policy.jar +# are not included in the module image yet. + +MODULE_IMAGEBINDIR = bin + +# +# Targets. +# +INITIAL_MODULE_IMAGE_JRE=initial-module-image-jre +INITIAL_MODULE_IMAGE_JDK=initial-module-image-jdk +ifeq ($(PLATFORM), solaris) + ifeq ($(ARCH_DATA_MODEL), 64) + INITIAL_MODULE_IMAGE_JRE=initial-module-image-jre-sol64 + INITIAL_MODULE_IMAGE_JDK=initial-module-image-jdk-sol64 + endif +endif + +modules modules-clobber \ +initial-module-image-jre initial-module-image-jdk \ +initial-module-image-jre-sol64 initial-module-image-jdk-sol64 \ +trim-module-image-jre trim-module-image-jdk \ +process-module-image-jre process-module-image-jdk :: + @$(ECHO) ">>>Making "$@" @ `$(DATE)` ..." + +# Order is important here, trim jre after jdk image is created +modules:: sanity-module-images post-sanity-module-images \ + $(INITIAL_MODULE_IMAGE_JRE) $(INITIAL_MODULE_IMAGE_JDK) \ + trim-module-image-jre trim-module-image-jdk \ + process-module-image-jre process-module-image-jdk + +# Don't use these +module-image-jre:: initial-module-image-jre trim-module-image-jre process-module-image-jre +module-image-jdk:: initial-module-image-jdk trim-module-image-jdk process-module-image-jdk + +# +# Paths to these files we need +JDK_MODULE_LICENSES = $(LICENSE_DOCLIST_JDK:%=$(JDK_MODULE_IMAGE_DIR)/%) +JDK_MODULE_64_LICENSES = $(LICENSE_DOCLIST_JDK:%=$(JDK_MODULE_IMAGE_DIR)/%64) +JDK_MODULE_DOCFILES = $(OTHER_DOCLIST_JDK:%=$(JDK_MODULE_IMAGE_DIR)/%) + +JRE_MODULE_LICENSES = $(LICENSE_DOCLIST_JRE:%=$(JRE_MODULE_IMAGE_DIR)/%) +JRE_MODULE_64_LICENSES = $(LICENSE_DOCLIST_JRE:%=$(JRE_MODULE_IMAGE_DIR)/%64) +JRE_MODULE_DOCFILES = $(OTHER_DOCLIST_JRE:%=$(JRE_MODULE_IMAGE_DIR)/%) +JRE_MODULE_DOCFILES += $(JRE_NAMECHANGE_DOCLIST:%=$(JRE_MODULE_IMAGE_DIR)/%$(TEXT_SUFFIX)) + +###### RULES + +# JDK files +$(JDK_MODULE_IMAGE_DIR)/%: $(SHARE_JDK_DOC_SRC)/% + $(process-doc-file) +# Removes LICENSE_VERSION or not +ifdef LICENSE_VERSION +$(JDK_MODULE_IMAGE_DIR)/%: $(SHARE_JDK_DOC_SRC)/%$(LICENSE_VERSION) + $(process-doc-file) +$(JDK_MODULE_IMAGE_DIR)/%64: $(SHARE_JDK_DOC_SRC)/%$(LICENSE_VERSION) + $(process-doc-file) +else +$(JDK_MODULE_IMAGE_DIR)/%64: $(SHARE_JDK_DOC_SRC)/% + $(process-doc-file) +endif + +# JRE files +$(JRE_MODULE_IMAGE_DIR)/%: $(SHARE_JRE_DOC_SRC)/% + $(process-doc-file) +# Add $(TEXT_SUFFIX) suffix +ifdef TEXT_SUFFIX +$(JRE_MODULE_IMAGE_DIR)/%$(TEXT_SUFFIX): $(SHARE_JRE_DOC_SRC)/% + $(process-doc-file) +endif +# Removes LICENSE_VERSION or not +ifdef LICENSE_VERSION +$(JRE_MODULE_IMAGE_DIR)/%: $(SHARE_JRE_DOC_SRC)/%$(LICENSE_VERSION) + $(process-doc-file) +$(JRE_MODULE_IMAGE_DIR)/%64: $(SHARE_JRE_DOC_SRC)/%$(LICENSE_VERSION) + $(process-doc-file) +else +$(JRE_MODULE_IMAGE_DIR)/%64: $(SHARE_JRE_DOC_SRC)/% + $(process-doc-file) +endif + +###################################################### +# JRE Image +###################################################### + +MODULES_TEMPDIR=$(ABS_TEMPDIR)/modules +MODULES_LIB = $(ABS_OUTPUTDIR)/modules + +gen-modules: + $(CD) modules; $(MAKE) all + +initial-module-image-jre-setup: + $(RM) -r $(JRE_MODULE_IMAGE_DIR) + $(MKDIR) -p $(JRE_MODULE_IMAGE_DIR) + +# 64-bit solaris jre image contains only the 64-bit add-on files. +initial-module-image-jre-sol64:: initial-module-image-jre-setup \ + $(JRE_MODULE_LICENSES) $(JRE_MODULE_64_LICENSES) + @# Use tar instead of cp to preserve the symbolic links + for dir in bin lib ; do \ + ( $(CD) $(OUTPUTDIR) && \ + $(TAR) cf - `$(FIND) $$dir -name '$(ARCH)' -print` | \ + ($(CD) $(JRE_MODULE_IMAGE_DIR) && $(TAR) xf -) ) ; \ + done + @# Remove some files from the jre area + for t in $(NOTJRETOOLS) ; do \ + $(RM) $(JRE_MODULE_IMAGE_DIR)/bin$(ISA_DIR)/$$t ; \ + done + $(RM) `$(FIND) $(JRE_MODULE_IMAGE_DIR)/lib -name 'orb.idl'` + $(RM) `$(FIND) $(JRE_MODULE_IMAGE_DIR)/lib -name 'ir.idl'` + +# Construct an initial jre image (initial jdk jre) no trimming or stripping +initial-module-image-jre:: initial-module-image-jre-setup \ + $(JRE_LICENSES) $(JRE_MODULE_DOCFILES) \ + gen-modules \ + $(BUILDMETAINDEX_JARFILE) + @# Copy in bin directory + $(CD) $(OUTPUTDIR) && $(FIND) bin -depth | $(CPIO) -pdum $(JRE_MODULE_IMAGE_DIR) + @# CTE plugin security change require new empty directory lib/applet + $(MKDIR) -p $(JRE_MODULE_IMAGE_DIR)/lib/applet + @# Copy files but not .jar in lib directory + $(CD) $(OUTPUTDIR) && $(FIND) lib -depth | $(EGREP) -v ".jar$$" | $(CPIO) -pdum $(JRE_MODULE_IMAGE_DIR) + @# + @# copy modules to jre/lib + @# + $(CP) -rf $(MODULES_LIB)/jre/lib/* $(JRE_MODULE_IMAGE_DIR)/lib + @# Make sure all directories are read/execute for everyone + $(CHMOD) a+rx `$(FIND) $(JRE_MODULE_IMAGE_DIR) -type d` + @# Remove some files from the jre area + for t in $(NOTJRETOOLS) ; do \ + $(RM) $(JRE_MODULE_IMAGE_DIR)/bin$(ISA_DIR)/$$t ; \ + done + @# Remove orb.idl and ir.idl from jre + $(FIND) $(JRE_MODULE_IMAGE_DIR)/lib -name 'orb.idl' -exec $(RM) \{} \; + $(FIND) $(JRE_MODULE_IMAGE_DIR)/lib -name 'ir.idl' -exec $(RM) \{} \; + @# Generate meta-index to make boot and extension class loaders lazier + $(CD) $(JRE_MODULE_IMAGE_DIR)/lib && \ + $(BOOT_JAVA_CMD) -jar $(BUILDMETAINDEX_JARFILE) \ + -o meta-index *.jar + @$(CD) $(JRE_MODULE_IMAGE_DIR)/lib && $(java-vm-cleanup) + $(CD) $(JRE_MODULE_IMAGE_DIR)/lib/ext && \ + $(BOOT_JAVA_CMD) -jar $(BUILDMETAINDEX_JARFILE) \ + -o meta-index *.jar + @$(CD) $(JRE_MODULE_IMAGE_DIR)/lib/ext && $(java-vm-cleanup) +ifeq ($(PLATFORM), windows) + @# Remove certain *.lib files + $(CD) $(JRE_MODULE_IMAGE_DIR)/lib && \ + $(RM) java.$(LIB_SUFFIX) jvm.$(LIB_SUFFIX) \ + hpi.$(LIB_SUFFIX) awt.$(LIB_SUFFIX) jawt.$(LIB_SUFFIX) + ifeq ($(ARCH_DATA_MODEL), 32) + @# The Java Kernel JRE image ships with a special VM. It is not included + @# in the full JRE image, so remove it. Also, is it only for 32-bit windows. + $(CD) $(JRE_MODULE_IMAGE_DIR)/bin && $(RM) -r kernel + endif +endif # Windows +ifneq ($(PLATFORM), windows) + $(call copy-man-pages,$(JRE_MODULE_IMAGE_DIR),$(JRE_MAN_PAGES)) +endif # !windows + +# Trim out any extra files not for the jre shipment but wanted in the jdk jre. +# (Note the jdk WILL want the jre image before this trimming) +# Removes server VM on Windows 32bit. +# Remove certain shared libraries that should not be in the jre image +# but should be in the jdk jre image. +trim-module-image-jre:: +ifeq ($(PLATFORM), windows) + ifeq ($(ARCH_DATA_MODEL), 32) + $(RM) -r $(JRE_MODULE_IMAGE_DIR)/bin/server + endif + ifdef NOTJRE_SHARED_LIBS + for l in $(NOTJRE_SHARED_LIBS) ; do \ + $(RM) $(JRE_MODULE_IMAGE_DIR)/bin/$$l ; \ + done ; + endif +else # PLATFORM + ifdef NOTJRE_SHARED_LIBS + for l in $(NOTJRE_SHARED_LIBS) ; do \ + $(RM) $(JRE_MODULE_IMAGE_DIR)/lib/$(LIBARCH)/$$l ; \ + done ; + endif +endif # PLATFORM + +# Get list of all Elf files in the jre +JRE_MODULE_ELF_LIST=$(MODULES_TEMPDIR)/jre-elf-files.list +$(JRE_MODULE_ELF_LIST): + @$(prep-target) +ifneq ($(PLATFORM), windows) + $(RM) $@ + $(FIND) $(JRE_MODULE_IMAGE_DIR)/lib -type f -name \*.$(LIB_SUFFIX) >> $@ + $(FILE) `$(FIND) $(JRE_MODULE_IMAGE_DIR)/bin -type f -name \*$(EXE_SUFFIX)` \ + | $(EGREP) 'ELF' | $(CUT) -d':' -f1 >> $@ +endif + +# Post process the image (strips and mcs on Elf files we are shipping) +# (Note the jdk WILL want the jre image before this processing) +process-module-image-jre:: $(JRE_MODULE_ELF_LIST) +ifneq ($(POST_STRIP_PROCESS), ) + for f in `$(CAT) $(JRE_MODULE_ELF_LIST)`; do \ + $(CHMOD) u+w $${f}; \ + $(ECHO) $(POST_STRIP_PROCESS) $${f}; \ + $(POST_STRIP_PROCESS) $${f}; \ + $(CHMOD) go-w $${f}; \ + done +endif +ifneq ($(POST_MCS_PROCESS), ) + for f in `$(CAT) $(JRE_MODULE_ELF_LIST)`; do \ + $(CHMOD) u+w $${f}; \ + $(ECHO) $(POST_MCS_PROCESS) $${f}; \ + $(POST_MCS_PROCESS) $${f}; \ + $(CHMOD) go-w $${f}; \ + done +endif + $(RM) $(JRE_MODULE_ELF_LIST) + +###################################################### +# JDK Image +###################################################### +# Note: cpio ($(CPIO)) sometimes leaves directories without rx access. + +initial-module-image-jdk-setup: + $(RM) -r $(JDK_MODULE_IMAGE_DIR) + $(MKDIR) -p $(JDK_MODULE_IMAGE_DIR)/jre + ($(CD) $(JRE_MODULE_IMAGE_DIR) && $(FIND) . -depth -print \ + | $(CPIO) -pdum $(JDK_MODULE_IMAGE_DIR)/jre ) + $(RM) -rf $(JDK_MODULE_IMAGE_DIR)/jre/man + $(CHMOD) a+rx `$(FIND) $(JDK_MODULE_IMAGE_DIR) -type d` + +initial-module-image-jdk64-bindemos: + for dir in bin demo ; do \ + ( $(CD) $(OUTPUTDIR) && \ + $(TAR) cf - `$(FIND) $$dir -name '$(LIBARCH)' -print` | \ + ($(CD) $(JDK_MODULE_IMAGE_DIR) && $(TAR) xf -) ) ; \ + done + +# Solaris 64 bit image is special +initial-module-image-jdk-sol64:: initial-module-image-jdk-setup \ + initial-module-image-jdk64-bindemos \ + $(JDK_MODULE_LICENSES) $(JDK_MODULARLIZED_64_LICENSES) + +# DB files to add +ifeq ($(OPENJDK),true) + +initial-module-image-jdk-db: + +else + +# Create the list of db *.zip files to bundle with jdk +ABS_DB_PATH :=$(call FullPath,$(CLOSED_SHARE_SRC)/db) +DB_ZIP_LIST = $(shell $(LS) $(ABS_DB_PATH)/*.zip 2>/dev/null) + +initial-module-image-jdk-db: $(DB_ZIP_LIST) + $(MKDIR) -p $(JDK_MODULE_IMAGE_DIR)/db + for d in $(DB_ZIP_LIST); do \ + ($(CD) $(JDK_MODULE_IMAGE_DIR)/db && $(UNZIP) -o $$d); \ + done + +endif + +# Standard jdk image +initial-module-image-jdk:: initial-module-image-jdk-setup \ + initial-module-image-jdk-db \ + $(JDK_MODULE_LICENSES) $(JDK_MODULE_DOCFILES) + $(MKDIR) $(JDK_MODULE_IMAGE_DIR)/lib + @# + @# copy jdk modules to jdk/lib + @# + $(MKDIR) -p $(JDK_MODULE_IMAGE_DIR)/lib + $(CP) -rf $(MODULES_LIB)/lib/* $(JDK_MODULE_IMAGE_DIR)/lib + ifeq ($(PLATFORM), windows) + @# + @# lib/ + @# + $(CP) $(LIBDIR)/$(LIB_PREFIX)jvm.$(LIB_SUFFIX) $(JDK_MODULE_IMAGE_DIR)/lib + $(CP) $(LIBDIR)/$(LIB_PREFIX)jawt.$(LIB_SUFFIX) $(JDK_MODULE_IMAGE_DIR)/lib + @# + @# bin/ + @# + @# copy all EXE files and only certain DLL files from BINDIR + $(MKDIR) -p $(JDK_MODULE_IMAGE_DIR)/bin + $(CP) $(BINDIR)/*$(EXE_SUFFIX) $(JDK_MODULE_IMAGE_DIR)/bin + $(CP) $(BINDIR)/jli.$(LIBRARY_SUFFIX) $(JDK_MODULE_IMAGE_DIR)/bin + ifeq ($(ARCH_DATA_MODEL), 32) + ifeq ($(COMPILER_VERSION), VS2003) + $(CP) $(BINDIR)/msvc*71.$(LIBRARY_SUFFIX) $(JDK_MODULE_IMAGE_DIR)/bin + endif + endif + else # PLATFORM + @# + @# bin/ + @# + ($(CD) $(BINDIR)/.. && $(TAR) cf - \ + `$(FIND) bin \( -type f -o -type l \) -print `) | \ + ($(CD) $(JDK_MODULE_IMAGE_DIR) && $(TAR) xf -) + endif # PLATFORM + @# + @# lib/ct.sym + @# + $(MKDIR) -p $(OUTPUTDIR)/symbols/META-INF/sym + $(JAVAC_CMD) -XDprocess.packages -proc:only \ + -processor com.sun.tools.javac.sym.CreateSymbols \ + -Acom.sun.tools.javac.sym.Jar=$(RT_JAR) \ + -Acom.sun.tools.javac.sym.Dest=$(OUTPUTDIR)/symbols/META-INF/sym/rt.jar \ + $(CORE_PKGS) $(NON_CORE_PKGS) $(EXCLUDE_PROPWARN_PKGS) + $(BOOT_JAR_CMD) c0f $(LIBDIR)/ct.sym \ + -C $(OUTPUTDIR)/symbols META-INF $(BOOT_JAR_JFLAGS) + @$(java-vm-cleanup) + $(CP) $(LIBDIR)/ct.sym $(JDK_MODULE_IMAGE_DIR)/lib/ct.sym + @# + @# CORBA supported orb.idl and ir.idl should be copied to lib + @# + $(CP) $(LIBDIR)/orb.idl $(JDK_MODULE_IMAGE_DIR)/lib/orb.idl + $(CP) $(LIBDIR)/ir.idl $(JDK_MODULE_IMAGE_DIR)/lib/ir.idl + ifeq ($(PLATFORM), linux) + @# + @# on Linux copy jexec from jre/lib to /lib + @# + $(CP) $(LIBDIR)/jexec $(JDK_MODULE_IMAGE_DIR)/lib/jexec + endif # PLATFORM + @# + @# demo, include + @# + $(CP) -r -f $(DEMODIR) $(JDK_MODULE_IMAGE_DIR) + $(CP) -r -f $(SAMPLEDIR) $(JDK_MODULE_IMAGE_DIR) + $(CP) -r $(INCLUDEDIR) $(JDK_MODULE_IMAGE_DIR) + @# + @# Swing BeanInfo generation + @# + $(CD) javax/swing/beaninfo && $(MAKE) JDK_IMAGE_DIR=$(JDK_MODULE_IMAGE_DIR) swing-1.2-beans +ifneq ($(PLATFORM), windows) + $(call copy-man-pages,$(JDK_MODULE_IMAGE_DIR),$(JDK_MAN_PAGES)) +endif # !windows + +# Trim out files we don't want to ship +trim-module-image-jdk:: + @# Remove tools that should not be part of SDK. + for t in $(NOTJDKTOOLS); do \ + $(RM) $(JDK_MODULE_IMAGE_DIR)/bin/$${t}$(EXE_SUFFIX) \ + $(JDK_MODULE_IMAGE_DIR)/bin/*/native_threads/$${t}$(EXE_SUFFIX); \ + done + +# Get list of Elf files in the jdk +JDK_MODULE_ELF_LIST=$(MODULES_TEMPDIR)/jdk-elf-files.list +$(JDK_MODULE_ELF_LIST): + @$(prep-target) +ifneq ($(PLATFORM), windows) + $(RM) $@ + $(FIND) $(JDK_MODULE_IMAGE_DIR)/jre/lib -type f -name \*.$(LIB_SUFFIX) >> $@ + $(FILE) `$(FIND) $(JDK_MODULE_IMAGE_DIR)/jre/bin -type f -name \*$(EXE_SUFFIX)` \ + | $(EGREP) 'ELF' | $(CUT) -d':' -f1 >> $@ + file `$(FIND) $(JDK_MODULE_IMAGE_DIR)/bin -type f -name \*$(EXE_SUFFIX)` \ + | $(EGREP) 'ELF' | $(CUT) -d':' -f1 >> $@ +endif + +# Post process the image (strips and mcs on files we are shipping) +process-module-image-jdk:: $(JDK_MODULE_ELF_LIST) +ifneq ($(POST_STRIP_PROCESS), ) + for f in `$(CAT) $(JDK_MODULE_ELF_LIST)`; do \ + $(CHMOD) u+w $${f}; \ + $(ECHO) $(POST_STRIP_PROCESS) $${f}; \ + $(POST_STRIP_PROCESS) $${f}; \ + $(CHMOD) go-w $${f}; \ + done +endif +ifneq ($(POST_MCS_PROCESS), ) + for f in `$(CAT) $(JDK_MODULE_ELF_LIST)`; do \ + $(CHMOD) u+w $${f}; \ + $(ECHO) $(POST_MCS_PROCESS) $${f}; \ + $(POST_MCS_PROCESS) $${f}; \ + $(CHMOD) go-w $${f}; \ + done +endif + $(RM) $(JDK_MODULE_ELF_LIST) + +###################################################### +# clobber +###################################################### +modules-clobber:: + $(RM) -r $(JDK_MODULE_IMAGE_DIR) + $(RM) -r $(JRE_MODULE_IMAGE_DIR) + +# +# TODO - nop for now +sanity-module-images post-sanity-module-images: + +modules modules-clobber:: + @$(ECHO) ">>>Finished making "$@" @ `$(DATE)` ..." + @$(java-vm-cleanup) + +.PHONY: modules module-image-jre module-image-jdk \ + initial-module-image-jre initial-module-image-jdk \ + initial-module-image-jre-sol64 initial-module-image-jdk-sol64 \ + initial-module-image-jdk-setup \ + initial-module-image-jdk-db \ + initial-module-image-jdk64-bindemos \ + initial-module-image-jre-setup \ + trim-module-image-jre trim-module-image-jdk \ + process-module-image-jre process-module-image-jdk \ + install-previous-jre install-previous-jdk \ + modules-clobber + +# Force rule +FRC: + diff --git a/make/modules/Makefile b/make/modules/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..039682e871a2f6f037171424440cb26eb25b0bd7 --- /dev/null +++ b/make/modules/Makefile @@ -0,0 +1,145 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# Modularizing the JDK +# + +BUILDDIR = .. +include $(BUILDDIR)/common/Defs.gmk + +CLASSANALYZER_JAR=$(BUILDTOOLJARDIR)/classanalyzer.jar +JAVA_FLAGS=$(JAVA_TOOLS_FLAGS) -Xbootclasspath:$(CLASSBINDIR) + +MODULE_LIB = $(ABS_OUTPUTDIR)/modules +MAINMANIFEST=$(JDK_TOPDIR)/make/tools/manifest.mf +MODULE_JAR_MANIFEST_FILE=$(ABS_TEMPDIR)/manifest.tmp + +TMP=$(ABS_TEMPDIR)/modules +MODULE_CLASSLIST = $(TMP)/classlist +MODULE_CLASSES = $(TMP)/classes +MODULE_LIST = $(MODULE_CLASSLIST)/modules.list + +# Modules in the modules/ext directory +EXT_MODULES = localedata security-sunec security-sunjce + +# Build PKCS#11 on all platforms except 64-bit Windows. +# We exclude windows-amd64 because we don't have any +# 64-bit PKCS#11 implementations to test with on that platform. +PKCS11 = security-sunpkcs11 +ifeq ($(ARCH_DATA_MODEL), 64) + ifeq ($(PLATFORM), windows) + PKCS11 = + endif +endif + +EXT_MODULES += $(PKCS11) + +# Build Microsoft CryptoAPI provider only on (non-64-bit) Windows platform. +ifeq ($(PLATFORM), windows) + ifneq ($(ARCH_DATA_MODEL), 64) + EXT_MODULES += security-sunmscapi + endif +endif + + +JDK_MODULES = tools + +SUBDIRS = tools +all build clean clobber:: + $(SUBDIRS-loop) + +all:: unpack-jars gen-classlist modularize + +$(CLASSANALYZER_JAR): + $(CD) tools && $(MAKE) all + +JAR_LIST := $(shell $(FIND) $(ABS_OUTPUTDIR)/lib -name \*.jar -depth) +unpack-jars: + $(RM) -rf $(MODULE_CLASSES) + $(MKDIR) -p $(MODULE_CLASSES) + $(CP) -rf $(CLASSBINDIR)/* $(MODULE_CLASSES) + for jf in $(JAR_LIST) ; do \ + $(CD) $(MODULE_CLASSES) && $(BOOT_JAR_CMD) xf $$jf $(BOOT_JAR_JFLAGS);\ + done + +gen-classlist: $(CLASSANALYZER_JAR) + @$(ECHO) ">>>Making "$@" @ `$(DATE)` ..." + @$(RM) -rf $(MODULE_CLASSLIST) + @$(MKDIR) -p $(MODULE_CLASSLIST) + + @# Use java in the default tool directory. + @# OUTPUTDIR for solaris 64-bit doesn't have the tools. + $(JAVA_TOOLS_DIR)/java $(JAVA_FLAGS) \ + -Dclassanalyzer.debug \ + -jar $(CLASSANALYZER_JAR) \ + -jdkhome $(OUTPUTDIR) \ + -config modules.config \ + -config modules.group \ + -depconfig jdk7.depconfig \ + -depconfig optional.depconfig \ + -showdynamic \ + -output $(MODULE_CLASSLIST) + @$(ECHO) ">>>Finished making "$@" @ `$(DATE)` ..." + +modularize: $(MODULE_JAR_MANIFEST_FILE) + @$(ECHO) ">>>Making "$@" @ `$(DATE)` ..." + @$(RM) -rf $(MODULE_LIB) + @$(MKDIR) -p $(MODULE_LIB)/lib + @$(MKDIR) -p $(MODULE_LIB)/jre/lib/ext + + @# create modules + for m in `$(NAWK) '{print $$1}' $(MODULE_LIST)` ; do \ + $(ECHO) "Creating module $$m" ; \ + $(SED) -e 's%\\%\/%g' < $(MODULE_CLASSLIST)/$$m.classlist > $(TMP)/tmp.cf ; \ + if [ -f $(MODULE_CLASSLIST)/$$m.resources ] ; then \ + $(SED) -e 's%\\%\/%g' < $(MODULE_CLASSLIST)/$$m.resources >> $(TMP)/tmp.cf ; \ + fi ; \ + $(CD) $(MODULE_CLASSES) && \ + $(BOOT_JAR_CMD) c0mf $(MODULE_JAR_MANIFEST_FILE) \ + $(MODULE_LIB)/$$m.jar \ + @$(TMP)/tmp.cf \ + $(BOOT_JAR_JFLAGS) ; \ + done + @$(CD) $(MODULE_CLASSES) && $(java-vm-cleanup) + @# move modules to lib, jre/lib, or jre/lib/ext + for m in $(EXT_MODULES) ; do \ + $(MV) $(MODULE_LIB)/$$m.jar $(MODULE_LIB)/jre/lib/ext ; \ + done + for m in $(JDK_MODULES) ; do \ + $(MV) $(MODULE_LIB)/$$m.jar $(MODULE_LIB)/lib ; \ + done + $(MV) $(MODULE_LIB)/*.jar $(MODULE_LIB)/jre/lib + @$(ECHO) ">>>Finished making "$@" @ `$(DATE)` ..." + +$(MODULE_JAR_MANIFEST_FILE): + $(SED) -e "s/@@RELEASE@@/$(RELEASE)/" $(MAINMANIFEST) > $@ + +clean clobber:: + $(RM) -rf $(MODULE_CLASSLIST) + $(RM) -rf $(MODULE_LIB) + $(RM) -f $(MODULE_JAR_MANIFEST_FILE) + $(RM) -f $(CLASSANALYZER_JAR) + diff --git a/make/modules/bootmodule.roots b/make/modules/bootmodule.roots new file mode 100644 index 0000000000000000000000000000000000000000..cd0b264b2549006d6043f2c2cfd8e4d9e1bbbba5 --- /dev/null +++ b/make/modules/bootmodule.roots @@ -0,0 +1,199 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# List of root classes/methods, each line of the following syntax: +# +# |* +# exclude | + +# The boot module generated based on this rootset does not support +# - security permission check +# - non-standard charset +# - logging output +# - resource bundles +# including error output from the launcher + +# VM preloaded classes +java.lang.Object +java.lang.String +java.lang.Class +java.lang.Cloneable +java.lang.ClassLoader +java.lang.System +java.lang.Throwable +java.lang.Error +java.lang.ThreadDeath +java.lang.Exception +java.lang.RuntimeException +java.security.ProtectionDomain +java.security.AccessControlContext +java.lang.ClassNotFoundException +java.lang.NoClassDefFoundError +java.lang.ClassCastException +java.lang.ArrayStoreException +java.lang.VirtualMachineError +java.lang.OutOfMemoryError +java.lang.StackOverflowError +java.lang.IllegalMonitorStateException +java.lang.ref.Reference +java.lang.ref.SoftReference +java.lang.ref.WeakReference +java.lang.ref.FinalReference +java.lang.ref.PhantomReference +java.lang.ref.Finalizer +java.lang.Runnable +java.lang.Thread +java.lang.ThreadGroup +java.util.Properties +java.lang.reflect.AccessibleObject +java.lang.reflect.Member +java.lang.reflect.Field +java.lang.reflect.Method +java.lang.reflect.Constructor +java.lang.reflect.Type +sun.reflect.MagicAccessorImpl +sun.reflect.MethodAccessorImpl +sun.reflect.ConstructorAccessorImpl +sun.reflect.DelegatingClassLoader +sun.reflect.ConstantPool +sun.reflect.UnsafeStaticFieldAccessorImpl +java.util.Vector +java.lang.StringBuffer +java.lang.StackTraceElement +java.nio.Buffer +java.lang.Boolean +java.lang.Character +java.lang.Float +java.lang.Double +java.lang.Byte +java.lang.Short +java.lang.Integer +java.lang.Long +java.lang.NullPointerException +java.lang.ArithmeticException +java.lang.Compiler + + +# Root methods +java.lang.ClassLoader.getSystemClassLoader ()Ljava/lang/ClassLoader; +java.lang.System.initializeSystemClass ()V +sun.launcher.LauncherHelper.checkAndLoadMain (ZZLjava/lang/String;)Ljava/lang/Object; + +# The tool doesn't automatically find superclasses and parse the method +# if overridden as it tries to reduce unnecessary classes being pulled in. +# The following forces the dependency to be included the result. +sun.net.www.protocol.file.Handler. ()V +sun.net.www.protocol.jar.Handler. ()V +sun.net.www.protocol.file.Handler.openConnection * +sun.net.www.protocol.jar.Handler.openConnection * +sun.misc.URLClassPath$JarLoader. (Ljava/net/URL;Ljava/net/URLStreamHandler;Ljava/util/HashMap;)V +sun.misc.URLClassPath$FileLoader. (Ljava/net/URL;)V +sun.misc.URLClassPath$FileLoader.getClassPath * +sun.misc.URLClassPath$FileLoader.getResource * +sun.misc.URLClassPath$JarLoader.getResource * +sun.misc.URLClassPath$JarLoader.getClassPath * + +# permission collections +java.io.FilePermission.newPermissionCollection ()Ljava/security/PermissionCollection; +java.security.BasicPermission.newPermissionCollection ()Ljava/security/PermissionCollection; + +# native +java.io.UnixFileSystem +java.io.UnixFileSystem. ()V +java.io.UnixFileSystem.canonicalize * +java.io.Win32FileSystem +java.io.Win32FileSystem. ()V +java.io.Win32FileSystem.canonicalize * +java.io.WinNTFileSystem +java.io.WinNTFileSystem. ()V +java.io.WinNTFileSystem.canonicalize * + +# missing +java.util.HashMap. ()V +java.util.HashMap$EntrySet.iterator * + +# Called from native GetStringPlatformChars (jni_util.c) +java.lang.String.getBytes * + +# charset +sun.nio.cs.US_ASCII.newEncoder ()Ljava/nio/charset/CharsetEncoder; +sun.nio.cs.UTF_8.newEncoder ()Ljava/nio/charset/CharsetEncoder; +sun.nio.cs.UTF_8.newDecoder * +sun.nio.cs.UTF_16.newEncoder ()Ljava/nio/charset/CharsetEncoder; +sun.nio.cs.UTF_16.newDecoder * +sun.nio.cs.UTF_32.newEncoder ()Ljava/nio/charset/CharsetEncoder; +sun.nio.cs.UTF_32.newDecoder * + +# hashcode +java.util.jar.Attributes$Name.hashCode * + +# nio +sun.nio.ByteBuffered +sun.nio.ch.DirectBuffer +java.nio.DirectByteBuffer +java.nio.MappedByteBuffer +java.nio.DirectLongBufferU + +# resource files +sun.launcher.resources.launcher + +sun.misc.Launcher$AppClassLoader.getPermissions * +sun.misc.Launcher$AppClassLoader.loadClass (Ljava/lang/String;)Ljava/lang/Class; +sun.misc.Launcher$AppClassLoader.findClass (Ljava/lang/String;)Ljava/lang/Class; +sun.misc.Launcher$ExtClassLoader.getPermissions * +sun.misc.Launcher$ExtClassLoader.loadClass (Ljava/lang/String;)Ljava/lang/Class; +sun.misc.Launcher$ExtClassLoader.findClass (Ljava/lang/String;)Ljava/lang/Class; +java.lang.ClassLoader.checkPackageAccess * +java.lang.ClassLoader.findClass * +java.lang.ClassLoader.defineClass * +java.net.URLClassLoader.getPermissions * +java.net.URLClassLoader.findClass * +java.net.URLClassLoader.defineClass * +java.security.SecureClassLoader.defineClass * +# need to parse superclasses +java.security.SecureClassLoader. ()V + +exclude sun.security.provider.PolicyFile. +exclude java.lang.ClassLoader.compareCerts +exclude java.security.cert.Certificate.equals +# unsigned jars - no verifier +exclude java.util.jar.JarFile.initializeVerifier +exclude java.util.jar.JarVerifier +exclude sun.security.util.SignatureFileVerifier. + + +# what about other charset +exclude sun.misc.Service +exclude java.util.ServiceLoader + +# exclude support for localized messages +exclude java.util.ResourceBundle.getBundle +exclude java.text.MessageFormat +exclude sun.util.logging.PlatformLogger$LoggerProxy.format * + +# exclude nio and miscellaneous classes +exclude java.nio.channels.** +exclude sun.misc.FloatingDecimal +exclude sun.misc.FormattedFloatingDecimal +exclude sun.misc.FDBigInt diff --git a/make/modules/jdk7.depconfig b/make/modules/jdk7.depconfig new file mode 100644 index 0000000000000000000000000000000000000000..286b19e3ad0bf099a0cc917768e655c97f351e9d --- /dev/null +++ b/make/modules/jdk7.depconfig @@ -0,0 +1,473 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# private java.lang.Object createInetSocketAddress(java.lang.String, int) +@ClassForName + com.sun.jndi.ldap.Connection -> java.net.InetSocketAddress + com.sun.jndi.ldap.Connection -> java.net.SocketAddress + +# com.sun.jndi.ldap.VersionHelper +@ClassForName(optional) + com.sun.jndi.ldap.VersionHelper -> com.sun.jndi.ldap.VersionHelper* + +# private static void initMethodHandles() +@ClassForName + com.sun.jndi.toolkit.corba.CorbaUtils -> javax.rmi.CORBA.Stub + com.sun.jndi.toolkit.corba.CorbaUtils -> javax.rmi.PortableRemoteObject + +# com.sun.naming.internal.ResourceManager$AppletParameter +@ClassForName(optional) + com.sun.naming.internal.ResourceManager$AppletParameter -> java.applet.Applet + +# private static boolean loadProviderAsService() +@Provider + com.sun.net.httpserver.spi.HttpServerProvider -> META-INF/services/com.sun.net.httpserver.spi.HttpServerProvider + +# com.sun.org.apache.xml.internal.security.transforms.implementations.TransformXSLT +@ClassForName + com.sun.org.apache.xml.internal.security.transforms.implementations.TransformXSLT -> javax.xml.XMLConstants + +# public static java.beans.PersistenceDelegate getPersistenceDelegate(java.lang.Class) +@ClassForName + java.beans.MetaData -> java.beans.*_PersistenceDelegate + +# private static java.lang.reflect.Method getNanosMethod() +@ClassForName(optional) + java.beans.java_sql_Timestamp_PersistenceDelegate -> java.sql.Timestamp + +# java.beans.java_util_Collections$CheckedCollection_PersistenceDelegate +@ClassForName + java.beans.java_util_Collections$CheckedCollection_PersistenceDelegate -> java.util.Collections$CheckedCollection + +# java.beans.java_util_Collections$CheckedMap_PersistenceDelegate +@ClassForName + java.beans.java_util_Collections$CheckedMap_PersistenceDelegate -> java.util.Collections$CheckedMap + +# private static java.lang.Object getType(java.lang.Object) +@ClassForName + java.beans.java_util_EnumMap_PersistenceDelegate -> java.util.EnumMap + +# private java.lang.Integer getAxis(java.lang.Object) +@ClassForName + java.beans.javax_swing_Box_PersistenceDelegate -> javax.swing.BoxLayout + +# java.lang.Double +@Inline + java.lang.Double -> sun.misc.FloatConsts + java.lang.Double -> sun.misc.DoubleConsts + +# java.lang.Float +@Inline + java.lang.Float -> sun.misc.FloatConsts + java.lang.Float -> sun.misc.DoubleConsts + +# java.net.DefaultDatagramSocketImplFactory +@ClassForName(optional) + java.net.DefaultDatagramSocketImplFactory -> java.net.*DatagramSocketImpl + +# private static sun.net.spi.nameservice.NameService createNSProvider(java.lang.String) +@Provider + java.net.InetAddress -> META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor + +# static java.net.InetAddressImpl create() +@ClassForName + java.net.InetAddressImplFactory -> java.net.*Inet[46]AddressImpl + +# private static void init() +@NativeFindClass + java.net.PlainDatagramSocketImpl -> java.io.FileDescriptor + +# java.net.ProxySelector +@ClassForName + java.net.ProxySelector -> sun.net.spi.DefaultProxySelector + +# static java.net.URLStreamHandler getURLStreamHandler(java.lang.String) +@ClassForName(optional) + java.net.URL -> sun.net.www.protocol.*.Handler + +# private java.net.ContentHandler lookupContentHandlerClassFor(java.lang.String) +@ClassForName + java.net.URLConnection -> sun.net.www.content.* + +# private static java.nio.channels.spi.AsynchronousChannelProvider loadProviderAsService() +@Provider + java.nio.channels.spi.AsynchronousChannelProvider$ProviderHolder -> META-INF/services/java.nio.channels.spi.AsynchronousChannelProvider + +# private static boolean loadProviderFromProperty() +@ClassForName + java.nio.channels.spi.SelectorProvider -> sun.nio.ch.DefaultSelectorProvider + +# private static boolean loadProviderAsService() +@Provider + java.nio.channels.spi.SelectorProvider -> META-INF/services/java.nio.channels.spi.SelectorProvider + +# private static java.util.Iterator providers() +@Provider + java.nio.charset.Charset -> META-INF/services/java.nio.charset.spi.CharsetProvider + +# private static void probeExtendedProvider() +@ClassForName(optional) + java.nio.charset.Charset -> sun.nio.cs.ext.ExtendedCharsets + +# public static java.nio.file.FileSystem newFileSystem(java.net.URI, java.util.Map, java.lang.ClassLoader) +@Provider + java.nio.file.FileSystems -> META-INF/services/java.nio.file.FileSystemProvider + +# private static java.util.List loadInstalledDetectors() +@Provider + java.nio.file.Files$DefaultFileTypeDetectorHolder -> META-INF/services/java.nio.file.spi.FileTypeDetector + +# public static java.util.List installedProviders() +@Provider + java.nio.file.spi.FileSystemProvider -> META-INF/services/java.nio.file.FileSystemProvider + +# private static java.rmi.server.RMIClassLoaderSpi initializeProvider() +@Provider + java.rmi.server.RMIClassLoader -> META-INF/services/java.rmi.server.RMIClassLoaderSpi + +# private static void initializeSystemScope() +@ClassForName(optional) + java.security.IdentityScope -> sun.security.provider.IdentityDatabase + +# static java.security.Policy getPolicyNoCheck() +@ClassForName + java.security.Policy -> sun.security.provider.PolicyFile + +# private static java.lang.Class getSpiClass(java.lang.String) +@ClassForName + java.security.Security -> java.security.*Spi + +# private static void invalidateSMCache(java.lang.String) +@ClassForName + java.security.Security -> java.lang.SecurityManager + +# private static void loadInitialDrivers() +@Provider + java.sql.DriverManager -> META-INF/services/java.sql.Driver + +# private static java.text.BreakIterator createBreakInstance(java.util.Locale, int, java.lang.String, java.lang.String) +@Provider + java.text.BreakIterator -> META-INF/services/java.util.spi.BreakIteratorProvider + +# public static java.text.Collator getInstance(java.util.Locale) +@Provider + java.text.Collator -> META-INF/services/java.util.spi.CollatorProvider + +# private static java.text.DateFormat get(int, int, int, java.util.Locale) +@Provider + java.text.DateFormat -> META-INF/services/java.util.spi.DateNameProvider + +# public static java.util.Locale[] getAvailableLocales() +@Provider + java.text.DateFormatSymbols -> META-INF/services/java.util.spi.DateFormatSymbolsProvider + +# public static java.util.Locale[] getAvailableLocales() +@Provider + java.text.DecimalFormatSymbols -> META-INF/services/java.util.spi.DecimalFormatSymbolsProvider + +# public static java.util.Locale[] getAvailableLocales() +@Provider + java.text.NumberFormat -> META-INF/services/java.util.spi.NumberFormatProvider + +# public java.lang.String getDisplayName(java.util.Locale) +@Provider + java.util.Currency -> META-INF/services/java.util.spi.CurrencyNameProvider + +# java.util.Formatter +@Inline + java.util.Formatter -> sun.misc.DoubleConsts + +# java.util.Locale +@Inline + java.util.Locale -> java.util.LocaleISOData + +# private java.lang.String getDisplayString(java.lang.String, java.util.Locale, int) +@Provider + java.util.Locale -> META-INF/services/java.util.spi.LocaleNameProvider + +# private static java.util.prefs.PreferencesFactory factory1() +@ClassForName + java.util.prefs.Preferences -> java.util.prefs.WindowsPreferencesFactory + java.util.prefs.Preferences -> java.util.prefs.FileSystemPreferencesFactory + +# private static java.util.prefs.PreferencesFactory factory1() +@Provider + java.util.prefs.Preferences -> META-INF/services/java.util.prefs.PreferencesFactory + +# public void registerApplicationClasspathSpis() +@Provider + javax.imageio.spi.IIORegistry -> META-INF/services/javax.imageio.spi.IIOServiceProvider + +# private void registerInstalledProviders() +@Provider + javax.imageio.spi.IIORegistry -> META-INF/services/javax.imageio.spi.ImageReaderSpi + javax.imageio.spi.IIORegistry -> META-INF/services/javax.imageio.spi.ImageWriterSpi + javax.imageio.spi.IIORegistry -> META-INF/services/javax.imageio.spi.ImageReaderWriterSpi + javax.imageio.spi.IIORegistry -> META-INF/services/javax.imageio.spi.ImageTranscoderSpi + javax.imageio.spi.IIORegistry -> META-INF/services/javax.imageio.spi.ImageInputStreamSpi + javax.imageio.spi.IIORegistry -> META-INF/services/javax.imageio.spi.ImageOutputStreamSpi + +# public javax.naming.ldap.ExtendedResponse createExtendedResponse(java.lang.String, byte[], int, int) +@Provider + javax.naming.ldap.StartTlsRequest -> META-INF/services/javax.naming.ldap.StartTlsResponse + +# private static java.util.ArrayList getAllLookupServices() +@Provider + javax.print.PrintServiceLookup -> META-INF/services/javax.print.PrintServiceLookup + +# private static java.util.ArrayList getAllFactories() +@Provider + javax.print.StreamPrintServiceFactory -> META-INF/services/javax.print.StreamPrintServiceFactory + +# private void initEngines(java.lang.ClassLoader) +@Provider + javax.script.ScriptEngineManager -> META-INF/services/javax.script.ScriptEngineFactory + +# private void initializeInputMethodLocatorList() +@Provider + sun.awt.im.ExecutableInputMethodManager -> META-INF/services/java.awt.im.spi.InputMethodDescriptor + +# private static java.lang.Class getConverterClass(int, java.lang.String) +@ClassForName(optional) + sun.io.Converters -> sun.io.* + +# public static sun.java2d.cmm.PCMM getModule() +@Provider + sun.java2d.cmm.CMSManager -> META-INF/services/sun.java2d.cmm.PCMM + +# public static sun.java2d.pipe.RenderingEngine getInstance() +@Provider + sun.java2d.pipe.RenderingEngine -> META-INF/services/sun.java2d.pipe.RenderingEngine + +# public static sun.java2d.pipe.RenderingEngine getInstance() +@ClassForName(optional) + sun.java2d.pipe.RenderingEngine -> sun.dc.DuctusRenderingEngine + +# sun.misc.FloatingDecimal +@Inline + sun.misc.FloatingDecimal -> sun.misc.FloatConsts + sun.misc.FloatingDecimal -> sun.misc.DoubleConsts + +# sun.misc.FormattedFloatingDecimal +@Inline + sun.misc.FormattedFloatingDecimal -> sun.misc.FloatConsts + sun.misc.FormattedFloatingDecimal -> sun.misc.DoubleConsts + +# sun.misc.FpUtils +@Inline + sun.misc.FpUtils -> sun.misc.FloatConsts + sun.misc.FpUtils -> sun.misc.DoubleConsts + +# public java.net.URLStreamHandler createURLStreamHandler(java.lang.String) +@ClassForName(optional) + sun.misc.Launcher$Factory -> sun.net.www.protocol.*.Handler + +# private static sun.net.NetHooks$Provider loadProvider(java.lang.String) +@ClassForName(optional) + sun.net.NetHooks -> sun.net.spi.SdpProvider + +# sun.net.idn.StringPrep +@Inline + sun.net.idn.StringPrep -> sun.net.idn.UCharacterDirection + +# private static boolean init() +@NativeFindClass + sun.net.spi.DefaultProxySelector -> java.net.Proxy + sun.net.spi.DefaultProxySelector -> java.net.Proxy$Type + sun.net.spi.DefaultProxySelector -> java.net.InetSocketAddress + +# private static java.nio.channels.Channel createChannel() +@ClassForName + sun.nio.ch.InheritedChannel -> java.io.FileDescriptor + +# private static void initDBBConstructor() +@ClassForName + sun.nio.ch.Util -> java.nio.DirectByteBuffer + +# private static void initDBBRConstructor() +@ClassForName + sun.nio.ch.Util -> java.nio.DirectByteBufferR + +# private java.nio.charset.Charset lookup(java.lang.String) +@ClassForName(optional) + sun.nio.cs.FastCharsetProvider -> sun.nio.cs.* + +# sun.nio.cs.ext.ExtendedCharsets +@ClassForName(optional) + sun.nio.cs.ext.ExtendedCharsets -> sun.nio.cs.ext.* + +# sun.nio.cs.ext.ExtendedCharsets +@ClassForName(optional) + sun.nio.cs.ext.ExtendedCharsets -> sun.nio.cs.ext.* + +# public static java.nio.file.spi.FileSystemProvider create() +@ClassForName + sun.nio.fs.DefaultFileSystemProvider -> sun.nio.fs.SolarisFileSystemProvider + sun.nio.fs.DefaultFileSystemProvider -> sun.nio.fs.LinuxFileSystemProvider + +# sun.rmi.server.MarshalInputStream +@ClassForName + sun.rmi.server.MarshalInputStream -> sun.rmi.server.Activation$ActivationSystemImpl_Stub + sun.rmi.server.MarshalInputStream -> sun.rmi.registry.RegistryImpl_Stub + +# private java.security.Provider doLoadProvider() +@ClassForName(optional) + sun.security.jca.ProviderConfig -> sun.security.pkcs11.SunPKCS11 + sun.security.jca.ProviderConfig -> sun.security.provider.Sun + sun.security.jca.ProviderConfig -> sun.security.rsa.SunRsaSign + sun.security.jca.ProviderConfig -> sun.security.ec.SunEC + sun.security.jca.ProviderConfig -> com.sun.net.ssl.internal.ssl.Provider + sun.security.jca.ProviderConfig -> com.sun.crypto.provider.SunJCE + sun.security.jca.ProviderConfig -> sun.security.jgss.SunProvider + sun.security.jca.ProviderConfig -> com.sun.security.sasl.Provider + sun.security.jca.ProviderConfig -> org.jcp.xml.dsig.internal.dom.XMLDSigRI + sun.security.jca.ProviderConfig -> sun.security.smartcardio.SunPCSC + sun.security.jca.ProviderConfig -> sun.security.mscapi.SunMSCAPI + +# public static java.security.Provider getSunProvider() +@ClassForName + sun.security.jca.Providers -> sun.security.provider.Sun + sun.security.jca.Providers -> sun.security.provider.VerificationProvider + +# private static sun.security.jgss.spi.MechanismFactory getMechFactoryImpl(java.security.Provider, java.lang.String, org.ietf.jgss.Oid, sun.security.jgss.GSSCaller) +@ClassForName + sun.security.jgss.ProviderList -> sun.security.jgss.spi.MechanismFactory + +# sun.security.jgss.wrapper.SunNativeProvider +@NativeFindClass + sun.security.jgss.wrapper.SunNativeProvider -> org.ietf.jgss.Oid + sun.security.jgss.wrapper.SunNativeProvider -> org.ietf.jgss.GSSException + sun.security.jgss.wrapper.SunNativeProvider -> sun.security.jgss.wrapper.GSSNameElement + sun.security.jgss.wrapper.SunNativeProvider -> sun.security.jgss.wrapper.GSSCredElement + sun.security.jgss.wrapper.SunNativeProvider -> sun.security.jgss.wrapper.NativeGSSContext + sun.security.jgss.wrapper.SunNativeProvider -> sun.security.jgss.wrapper.SunNativeProvider + sun.security.jgss.wrapper.SunNativeProvider -> org.ietf.jgss.MessageProp + sun.security.jgss.wrapper.SunNativeProvider -> org.ietf.jgss.ChannelBinding + sun.security.jgss.wrapper.SunNativeProvider -> java.net.InetAddress + sun.security.jgss.wrapper.SunNativeProvider -> sun.security.jgss.wrapper.GSSLibStub + +# static void ensureLoaded() +@NativeFindClass + sun.security.krb5.Credentials -> sun.security.krb5.internal.Krb5 + sun.security.krb5.Credentials -> sun.security.krb5.internal.Ticket + sun.security.krb5.Credentials -> sun.security.krb5.PrincipalName + sun.security.krb5.Credentials -> sun.security.util.DerValue + sun.security.krb5.Credentials -> sun.security.krb5.EncryptionKey + sun.security.krb5.Credentials -> sun.security.krb5.internal.TicketFlags + sun.security.krb5.Credentials -> sun.security.krb5.internal.KerberosTime + +# public static java.lang.String getDefaultCacheName() +@ClassForName(optional) + sun.security.krb5.internal.ccache.FileCredentialsCache -> com.sun.security.auth.module.UnixSystem + +# sun.security.pkcs.PKCS9Attribute +@ClassForName + sun.security.pkcs.PKCS9Attribute -> sun.security.util.ObjectIdentifier + sun.security.pkcs.PKCS9Attribute -> java.util.Date + sun.security.pkcs.PKCS9Attribute -> sun.security.pkcs.SignerInfo + sun.security.pkcs.PKCS9Attribute -> sun.security.x509.CertificateExtensions + +# protected T engineGetKeySpec(java.security.Key, java.lang.Class) +@ClassForName + sun.security.provider.DSAKeyFactory -> java.security.spec.DSAPublicKeySpec + sun.security.provider.DSAKeyFactory -> java.security.spec.X509EncodedKeySpec + sun.security.provider.DSAKeyFactory -> java.security.spec.DSAPrivateKeySpec + sun.security.provider.DSAKeyFactory -> java.security.spec.PKCS8EncodedKeySpec + +# protected T engineGetParameterSpec(java.lang.Class) +@ClassForName + sun.security.provider.DSAParameters -> java.security.spec.DSAParameterSpec + +# sun.security.provider.VerificationProvider +@ClassForName(optional) + sun.security.provider.VerificationProvider -> sun.security.provider.Sun + sun.security.provider.VerificationProvider -> sun.security.rsa.SunRsaSign + +# sun.security.provider.certpath.URICertStore$LDAP +@ClassForName(optional) + sun.security.provider.certpath.URICertStore$LDAP -> sun.security.provider.certpath.ldap.LDAPCertStoreHelper + +# sun.security.smartcardio.PCSC +@NativeFindClass + sun.security.smartcardio.PCSC -> sun.security.smartcardio.PCSCException + +# sun.security.ssl.HandshakeMessage +@ClassForName + sun.security.ssl.HandshakeMessage -> java.security.MessageDigest$Delegate + +# sun.security.ssl.JsseJce +@ClassForName(optional) + sun.security.ssl.JsseJce -> sun.security.krb5.PrincipalName + +# sun.security.x509.OIDMap$OIDInfo +@ClassForName + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.SubjectKeyIdentifierExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.KeyUsageExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.PrivateKeyUsageExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.SubjectAlternativeNameExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.IssuerAlternativeNameExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.BasicConstraintsExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.CRLNumberExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.CRLReasonCodeExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.NameConstraintsExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.PolicyMappingsExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.AuthorityKeyIdentifierExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.PolicyConstraintsExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.NetscapeCertTypeExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.CertificatePoliciesExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.ExtendedKeyUsageExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.InhibitAnyPolicyExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.CRLDistributionPointsExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.CertificateIssuerExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.SubjectInfoAccessExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.AuthorityInfoAccessExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.IssuingDistributionPointExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.DeltaCRLIndicatorExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.FreshestCRLExtension + sun.security.x509.OIDMap$OIDInfo -> sun.security.x509.OCSPNoCheckExtension + +# sun.util.LocaleServiceProviderPool$AllAvailableLocales +@Provider + sun.util.LocaleServiceProviderPool$AllAvailableLocales -> META-INF/services/java.text.spi.BreakIteratorProvider + sun.util.LocaleServiceProviderPool$AllAvailableLocales -> META-INF/services/java.text.spi.CollatorProvider + sun.util.LocaleServiceProviderPool$AllAvailableLocales -> META-INF/services/java.text.spi.DateFormatProvider + sun.util.LocaleServiceProviderPool$AllAvailableLocales -> META-INF/services/java.text.spi.DateFormatSymbolsProvider + sun.util.LocaleServiceProviderPool$AllAvailableLocales -> META-INF/services/java.text.spi.DecimalFormatSymbolsProvider + sun.util.LocaleServiceProviderPool$AllAvailableLocales -> META-INF/services/java.text.spi.NumberFormatProvider + sun.util.LocaleServiceProviderPool$AllAvailableLocales -> META-INF/services/java.util.spi.CurrencyNameProvider + sun.util.LocaleServiceProviderPool$AllAvailableLocales -> META-INF/services/java.util.spi.LocaleNameProvider + sun.util.LocaleServiceProviderPool$AllAvailableLocales -> META-INF/services/java.util.spi.TimeZoneNameProvider + +# private static final java.lang.String[] retrieveDisplayNames(sun.util.resources.OpenListResourceBundle, java.lang.String, java.util.Locale) +@Provider + sun.util.TimeZoneNameUtility -> META-INF/services/java.util.spi.TimeZoneNamePProvider + +# public static sun.util.calendar.CalendarSystem forName(java.lang.String) +@ClassForName + sun.util.calendar.CalendarSystem -> sun.util.calendar.Gregorian + sun.util.calendar.CalendarSystem -> sun.util.calendar.LocalGregorianCalendar + sun.util.calendar.CalendarSystem -> sun.util.calendar.JulianCalendar + +# sun.util.logging.LoggingSupport +@ClassForName(optional) + sun.util.logging.LoggingSupport -> java.util.logging.LoggingProxyImpl diff --git a/make/modules/modules.config b/make/modules/modules.config new file mode 100644 index 0000000000000000000000000000000000000000..04b71ea6a51a8da00606c6b03f4a48ba91609e60 --- /dev/null +++ b/make/modules/modules.config @@ -0,0 +1,858 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +// These classes are not referenced in the JDK but we can't +// remove them for compatibility reason. Define this module +// first so that other modules don't need to exclude these clases +module private-legacy { + include sun.misc.Cache*, + sun.misc.ClassLoaderUtil, + sun.misc.Compare, + sun.misc.ConditionLock, + sun.misc.CRC16, + sun.misc.Lock, + sun.misc.Regexp, + sun.misc.RequestProcessor, + sun.misc.Sort, + sun.misc.Request, + sun.misc.Timeable, + sun.misc.Timer, + sun.misc.TimerThread, + sun.misc.TimerTickThread, + sun.misc.UCDecoder, + sun.misc.UCEncoder, + sun.misc.UUDecoder, + sun.misc.UUEncoder, + com.sun.net.ssl.SSLContext, + sun.net.NetworkServer, + sun.net.URLCanonicalizer, + sun.reflect.misc.ConstructorUtil, + sun.reflect.FieldInfo, + sun.reflect.SignatureIterator, + sun.reflect.generics.reflectiveObjects.NotImplementedException, + sunw.io.Serializable, + sunw.util.EventListener, + sunw.util.EventObject; +} + +// Deprecated classes that aren't referenced/used go here. +module deprecated { + // add deprecated security classes once b78 is promoted +} + +/**************************************************************************/ + +module base { + // core classes + include java.lang.*, + java.lang.annotation.*, + java.lang.ref.*, + java.lang.reflect.*, + java.math.*, + java.net.*, + java.util.*, + java.util.concurrent.**, + java.util.jar.*, + java.util.regex.*, + java.util.spi.*, + java.util.zip.*, + java.text.**; + + exclude java.util.jar.Pack200*, + java.util.XMLUtils, + java.text.Bidi; + + include java.io.*, java.nio.*, java.nio.charset.**; + exclude java.io.TempFileHelper, java.nio.BufferPoolMXBean; + + // security APIs + // javax.crypto and javax.security.auth are included to avoid inconsistent + // spliting of JCA and JAAS. This adds about 85k. Also note that some deprecated + // classes must be included for now (see 6876158, 6876170) + include java.security.*, + java.security.cert.*, + java.security.interfaces.*, + java.security.spec.*, + javax.security.auth.**, + javax.crypto.**; + + // Sun and RSA security providers (except LDAP CertStore) + // roots sun.security.provider.* sun.security.provider.certpath.* sun.security.rsa.* + include com.sun.security.auth.PrincipalComparator, + com.sun.security.auth.SubjectCodeSource, + com.sun.security.auth.login.**, + com.sun.security.auth.Policy*, + sun.security.action.*, + sun.security.ec.*, + sun.security.jca.*, + sun.security.pkcs.*, + sun.security.provider.*, + sun.security.provider.certpath.*, + sun.security.rsa.*, + sun.security.util.*, + sun.security.validator.*, + sun.security.x509.*, + sun.security.timestamp.*; + + // this list is based on the classlist generated from the rootset + // need investigation + exclude sun.security.ec.ECD*, + sun.security.ec.ECKeyPairGenerator, + sun.security.ec.SunEC*, + sun.security.pkcs.PKCS10*, + sun.security.pkcs.EncodingException, + sun.security.util.AuthResources_*, + sun.security.util.Resources_*, + sun.security.util.BigInt, + sun.security.util.HostnameChecker, + sun.security.x509.CertAndKeyGen, + sun.security.util.PathList; + + // Kerberos not needed + exclude javax.security.auth.kerberos.**, + sun.security.jgss.**, + sun.security.krb5.**, + sun.security.ssl.Kerberos*, + org.ietf.jgss.**; + + // property events and annotations + include java.beans.ChangeListenerMap, + java.beans.IndexedPropertyChangeEvent, + java.beans.PropertyChange*, + java.beans.PropertyVetoException, + java.beans.VetoableChange*, + java.beans.ConstructorProperties; + + // mandatory charsets + include sun.nio.cs.*; + + exclude sun.nio.cs.AbstractCharsetProvider, + sun.nio.cs.CharsetMapping, + sun.nio.cs.IBM*, + sun.nio.cs.ISO*, + sun.nio.cs.KOI8_*, + sun.nio.cs.MS125*, + sun.nio.cs.UTF_32*, + sun.nio.cs.SingleByteDecoder, + sun.nio.cs.SingleByteEncoder; + + allow sun.nio.cs.ISO_8859_1, + sun.nio.cs.ISO_8859_15, + sun.nio.cs.MS1252; + + include sun.text.*, + sun.text.normalizer.*; + + // resource files + include sun/text/resources/*.icu; + + exclude sun.text.bidi.*, + sun.text.CharArrayCodePointIterator, + sun.text.CharSequenceCodePointIterator, + sun.text.CharacterIteratorCodePointIterator, + sun.text.CodePointIterator; + + include sun.util.*, + sun.util.calendar.*, + sun.util.logging.*, + sun.util.resources.LocaleData, + sun.util.resources.LocaleNamesBundle, + sun.util.resources.OpenListResourceBundle; + + // US_en locale + include sun.text.resources.BreakIteratorInfo, + sun.text.resources.FormatData, + sun.text.resources.FormatData_en_US, + sun.util.resources.CalendarData, + sun.util.resources.CalendarData_en, + sun.util.resources.TimeZoneNames, + sun.util.resources.TimeZoneNames_en, + sun.util.resources.TimeZoneNamesBundle, + sun.util.resources.LocaleNames, + sun.util.resources.LocaleNames_en, + sun.util.resources.LocalenamesBundles, + sun.util.resources.CurrencyNames, + sun.util.resources.CurrencyNames_en_US, + sun.util.EmptyListResourceBundle; + + // resources file needed by + // - sun.misc.ExtensionInfo + // - sun.security.provider.PolicyFile + // - com.sun.security.auth.PolicyFile + include sun.misc.resources.Messages, + sun.security.util.Resources, + sun.security.util.AuthResources; + + // java.nio.channels and java.nio.file not in base + include sun.nio.ch.Interruptible, + sun.nio.ch.DirectBuffer, + sun.nio.ByteBuffered; + + include sun.reflect.**; + + // protocol handlers + include sun.net.www.protocol.file.*, + sun.net.www.protocol.jar.*, + sun.net.www.protocol.http.*; + + include sun.net.*, + sun.net.spi.*, + sun.net.idn.*, + sun.net.util.*, + sun.net.www.*, + sun.net.www.http.*, + sun.net.spi.nameservice.*; + + // resource file for sun.net.idn + include sun/net/idn/*; + + // classes in net-compat + exclude sun.net.Telnet*, sun.net.TransferProtocolClient; + + // classes in deploy + exclude sun.net.www.protocol.http.AuthCacheBridge; + + // classes in security-jsse + exclude java.net.SecureCacheResponse; + + // launcher + include sun.launcher.LauncherHelper, sun.launcher.resources.launcher; + + include sun.misc.*; + exclude sun.misc.FIFOQueueEnumerator, + sun.misc.LIFOQueueEnumerator, + sun.misc.GC, + sun.misc.PerformanceLogger, + sun.misc.Queue, + sun.misc.QueueElement, + sun.misc.Ref, + sun.misc.VMSupport; + + // On Windows, OSEnvironment dependency + include sun.io.Win32ErrorMode; +} + +/**************************************************************************/ + +module charsets { + include sun.nio.cs.ext.**; + + include sun.nio.cs.AbstractCharsetProvider, + sun.nio.cs.CharsetMapping, + sun.nio.cs.IBM*, + sun.nio.cs.ISO*, + sun.nio.cs.KOI8_*, + sun.nio.cs.MS125*, + sun.nio.cs.SingleByte*, + sun.nio.cs.UTF_32*; + + exclude sun.nio.cs.ISO_8859_1, + sun.nio.cs.MS1252; + + // legacy sun.io converters + include sun.io.*; +} + +/**************************************************************************/ + +// For now, retains the current JRE extensions where localedata.jar in jre/lib/ext +module localedata { + include sun.util.resources.*_ar, + sun.util.resources.*_ar_*, + sun.util.resources.*_hi, + sun.util.resources.*_hi_*, + sun.util.resources.*_iw, + sun.util.resources.*_iw_*, + sun.util.resources.*_ja, + sun.util.resources.*_ja_*, + sun.util.resources.*_ko, + sun.util.resources.*_ko_*, + sun.util.resources.*_th, + sun.util.resources.*_th_*, + sun.util.resources.*_vi, + sun.util.resources.*_vi_*, + sun.util.resources.*_zh, + sun.util.resources.*_zh_*; + include sun.text.resources.*_ar, + sun.text.resources.*_ar_*, + sun.text.resources.*_hi, + sun.text.resources.*_hi_*, + sun.text.resources.*_iw, + sun.text.resources.*_iw_*, + sun.text.resources.*_ja, + sun.text.resources.*_ja_*, + sun.text.resources.*_ko, + sun.text.resources.*_ko_*, + sun.text.resources.*_th, + sun.text.resources.*_th_*, + sun.text.resources.*_vi, + sun.text.resources.*_vi_*, + sun.text.resources.*_zh, + sun.text.resources.*_zh_*; +} + +module resources { + include sun.text.resources.*, sun.util.resources.*, sun.misc.resources.*; +} + +/**************************************************************************/ + +module nio { + include java.nio.channels.**, java.nio.file.**, com.sun.nio.file.**; + + // this is excluded from base + include java.io.TempFileHelper; + + // provider implementations and their dependencies + include sun.nio.ch.*, sun.nio.fs.**; + exclude sun.nio.ch.Sctp*; +} + +/**************************************************************************/ + +module pack200 { + include java.util.jar.Pack200*, com.sun.java.util.jar.pack.**; +} + +/**************************************************************************/ + +module logging { + include java.util.logging.*, sun.util.logging.**; + exclude java.util.logging.PlatformLoggingMXBean; + + // Formatter for HTTP messages + include sun.net.www.protocol.http.logging.*; +} + +/**************************************************************************/ + +module management-snmp { + include com.sun.jmx.snmp.**, sun.management.snmp.**; +} + +module management-iiop { + include com.sun.jmx.remote.protocol.iiop.*; + + // stubs and ties + include javax.management.remote.rmi._*, + org.omg.stub.javax.management.remote.rmi.**; +} + +module management { + include java.lang.management.*, com.sun.management.**, sun.management.**; + include javax.management.**, com.sun.jmx.**; + + // other management interfaces + include java.nio.BufferPoolMXBean; + include java.util.logging.PlatformLoggingMXBean; + + // supporting classes in sun.misc + include sun.misc.VMSupport; +} + +/**************************************************************************/ + +module instrument { + // java.lang.instrument + include java.lang.instrument.*, sun.instrument.*; + + // tracing + include com.sun.tracing.**, sun.tracing.**; + + // HPROF support + include com.sun.demo.jvmti.hprof.*; +} + +/**************************************************************************/ + +module rmi-activation { + include java.rmi.activation.**, + sun.rmi.server.Act*, + sun.rmi.server.InactiveGroupException; +} + +module rmi { + include java.rmi.**, sun.rmi.**, com.sun.rmi.**; + + // SSL factories are in rmi + include javax.rmi.ssl.**; + + // rmic is in tools + exclude sun.rmi.rmic.**; + + // supporting classes in sun.misc and dependencies + include sun.misc.GC; +} + +/**************************************************************************/ + +module prefs { + include java.util.prefs.*; +} + +/**************************************************************************/ + +module security-jsse { + include javax.net.**, + javax.security.cert.*, + java.net.SecureCacheResponse, + com.sun.net.ssl.**, + com.sun.security.cert.internal.x509.*, + sun.security.ssl.*, + sun.net.www.protocol.https.**, + sun.security.internal.interfaces.Tls*, + sun.security.internal.spec.Tls*, + sun.security.util.HostnameChecker; +} + +module security-sunpkcs11 { + include sun.security.pkcs11.**; +} + +module security-sunjce { + include com.sun.crypto.provider.*; +} + +module security-sunec { + include sun.security.ec.*; +} + +module security-sunmscapi { + include sun.security.mscapi.*; +} + +module security-kerberos { + include javax.security.auth.kerberos.*, + com.sun.security.jgss.**, + com.sun.security.auth.module.Krb5LoginModule, + com.sun.security.sasl.gsskerb.**, // GSSAPI SASL mechanism + sun.security.jgss.**, + sun.security.ssl.krb5.**, + sun.security.krb5.**, + org.ietf.jgss.**, + sun.net.www.protocol.http.spnego.*; +} + +module security-sasl { + include javax.security.sasl.**, + com.sun.security.sasl.**; +} + +module security-xmldsig { + include javax.xml.crypto.**, + org.jcp.xml.dsig.**, + com.sun.org.apache.xml.internal.security.**; +} + +module security-smartcardio { + include javax.smartcardio.**, sun.security.smartcardio.**; +} + +module security-misc { + include com.sun.security.auth.**, sun.security.util.AuthResources_*, + sun.security.pkcs.*, + sun.security.pkcs12.*; + + // this class is a candidate to be removed. + include sun.security.util.BigInt; +} + +module security-resources { + include sun.security.util.Resources_*; +} + +module security-compat { + include java.security.acl.*, sun.security.acl.*; +} + +/**************************************************************************/ + +module jndi-ldap { + include javax.naming.ldap.**, + com.sun.jndi.ldap.**, + com.sun.jndi.url.ldap.*, + com.sun.jndi.url.ldaps.*, + sun.security.provider.certpath.ldap.**; +} + +module jndi-rmiregistry { + include com.sun.jndi.rmi.**, com.sun.jndi.url.rmi.**; +} + +module jndi-dns { + include com.sun.jndi.dns.**, com.sun.jndi.url.dns.**; + include sun.net.dns.**; // to access DNS config. + include sun.net.spi.nameservice.dns.**; // for DNS-only name service. +} + +module jndi-cosnaming { + include com.sun.jndi.cosnaming.**, + com.sun.jndi.toolkit.corba.**, + com.sun.jndi.url.corbaname.**, + com.sun.jndi.url.iiop.**, + com.sun.jndi.url.iiopname.**; +} + +// framework/API and classes used by providers +module jndi { + include javax.naming.**, + com.sun.naming.**, + com.sun.jndi.toolkit.ctx.**, + com.sun.jndi.toolkit.dir.**, + com.sun.jndi.toolkit.url.**; +} + +/**************************************************************************/ + +module jdbc-base { + include java.sql.**, javax.sql.*; + exclude javax.sql.XA*; +} + +module jdbc-enterprise { + include javax.sql.**, com.sun.rowset.**; +} + +module jdbc-odbc { + include sun.jdbc.odbc.**; +} + +/**************************************************************************/ + +module scripting { + include javax.script.**; + + // supporting classes for scripting engines + include com.sun.script.util.**; +} + +module scripting-rhino { + include com.sun.script.javascript.**, sun.org.mozilla.javascript.**; +} + +/**************************************************************************/ + +module httpserver { + include com.sun.net.httpserver.**, sun.net.httpserver.**; +} + +/**************************************************************************/ + +module sctp { + // API and dependencies + include com.sun.nio.sctp.**, sun.nio.ch.Sctp*; +} + +/**************************************************************************/ + +module langtools { + include javax.tools.**, javax.lang.model.**, javax.annotation.processing.**; + + // include mirror API for now + include com.sun.mirror.**; + + // include the JSR292 APIs for now + include java.dyn.**, sun.dyn.**; +} + +/**************************************************************************/ + +module beans { + include java.beans.**, com.sun.beans.**, sun.beans.**; +} + +/**************************************************************************/ + +module jaxp-parsers-api { + include javax.xml.*, javax.xml.parsers.**, + org.w3c.dom.**, org.w3c.sax.**, org.xml.sax.**; +} + +module jaxp-api { + include javax.xml.**; + exclude javax.xml.crypto.**, // XML-DSIG + javax.xml.bind.**, // JAX-WS + javax.xml.soap.**, + javax.xml.ws.**; +} + +module jaxp-xerces-impl { + include com.sun.org.apache.xerces.internal.**; + + // include in xerces-impl due to circular dependencies + include com.sun.org.apache.xml.internal.serialize.**, + com.sun.xml.internal.stream.**; + exclude com.sun.xml.internal.stream.buffer.**; // JAX-WS +} + +// required by Xerces and JAX-WS +module jaxp-xerces-resolver { + include com.sun.org.apache.xml.internal.resolver.**; +} + +module jaxp-xalan { + include com.sun.org.apache.xalan.internal.**, + com.sun.org.apache.xpath.internal.**, + com.sun.org.apache.xml.internal.dtm.**, + com.sun.org.apache.xml.internal.res.**, + com.sun.org.apache.xml.internal.serializer.**, + com.sun.org.apache.xml.internal.utils.**, + com.sun.org.apache.bcel.internal.**, + com.sun.org.apache.regexp.internal.**, + com.sun.java_cup.internal.**; +} + +/**************************************************************************/ + +module jaxws-tools { + include com.sun.codemodel.**, + com.sun.xml.internal.dtdparser.**, + com.sun.xml.internal.rngom.**, + com.sun.xml.internal.xsom.**, + com.sun.istack.internal.tools.**, + com.sun.istack.internal.ws.**, + com.sun.tools.internal.xjc.**, + com.sun.tools.internal.ws.**, + com.sun.tools.internal.jxc.**, + org.relaxng.datatype.**; +} + +module jaxws { + include javax.jws.**, + javax.xml.bind.**, + javax.xml.soap.**, + javax.xml.ws.**, + org.relaxng.**, + com.sun.istack.internal.*, + com.sun.istack.internal.localization.*, + com.sun.xml.internal.**; + + // include JAF in this module + include javax.activation.**, com.sun.activation.**; + + include META-INF/mailcap.default, + META-INF/mimetypes.default; +} + +/**************************************************************************/ +module enterprise-base { + include javax.transaction.**, // JTA + javax.annotation.*; // Common annotations (JSR-250) +} + +/**************************************************************************/ +module corba { + include javax.activity.**, + javax.rmi.*, + javax.rmi.CORBA.*, + javax.transaction.**, + com.sun.corba.**, + com.sun.org.omg.**, + org.omg.**, + sun.corba.**; + + // JMX remote API + exclude org.omg.stub.javax.management.**; +} + +/**************************************************************************/ + +module client { + include java.applet.**, + java.awt.**, + javax.accessibility.*, + javax.imageio.**, + javax.print.**, + javax.sound.**, + javax.swing.**, + sun.applet.**, + sun.audio.**, + sun.awt.**, + sun.dc.**, + sun.font.**, + sun.java2d.**, + sun.print.**, + sun.swing.**, + com.sun.accessibility.**, + com.sun.awt.**, + com.sun.image.**, + com.sun.imageio.**, + com.sun.java.swing.*, // sajdi also contains classes in a subpackage; + // so use '*' instead of '**' + com.sun.java.swing.plaf.**, + com.sun.media.**, + com.sun.swing.**; + + // Bidi class in client module for now + include java.text.Bidi, sun.text.bidi.*; + + // PerformanceLogger and dependencies + include sun.misc.Ref, sun.misc.PerformanceLogger; + + // misc. dependencies that we need to examine + include sun.text.CodePointIterator, + sun.text.Char*, + sun.misc.Queue*, + sun.misc.FIFOQueueEnumerator, + sun.misc.LIFOQueueEnumerator; + + // content handlers + include sun.net.www.content.audio.**, + sun.net.www.content.image.**; +} + +/**************************************************************************/ + +module deploy { + // For now, all plugin and JNLP + include com.sun.java.browser.**, + netscape.**, + sun.plugin.**, + sun.plugin2.**,, + com.sun.deploy.**, + com.sun.javaws.**, + javax.jnlp.*, + com.sun.jnlp.*, + sun.jkernel.*; + + // Hook for http authentication + include sun.net.www.protocol.http.AuthCacheBridge; +} + +/**************************************************************************/ + +module net-compat { + // NTLM authentication support + include sun.net.www.protocol.http.ntlm.*; + + // ftp and mail clients + include sun.net.ftp.**, sun.net.smtp.**; + + // Legacy protocol handlers + include sun.net.www.protocol.**; + + // Legacy content handlers + include sun.net.www.content.**; + + include sun.net.Telnet*, + sun.net.TransferProtocolClient; +} + +/**************************************************************************/ + +// jar-tool and security-tools are JRE tools +module jar-tool { + include sun.tools.jar.**; +} + +module security-tools { + include sun.security.tools.**; + + // Used by security tools + include sun.security.util.PathList, sun.security.x509.CertAndKeyGen; + + exclude sun.security.tools.JarBASE64Encoder, + sun.security.tools.JarSigner, + sun.security.tools.JarSignerParameters, + sun.security.tools.JarSignerResources*, + sun.security.tools.SignatureFile, + sun.security.tools.TimestampedSigner; +} + +module jconsole { + include sun.tools.jconsole.**, + com.sun.tools.jconsole.*; +} + +module serialver { + include sun.tools.serialver.**; +} + +module gui-tools { + include jconsole, + serialver; + + include com.sun.tools.example.debug.bdi.**, + com.sun.tools.example.debug.gui.**, + com.sun.tools.internal.xjc.**; +} + +module attach { + include com.sun.tools.attach.**, + sun.tools.attach.**; +} + +module debugging { + include com.sun.jdi.**, com.sun.tools.jdi.**; +} + +module jdb { + include com.sun.tools.example.debug.**; +} + +module sajdi { + include sun.jvm.hotspot.**, + com.sun.java.swing.ui.**, + com.sun.java.swing.action.**; + + include toolbarButtonGraphics/**; + include sa.properties; +} + +module tools { + include attach, + debugging, + jaxws-tools, + jdb, + sajdi; + + // include gui-tools in tools module unless the tool binaries + // are modified to load the new gui-tools.jar + include gui-tools; + + include com.sun.tools.**, sun.tools.**, sun.security.tools.**, + com.sun.jarsigner.**, + com.sun.javac.**, + com.sun.javadoc.**, com.sun.source.**, + sun.jvmstat.**, + sun.rmi.rmic.**; +} + +/**************************************************************************/ + +module servicetag { + include com.sun.servicetag.**; +} + +/**************************************************************************/ + +// these classes will be removed from JRE - see 6909002 +module inputmethods-ext { + include com.sun.inputmethods.internal.**; +} + +/**************************************************************************/ + +module other { + include **; +} diff --git a/make/modules/modules.group b/make/modules/modules.group new file mode 100644 index 0000000000000000000000000000000000000000..64abd180718f7ecff8f22d8e37571b73dd9bcc6f --- /dev/null +++ b/make/modules/modules.group @@ -0,0 +1,29 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * Example: + * module jdbc { + * include jdbc-base, jdbc-enterprise, jdbc-odbc; + * } + */ diff --git a/make/modules/optional.depconfig b/make/modules/optional.depconfig new file mode 100644 index 0000000000000000000000000000000000000000..0811163e7150013ee9937cdf733b19909e71e09b --- /dev/null +++ b/make/modules/optional.depconfig @@ -0,0 +1,124 @@ +# public final java.nio.channels.SocketChannel getChannel() +@Optional + sun.security.ssl.BaseSSLSocketImpl -> java.nio.channels.SocketChannel + +# public XMLDecoder(java.io.InputStream) +# public XMLDecoder(java.io.InputStream, java.lang.Object) +# public XMLDecoder(java.io.InputStream, java.lang.Object, java.beans.ExceptionListener) +# public XMLDecoder(java.io.InputStream, java.lang.Object, java.beans.ExceptionListener, java.lang.ClassLoader) +# public XMLDecoder(org.xml.sax.InputSource) +@Optional + java.beans.XMLDecoder -> com.sun.beans.decoder.DocumentHandler + java.beans.XMLDecoder -> org.xml.sax.InputSource + +# public static org.xml.sax.helpers.DefaultHandler createHandler(java.lang.Object, java.beans.ExceptionListener, java.lang.ClassLoader) +@Optional + java.beans.XMLDecoder -> com.sun.beans.decoder.DocumentHandler + java.beans.XMLDecoder -> org.xml.sax.helpers.DefaultHandler + +# public final java.nio.channels.FileChannel getChannel() +@Optional + java.net.SocketInputStream -> java.nio.channels.FileChannel + +# public final java.nio.channels.FileChannel getChannel() +@Optional + java.net.SocketOutputStream -> java.nio.channels.FileChannel + +# public Scanner(java.io.File) +# public Scanner(java.io.File, java.lang.String) +@Optional + java.util.Scanner -> java.nio.channels.ReadableByteChannel + java.util.Scanner -> java.nio.channels.Channels + +# public Scanner(java.nio.file.FileRef) +# public Scanner(java.nio.file.FileRef, java.lang.String) +@Optional + java.util.Scanner -> java.nio.file.FileRef + java.util.Scanner -> java.nio.file.OpenOption + +# public Scanner(java.nio.channels.ReadableByteChannel) +# public Scanner(java.nio.channels.ReadableByteChannel, java.lang.String) +@Optional + java.util.Scanner -> java.nio.channels.ReadableByteChannel + java.util.Scanner -> java.nio.channels.Channels + +# private static void loadSnmpAgent(java.lang.String, java.util.Properties) +@Optional + sun.management.Agent -> sun.management.snmp.AdaptorBootstrap + +# public void connect() +@Optional + sun.net.www.protocol.http.HttpURLConnection -> java.net.SecureCacheResponse + +# private static sun.security.util.PermissionFactory permissionFactory() +@Optional + sun.security.util.SecurityConstants$AWT -> sun.awt.AWTPermissionFactory + +# sun.util.logging.LoggingSupport +@Optional + sun.util.logging.LoggingSupport -> java.util.logging.LoggingProxyImpl + +# public java.nio.channels.DatagramChannel getChannel() +@Optional + java.net.DatagramSocket -> java.nio.channels.DatagramChannel + +# public java.nio.channels.SocketChannel getChannel() +@Optional + java.net.Socket -> java.nio.channels.SocketChannel + +# public java.nio.channels.ServerSocketChannel getChannel() +@Optional + java.net.ServerSocket -> java.nio.channels.ServerSocketChannel + +# public final java.nio.channels.FileChannel getChannel() +@Optional + java.io.RandomAccessFile -> java.nio.channels.FileChannel + java.io.RandomAccessFile -> sun.nio.ch.FileChannelImpl + +# public static sun.nio.cs.StreamDecoder forDecoder(java.nio.channels.ReadableByteChannel, java.nio.charset.CharsetDecoder, int) +@Optional + sun.nio.cs.StreamDecoder -> java.nio.channels.ReadableByteChannel + +# private static java.nio.channels.FileChannel getChannel(java.io.FileInputStream) +# StreamDecoder(java.io.InputStream, java.lang.Object, java.nio.charset.CharsetDecoder) +@Optional + sun.nio.cs.StreamDecoder -> java.nio.channels.FileChannel + +# StreamDecoder(java.nio.channels.ReadableByteChannel, java.nio.charset.CharsetDecoder, int) +@Optional + sun.nio.cs.StreamDecoder -> java.nio.channels.ReadableByteChannel + +# public static java.io.File createTemporaryFile(java.lang.String, java.lang.String, java.nio.file.attribute.FileAttribute[]) +@Optional + java.io.File -> java.io.TempFileHelper + java.io.File -> java.nio.file.attribute.FileAttribute + +# public java.nio.file.Path toPath() +@Optional + java.io.File -> java.nio.file.Paths + java.io.File -> java.nio.file.Path + +# public static sun.nio.cs.StreamEncoder forEncoder(java.nio.channels.WritableByteChannel, java.nio.charset.CharsetEncoder, int) +# private StreamEncoder(java.nio.channels.WritableByteChannel, java.nio.charset.CharsetEncoder, int) +@Optional + sun.nio.cs.StreamEncoder -> java.nio.channels.WritableByteChannel + +# public java.nio.channels.FileChannel getChannel() +@Optional + java.io.FileOutputStream -> java.nio.channels.FileChannel + java.io.FileOutputStream -> sun.nio.ch.FileChannelImpl + +# public java.nio.channels.FileChannel getChannel() +@Optional + java.io.FileInputStream -> java.nio.channels.FileChannel + java.io.FileInputStream -> sun.nio.ch.FileChannelImpl + +# public void loadFromXML(java.io.InputStream) +# public void storeToXML(java.io.OutputStream, java.lang.String, java.lang.String) +@Optional + java.util.Properties -> java.util.XMLUtils + +# public static java.nio.channels.Channel inheritedChannel() +@Optional + java.lang.System -> java.nio.channels.Channel + java.lang.System -> java.nio.channels.spi.SelectorProvider diff --git a/make/modules/tools/Makefile b/make/modules/tools/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fcf514bec888bfe33a431fb79b40c7c119dc8c2e --- /dev/null +++ b/make/modules/tools/Makefile @@ -0,0 +1,85 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Sun designates this +# particular file as subject to the "Classpath" exception as provided +# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# +# Makefile for building the classanalyzer tool +# + +BUILDDIR = ../.. +PACKAGE = com.sun.classanalyzer +PRODUCT = tools +PROGRAM = classanalyzer +include $(BUILDDIR)/common/Defs.gmk + +BUILDTOOL_SOURCE_ROOT = src +BUILDTOOL_MAIN = $(PKGDIR)/ClassAnalyzer.java +BUILTTOOL_MAINCLASS = $(subst /,.,$(BUILDTOOL_MAIN:%.java=%)) + +BUILDTOOL_MAIN_SOURCE_FILE = $(BUILDTOOL_SOURCE_ROOT)/$(BUILDTOOL_MAIN) +BUILDTOOL_MANIFEST_FILE = $(BUILDTOOLCLASSDIR)/$(PROGRAM)_manifest.mf +BUILDTOOL_JAR_FILE = $(BUILDTOOLJARDIR)/$(PROGRAM).jar + +FILES_java := $(shell $(CD) $(BUILDTOOL_SOURCE_ROOT) \ + && $(FIND) $(PKGDIR) $(SCM_DIRS_prune) -o -type f -print) +FILES_class = $(FILES_java:%.java=$(BUILDTOOLCLASSDIR)/%.class) + +all build: $(BUILDTOOL_JAR_FILE) tool_info + +$(BUILDTOOL_MANIFEST_FILE): $(BUILDTOOL_MAIN_SOURCE_FILE) + @$(prep-target) + $(ECHO) "Main-Class: $(BUILTTOOL_MAINCLASS)" > $@ + +$(BUILDTOOLCLASSDIR)/%.class : $(BUILDTOOL_SOURCE_ROOT)/%.java + @$(prep-target) + $(JAVAC_CMD) \ + -sourcepath $(BUILDTOOL_SOURCE_ROOT) \ + -d $(BUILDTOOLCLASSDIR) $< + +$(BUILDTOOL_JAR_FILE): $(BUILDTOOL_MANIFEST_FILE) $(FILES_class) + @$(prep-target) + $(BOOT_JAR_CMD) cfm $@ $(BUILDTOOL_MANIFEST_FILE) \ + -C $(BUILDTOOLCLASSDIR) $(PKGDIR) \ + $(BOOT_JAR_JFLAGS) || $(RM) $@ + $(java-vm-cleanup) + +# Printing out a build tool information line +define printBuildToolSetting +if [ "$2" != "" ] ; then $(PRINTF) "%-25s %s\n" "$1:" "$2"; fi +endef + +# Print out the build tool information +tool_info: + @$(ECHO) "=========================================================" + @$(call printBuildToolSetting,BUILDTOOL,$(PROGRAM)) + @$(call printBuildToolSetting,PACKAGE,$(PACKAGE)) + @$(call printBuildToolSetting,BUILDTOOL_SOURCE_ROOT,$(BUILDTOOL_SOURCE_ROOT)) + @$(call printBuildToolSetting,BUILTTOOL_MAINCLASS,$(BUILTTOOL_MAINCLASS)) + @$(call printBuildToolSetting,BUILDTOOL_JAR_FILE,$(BUILDTOOL_JAR_FILE)) + @$(ECHO) "=========================================================" + +clean clobber:: + @$(RM) -rf $(BUILDTOOLCLASSDIR)/$(PKGDIR) + @$(RM) $(BUILDTOOL_MANIFEST_FILE) + @$(RM) $(BUILDTOOL_JAR_FILE) diff --git a/make/modules/tools/build.xml b/make/modules/tools/build.xml new file mode 100644 index 0000000000000000000000000000000000000000..993ccb8de071689b5a1d1ab8efd412e49d5b1e5d --- /dev/null +++ b/make/modules/tools/build.xml @@ -0,0 +1,33 @@ + + + + diff --git a/make/modules/tools/nbproject/project.properties b/make/modules/tools/nbproject/project.properties new file mode 100644 index 0000000000000000000000000000000000000000..00b74962d973502055d61fcf241710b42bc6b05f --- /dev/null +++ b/make/modules/tools/nbproject/project.properties @@ -0,0 +1,92 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of Sun Microsystems nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +application.title=classanalyzer +application.vendor=mchung +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form + +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources + +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results + +cp.extra=${tools.jar} + +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} + +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/classanalyzer.jar +dist.javadoc.dir=${dist.dir}/javadoc + +excludes= + +file.reference.tools.jar=${jdk.home}/lib/tools.jar +file.reference.tools-src=src +includes=** +jar.compress=false +javac.classpath=\ + ${file.reference.tools.jar} +javac.deprecation=false +javac.source=1.5 +javac.target=1.5 +javac.test.classpath= +javadoc.author=false +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=false +javadoc.use=false +javadoc.version=false +main.class=com.sun.classanalyzer.ClassAnalyzer +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +platform.active=JDK_1.6 +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs=-Xmx256m +run.test.classpath= +source.encoding=UTF-8 +src.dir=${file.reference.tools-src} diff --git a/make/modules/tools/nbproject/project.xml b/make/modules/tools/nbproject/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..b8b0aeafe0703952e50a43be116f5178d9f9377e --- /dev/null +++ b/make/modules/tools/nbproject/project.xml @@ -0,0 +1,45 @@ + + + + + org.netbeans.modules.java.j2seproject + + + classanalyzer + + + + + + + + diff --git a/make/modules/tools/src/com/sun/classanalyzer/AnnotatedDependency.java b/make/modules/tools/src/com/sun/classanalyzer/AnnotatedDependency.java new file mode 100644 index 0000000000000000000000000000000000000000..72b21d9949eb362158a19e485906813b35d9c4c1 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/AnnotatedDependency.java @@ -0,0 +1,627 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ +package com.sun.classanalyzer; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.Map; + +import com.sun.classanalyzer.Module.Reference; +import java.util.LinkedList; +import java.util.TreeMap; + +/** + * + * @author Mandy Chung + */ +public abstract class AnnotatedDependency implements Comparable { + + final Klass from; + final List classes; + protected boolean optional; + String description; + Klass.Method method; + private List filters = null; + + public AnnotatedDependency(Klass klass) { + this(klass, false); + } + + public AnnotatedDependency(Klass klass, boolean optional) { + this.from = klass; + this.classes = new ArrayList(); + this.optional = optional; + } + + abstract String getTag(); + + abstract boolean isDynamic(); + + void setMethod(Klass.Method m) { + this.method = m; + } + + void addElement(String element, List value) { + if (element.equals("value")) { + addValue(value); + } else if (element.equals("description")) { + description = value.get(0); + } else if (element.equals("optional")) { + optional = value.get(0).equals("1") || Boolean.parseBoolean(value.get(0)); + } + } + + void addValue(List value) { + for (String s : value) { + if ((s = s.trim()).length() > 0) { + classes.add(s); + } + } + } + + List getValue() { + return classes; + } + + boolean isOptional() { + return optional; + } + + boolean isEmpty() { + return classes.isEmpty(); + } + + boolean matches(String classname) { + synchronized (this) { + // initialize filters + if (filters == null) { + filters = new ArrayList(); + for (String pattern : classes) { + filters.add(new Filter(pattern)); + } + + } + } + + for (Filter f : filters) { + if (f.matches(classname)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (String v : getValue()) { + if (sb.length() == 0) { + sb.append(getTag()); + sb.append("\n"); + } else { + sb.append("\n"); + } + sb.append(" "); + sb.append(from.getClassName()).append(" -> "); + sb.append(v); + } + return sb.toString(); + } + + @Override + public int compareTo(AnnotatedDependency o) { + if (from == o.from) { + if (this.getClass().getName().equals(o.getClass().getName())) { + String s1 = classes.isEmpty() ? "" : classes.get(0); + String s2 = o.classes.isEmpty() ? "" : o.classes.get(0); + return s1.compareTo(s2); + } else { + return this.getClass().getName().compareTo(o.getClass().getName()); + } + + } else { + return from.compareTo(o.from); + } + } + + @Override + public int hashCode() { + int hashcode = 7 + 73 * from.hashCode(); + for (String s : classes) { + hashcode ^= s.hashCode(); + } + return hashcode; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof AnnotatedDependency)) { + return false; + } + AnnotatedDependency other = (AnnotatedDependency) obj; + boolean ret = this.from.equals(other.from) && this.classes.size() == other.classes.size(); + if (ret == true) { + for (int i = 0; i < this.classes.size(); i++) { + ret = ret && this.classes.get(i).equals(other.classes.get(i)); + } + } + return ret; + } + + static class ClassForName extends AnnotatedDependency { + + public ClassForName(Klass klass, boolean optional) { + super(klass, optional); + } + + @Override + String getTag() { + if (this.optional) { + return TAG + "(optional)"; + } else { + return TAG; + } + } + + @Override + boolean isDynamic() { + return true; + } + static final String TYPE = "sun.annotation.ClassForName"; + static final String TAG = "@ClassForName"; + } + + static class NativeFindClass extends AnnotatedDependency { + + public NativeFindClass(Klass klass, boolean optional) { + super(klass, optional); + } + + @Override + String getTag() { + if (this.optional) { + return TAG + "(optional)"; + } else { + return TAG; + } + } + + @Override + boolean isDynamic() { + return true; + } + static final String TYPE = "sun.annotation.NativeFindClass"; + static final String TAG = "@NativeFindClass"; + } + + static class Provider extends AnnotatedDependency { + + private List services = new ArrayList(); + + Provider(Klass klass) { + super(klass, true); + } + + @Override + boolean isDynamic() { + return true; + } + + public List services() { + return services; + } + + @Override + void addElement(String element, List value) { + if (element.equals("service")) { + List configFiles = new ArrayList(); + for (String s : value) { + if ((s = s.trim()).length() > 0) { + configFiles.add(metaInfPath + s); + } + } + addValue(configFiles); + } + } + + @Override + void addValue(List value) { + for (String s : value) { + if ((s = s.trim()).length() > 0) { + if (s.startsWith("META-INF")) { + services.add(s); + readServiceConfiguration(s, classes); + } else { + throw new RuntimeException("invalid value" + s); + } + } + } + } + + boolean isEmpty() { + return services.isEmpty(); + } + static final String metaInfPath = + "META-INF" + File.separator + "services" + File.separator; + + static void readServiceConfiguration(String config, List names) { + BufferedReader br = null; + try { + InputStream is = ClassPath.open(config); + if (is != null) { + // Properties doesn't perserve the order of the input file + br = new BufferedReader(new InputStreamReader(is, "utf-8")); + int lc = 1; + while ((lc = parseLine(br, lc, names)) >= 0); + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + } + + // Parse a single line from the given configuration file, adding the name + // on the line to the names list. + // + private static int parseLine(BufferedReader r, int lc, List names) throws IOException { + String ln = r.readLine(); + if (ln == null) { + return -1; + } + int ci = ln.indexOf('#'); + if (ci >= 0) { + ln = ln.substring(0, ci); + } + ln = ln.trim(); + int n = ln.length(); + if (n != 0) { + if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) { + throw new RuntimeException("Illegal configuration-file syntax"); + } + int cp = ln.codePointAt(0); + if (!Character.isJavaIdentifierStart(cp)) { + throw new RuntimeException("Illegal provider-class name: " + ln); + } + for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { + cp = ln.codePointAt(i); + if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) { + throw new RuntimeException("Illegal provider-class name: " + ln); + } + } + if (!names.contains(ln)) { + names.add(ln); + } + } + return lc + 1; + } + + @Override + String getTag() { + return TAG; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof AnnotatedDependency)) { + return false; + } + Provider other = (Provider) obj; + boolean ret = this.from.equals(other.from) && + this.services.size() == other.services.size(); + if (ret == true) { + for (int i = 0; i < this.services.size(); i++) { + ret = ret && this.services.get(i).equals(other.services.get(i)); + } + } + return ret; + } + + @Override + public int hashCode() { + int hashcode = 7 + 73 * from.hashCode(); + for (String s : services) { + hashcode ^= s.hashCode(); + } + return hashcode; + } + + @Override + public List getValue() { + List result = new ArrayList(); + result.addAll(services); + return result; + } + static final String TYPE = "sun.annotation.Provider"; + static final String TAG = "@Provider"; + } + + static class OptionalDependency extends AnnotatedDependency { + + static boolean isOptional(Klass from, Klass to) { + synchronized (OptionalDependency.class) { + if (optionalDepsMap == null) { + // Build a map of classes to its optional dependencies + initDependencies(); + } + } + for (Reference ref : optionalDepsMap.keySet()) { + if (ref.referrer() == from && ref.referree() == to) { + return true; + } + } + return false; + } + + OptionalDependency(Klass klass) { + super(klass, true); + } + + @Override + boolean isDynamic() { + return false; + } + + @Override + String getTag() { + return TAG; + } + static final String TYPE = "sun.annotation.Optional"; + static final String TAG = "@Optional"; + } + + static class CompilerInline extends AnnotatedDependency { + + public CompilerInline(Klass klass) { + super(klass); + } + + @Override + String getTag() { + return TAG; + } + + @Override + boolean isDynamic() { + return false; + } + static final String TYPE = "sun.annotation.Inline"; + static final String TAG = "@Inline"; + } + + static class Filter { + + final String pattern; + final String regex; + + Filter(String pattern) { + this.pattern = pattern; + + boolean isRegex = false; + for (int i = 0; i < pattern.length(); i++) { + char p = pattern.charAt(i); + if (p == '*' || p == '[' || p == ']') { + isRegex = true; + break; + } + } + + if (isRegex) { + this.regex = convertToRegex(pattern); + } else { + this.regex = null; + } + } + + private String convertToRegex(String pattern) { + StringBuilder sb = new StringBuilder(); + int i = 0; + int index = 0; + int plen = pattern.length(); + while (i < plen) { + char p = pattern.charAt(i); + if (p == '*') { + sb.append("(").append(pattern.substring(index, i)).append(")"); + if (i + 1 < plen && pattern.charAt(i + 1) == '*') { + sb.append(".*"); + index = i + 2; + } else { + sb.append("[^\\.]*"); + index = i + 1; + } + } else if (p == '[') { + int j = i + 1; + while (j < plen) { + if (pattern.charAt(j) == ']') { + break; + } + j++; + } + if (j >= plen || pattern.charAt(j) != ']') { + throw new RuntimeException("Malformed pattern " + pattern); + } + sb.append("(").append(pattern.substring(index, i)).append(")"); + sb.append(pattern.substring(i, j + 1)); + index = j + 1; + i = j; + } + i++; + } + if (index < plen) { + sb.append("(").append(pattern.substring(index, plen)).append(")"); + } + return sb.toString(); + } + + boolean matches(String name) { + if (regex == null) { + // the pattern is not a regex + return name.equals(pattern); + } else { + return name.matches(regex); + } + } + } + + static boolean isValidType(String type) { + if (type.endsWith("(optional)")) { + int len = type.length() - "(optional)".length(); + type = type.substring(0, len); + } + return type.equals(ClassForName.TYPE) || type.equals(ClassForName.TAG) || + type.equals(NativeFindClass.TYPE) || type.equals(NativeFindClass.TAG) || + type.equals(Provider.TYPE) || type.equals(Provider.TAG) || + type.equals(CompilerInline.TYPE) || type.equals(CompilerInline.TAG) || + type.equals(OptionalDependency.TYPE) || type.equals(OptionalDependency.TAG); + } + + static AnnotatedDependency newAnnotatedDependency(String tag, String value, Klass klass) { + AnnotatedDependency dep = newAnnotatedDependency(tag, klass); + if (dep != null) { + dep.addValue(Collections.singletonList(value)); + } + return dep; + } + static List annotatedDependencies = new LinkedList(); + static List optionalDependencies = new LinkedList(); + + static AnnotatedDependency newAnnotatedDependency(String type, Klass klass) { + boolean optional = false; + if (type.endsWith("(optional)")) { + optional = true; + int len = type.length() - "(optional)".length(); + type = type.substring(0, len); + } + + if (type.equals(OptionalDependency.TYPE) || type.equals(OptionalDependency.TAG)) { + return newOptionalDependency(klass); + } + + AnnotatedDependency dep; + if (type.equals(ClassForName.TYPE) || type.equals(ClassForName.TAG)) { + dep = new ClassForName(klass, optional); + } else if (type.equals(NativeFindClass.TYPE) || type.equals(NativeFindClass.TAG)) { + dep = new NativeFindClass(klass, optional); + } else if (type.equals(Provider.TYPE) || type.equals(Provider.TAG)) { + dep = new Provider(klass); + } else if (type.equals(CompilerInline.TYPE) || type.equals(CompilerInline.TAG)) { + dep = new CompilerInline(klass); + } else { + return null; + } + klass.addAnnotatedDep(dep); + annotatedDependencies.add(dep); + return dep; + } + + static OptionalDependency newOptionalDependency(Klass klass) { + OptionalDependency dep = new OptionalDependency(klass); + optionalDependencies.add(dep); + return dep; + } + static Map> annotatedDepsMap = null; + static Map> optionalDepsMap = null; + + static Map> getReferences(Module m) { + // ensure it's initialized + initDependencies(); + + Map> result = new TreeMap>(); + for (Reference ref : annotatedDepsMap.keySet()) { + if (m.contains(ref.referrer()) && m.isModuleDependence(ref.referree())) { + result.put(ref, annotatedDepsMap.get(ref)); + } + } + return result; + } + + static Set getDependencies(Module m) { + // ensure it's initialized + initDependencies(); + + Set deps = new TreeSet(); + for (Reference ref : annotatedDepsMap.keySet()) { + if (m.contains(ref.referrer())) { + Module other = m.getModuleDependence(ref.referree()); + if (other != null) { + for (AnnotatedDependency ad : annotatedDepsMap.get(ref)) { + Module.Dependency d = new Module.Dependency(other, ad.isOptional(), ad.isDynamic()); + deps.add(d); + } + } + } + } + return deps; + } + + synchronized static void initDependencies() { + if (annotatedDepsMap != null) { + return; + } + + // Build a map of references to its dependencies + annotatedDepsMap = new TreeMap>(); + optionalDepsMap = new TreeMap>(); + + for (Klass k : Klass.getAllClasses()) { + for (AnnotatedDependency ad : annotatedDependencies) { + if (ad.matches(k.getClassName())) { + Reference ref = new Reference(ad.from, k); + Set set = annotatedDepsMap.get(ref); + if (set == null) { + set = new TreeSet(); + annotatedDepsMap.put(ref, set); + } + set.add(ad); + } + } + + for (AnnotatedDependency ad : optionalDependencies) { + if (ad.matches(k.getClassName())) { + Reference ref = new Reference(ad.from, k); + Set set = optionalDepsMap.get(ref); + if (set == null) { + set = new TreeSet(); + optionalDepsMap.put(ref, set); + } + set.add(ad); + } + } + } + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/AnnotationParser.java b/make/modules/tools/src/com/sun/classanalyzer/AnnotationParser.java new file mode 100644 index 0000000000000000000000000000000000000000..7d984aa2e74b3a58ce6437c764d924105182ba0c --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/AnnotationParser.java @@ -0,0 +1,293 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.classanalyzer; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.Annotation; +import com.sun.tools.classfile.ExtendedAnnotation; +import com.sun.tools.classfile.Annotation.Annotation_element_value; +import com.sun.tools.classfile.Annotation.Array_element_value; +import com.sun.tools.classfile.Annotation.Class_element_value; +import com.sun.tools.classfile.Annotation.Enum_element_value; +import com.sun.tools.classfile.Annotation.Primitive_element_value; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.Descriptor; +import com.sun.tools.classfile.Descriptor.InvalidDescriptor; +import java.util.ArrayList; +import java.util.List; + +import com.sun.classanalyzer.AnnotatedDependency.*; +import java.io.File; +import java.io.PrintWriter; +import java.util.Map; +import java.util.Set; + +/** + * + * @author Mandy Chung + */ +public class AnnotationParser { + + static boolean parseAnnotation = false; + static void setParseAnnotation(boolean newValue) { + parseAnnotation = newValue; + } + + private final ClassFileParser cfparser; + public AnnotationParser(ClassFileParser cfparser) { + this.cfparser = cfparser; + } + + private AnnotatedDependency addAnnotation(Annotation annot, Klass.Method method) { + String type = getType(annot.type_index); + AnnotatedDependency dep = AnnotatedDependency.newAnnotatedDependency(type, cfparser.this_klass); + if (dep != null) { + for (int i = 0; i < annot.num_element_value_pairs; i++) { + Element element = getElement(annot.element_value_pairs[i]); + dep.addElement(element.name, element.value); + } + dep.setMethod(method); + } + return dep; + } + + private AnnotatedDependency addAnnotation(ExtendedAnnotation annot, Klass.Method method) { + return addAnnotation(annot.annotation, method); + } + + class Element { + + String name; + List value; + + Element(String name) { + this.name = name; + this.value = new ArrayList(); + } + + void add(String v) { + value.add(v); + } + } + + Element getElement(Annotation.element_value_pair pair) { + Element element = new Element(getName(pair.element_name_index)); + evp.parse(pair.value, element); + return element; + } + + private String getType(int index) { + try { + Descriptor d = new Descriptor(index); + return d.getFieldType(cfparser.classfile.constant_pool); + } catch (ConstantPoolException ignore) { + } catch (InvalidDescriptor ignore) { + } + return "Unknown"; + } + + private String getName(int index) { + return cfparser.constantPoolParser.stringValue(index); + } + element_value_Parser evp = new element_value_Parser(); + + class element_value_Parser implements Annotation.element_value.Visitor { + + public Void parse(Annotation.element_value value, Element element) { + value.accept(this, element); + return null; + } + + public Void visitPrimitive(Primitive_element_value ev, Element element) { + String value = getName(ev.const_value_index); + element.add(value); + return null; + } + + public Void visitEnum(Enum_element_value ev, Element element) { + String value = getName(ev.type_name_index) + "." + getName(ev.const_name_index); + element.add(value); + return null; + } + + public Void visitClass(Class_element_value ev, Element element) { + String value = getName(ev.class_info_index) + ".class"; + element.add(value); + return null; + } + + public Void visitAnnotation(Annotation_element_value ev, Element element) { + // AnnotationParser.this.addAnnotation(ev.annotation_value); + throw new UnsupportedOperationException("Not supported: " + ev); + } + + public Void visitArray(Array_element_value ev, Element element) { + for (int i = 0; i < ev.num_values; i++) { + parse(ev.values[i], element); + } + return null; + } + } + + void parseAttributes(Attributes attributes, Klass.Method method) { + if (!parseAnnotation) { + return; + } + + visitRuntimeAnnotations((RuntimeVisibleAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleAnnotations), method); + visitRuntimeAnnotations((RuntimeInvisibleAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleAnnotations), method); + visitRuntimeTypeAnnotations((RuntimeVisibleTypeAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleTypeAnnotations), method); + visitRuntimeTypeAnnotations((RuntimeInvisibleTypeAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleTypeAnnotations), method); + visitRuntimeParameterAnnotations((RuntimeVisibleParameterAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleParameterAnnotations), method); + visitRuntimeParameterAnnotations((RuntimeInvisibleParameterAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleParameterAnnotations), method); + } + + public void visitRuntimeAnnotations(RuntimeAnnotations_attribute attr, Klass.Method method) { + if (attr == null) { + return; + } + + for (int i = 0; i < attr.annotations.length; i++) { + addAnnotation(attr.annotations[i], method); + } + } + + public void visitRuntimeTypeAnnotations(RuntimeTypeAnnotations_attribute attr, Klass.Method method) { + if (attr == null) { + return; + } + + for (int i = 0; i < attr.annotations.length; i++) { + addAnnotation(attr.annotations[i], method); + } + } + + public void visitRuntimeParameterAnnotations(RuntimeParameterAnnotations_attribute attr, Klass.Method method) { + if (attr == null) { + return; + } + + for (int param = 0; param < attr.parameter_annotations.length; param++) { + for (int i = 0; i < attr.parameter_annotations[param].length; i++) { + addAnnotation(attr.parameter_annotations[param][i], method); + } + } + } + + void parseAttributes(Attributes attributes) { + parseAttributes(attributes, null); + } + + public static void main(String[] args) throws Exception { + String jdkhome = null; + String output = "."; + + // process arguments + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-jdkhome")) { + if (i < args.length) { + jdkhome = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-output")) { + output = args[i++]; + } else { + usage(); + } + } + if (jdkhome == null) { + usage(); + } + + // parse annotation and code attribute to find all references + // to Class.forName etc + CodeAttributeParser.setParseCodeAttribute(true); + AnnotationParser.setParseAnnotation(true); + + ClassPath.setJDKHome(jdkhome); + ClassPath.parseAllClassFiles(); + + PrintWriter writer = new PrintWriter(new File(output, "jdk7.depconfig")); + + try { + for (Klass k : Klass.getAllClasses()) { + for (AnnotatedDependency dep : k.getAnnotatedDeps()) { + if (dep.isEmpty()) { + continue; + } + writer.format("# %s \n", dep.method == null ? dep.from : dep.method); + writer.format("%s\n\n", dep); + } + } + } finally { + writer.close(); + } + + writer = new PrintWriter(new File(output, "optional.depconfig")); + try { + AnnotatedDependency prev = null; + for (AnnotatedDependency dep : AnnotatedDependency.optionalDependencies) { + if (prev != null && !dep.equals(prev)) { + writer.format("%s\n\n", prev); + } + writer.format("# %s \n", dep.method == null ? dep.from : dep.method); + prev = dep; + } + if (prev != null) { + writer.format("%s\n\n", prev); + } + } finally { + writer.close(); + } + + writer = new PrintWriter(new File(output, "runtime.references")); + try { + for (Map.Entry> entry : CodeAttributeParser.runtimeReferences.entrySet()) { + writer.format("References to %s\n", entry.getKey()); + Klass prev = null; + for (Klass.Method m : entry.getValue()) { + if (prev == null || prev != m.getKlass()) { + writer.format(" %-50s # %s\n", m.getKlass(), m); + } else if (prev == m.getKlass()) { + writer.format(" %-50s # %s\n", "", m); + } + prev = m.getKlass(); + } + } + } finally { + writer.close(); + } + } + + private static void usage() { + System.out.println("Usage: AnnotationParser "); + System.out.println("Options: "); + System.out.println("\t-jdkhome where all jars will be parsed"); + System.out.println("\t-depconfig "); + System.out.println("\t-optional "); + System.exit(-1); + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/BootAnalyzer.java b/make/modules/tools/src/com/sun/classanalyzer/BootAnalyzer.java new file mode 100644 index 0000000000000000000000000000000000000000..06e332ace7c372642cbc2f0f0904e67c31f7ce69 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/BootAnalyzer.java @@ -0,0 +1,819 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ +package com.sun.classanalyzer; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.File; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.*; +import static com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.Instruction.TypeKind; +import com.sun.tools.classfile.Type.*; + +/** + * Generate the module config for the boot module with + * a given set of roots (classes or methods) and exclude list. + * + * This tool does method-level dependency analysis starting + * from the root set and follows references transitively as follows: + *
    + *
  • For a given class, it will parse the ClassFile to + * find its superclass and superinterfaces and also + * its static initializer <clinit>.
  • + *
  • For each method, it will parse its Code attribute + * to look for a Methodref, Fieldref, and InterfaceMethodref. + *
  • + *
  • For each Fieldref, it will include the type of + * the field in the dependency.
  • + *
  • For each MethodRef, it will follow all references in + * that method.
  • + *
  • For each InterfaceMethodref, it will follow all references in + * that method defined its implementation classes in + * the resulting dependency list.
  • + *
+ * + * Limitation: + *
    + *
  • For each Methodref, it only parses the method of + * the specified type. It doesn't analyze the class hierarchy + * and follow references of its subclasses since it ends up + * pulls in many unnecessary dependencies. For now, + * the list of subclasses and methods need to be listed in + * the root set.
  • + *
+ * + * @author Mandy Chung + */ +public class BootAnalyzer { + + public static void main(String[] args) throws Exception { + String jdkhome = null; + String config = null; + String output = "."; + boolean printClassList = false; + + // process arguments + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-jdkhome")) { + if (i < args.length) { + jdkhome = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-config")) { + config = args[i++]; + } else if (arg.equals("-output")) { + output = args[i++]; + } else if (arg.equals("-classlist")) { + printClassList = true; + } else { + usage(); + } + } + + + + if (jdkhome == null || config == null) { + usage(); + } + + File jre = new File(jdkhome, "jre"); + if (jre.exists()) { + ClassPath.setJDKHome(jdkhome); + } else { + File classes = new File(jdkhome, "classes"); + if (classes.exists()) { + ClassPath.setClassPath(classes.getCanonicalPath()); + } else { + throw new RuntimeException("Invalid jdkhome: " + jdkhome); + } + } + + parseConfigFile(config); + followRoots(); + + // create output directory if it doesn't exist + File dir = new File(output); + if (!dir.isDirectory()) { + if (!dir.exists()) { + boolean created = dir.mkdir(); + if (!created) { + throw new RuntimeException("Unable to create `" + dir + "'"); + } + } + } + + String bootmodule = "boot"; + String bootconfig = resolve(dir, bootmodule, "config"); + printBootConfig(bootconfig, bootmodule); + + List list = ModuleConfig.readConfigurationFile(bootconfig); + Module module = Module.addModule(list.get(0)); + for (Klass k : Klass.getAllClasses()) { + module.addKlass(k); + } + module.fixupDependencies(); + + if (printClassList) { + module.printClassListTo(resolve(dir, bootmodule, "classlist")); + module.printSummaryTo(resolve(dir, bootmodule, "summary")); + } + } + + // print boot.config file as an input to the ClassAnalyzer + private static void printBootConfig(String output, String bootmodule) throws IOException { + + File f = new File(output); + PrintWriter writer = new PrintWriter(f); + try { + int count = 0; + writer.format("module %s {%n", bootmodule); + for (Klass k : Klass.getAllClasses()) { + if (count++ == 0) { + writer.format("%4s%7s %s", "", "include", k); + } else { + writer.format(",%n"); + writer.format("%4s%7s %s", "", "", k); + } + } + writer.format(";%n}%n"); + } finally { + writer.close(); + } + } + + private static String resolve(File dir, String mname, String suffix) { + File f = new File(dir, mname + "." + suffix); + return f.toString(); + + } + static List methods = new LinkedList(); + static Deque pending = new ArrayDeque(); + static Deque interfaceMethodRefs = new ArrayDeque(); + static Filter filter = new Filter(); + + private static void followRoots() throws IOException { + MethodDescriptor md = null; + + while ((md = pending.poll()) != null) { + if (!methods.contains(md)) { + methods.add(md); + if (md.classname.isEmpty()) { + trace("Warning: class missing %s%n", md); + continue; + } + + if (filter.isExcluded(md.classname)) { + trace("excluded %s%n", md); + } else { + KlassInfo kinfo = getKlassInfo(md.classname); + if (kinfo.classname.contains("$")) { + int pos = kinfo.classname.lastIndexOf('$'); + String outer = kinfo.classname.substring(0, pos); + if (!cache.containsKey(outer)) { + trace(" include outer class %s%n", outer); + getKlassInfo(outer).ensureParse(); + } + } + + kinfo.ensureParse(); + if (md.methodname.length() > 0) { + if (filter.isExcluded(md.name)) { + trace("excluded %s%n", md); + } else { + if (md.interfaceMethodRef) { + trace("interface methodref %s%n", md); + interfaceMethodRefs.add(md); + } else { + List descriptors = kinfo.parse(md); + if (descriptors.isEmpty()) { + if (kinfo.getSuperclass() != null) { + String sn = kinfo.getSuperclass().classname; + MethodDescriptor superMD = new MethodDescriptor(sn + "." + md.methodname, md.descriptor, false); + if (!methods.contains(superMD) && !pending.contains(superMD)) { + trace(" delegated %s to %s%n", md, superMD); + pending.add(superMD); + } + } else if (kinfo.isClass()) { + trace(" %s (not found)%n", md); + } else { + trace(" %s (interface)%n", md); + } + } else { + if (md.descriptor.equals("*")) { + trace(" parsed %s : ", md.name); + for (String s : descriptors) { + trace(" %s", s); + } + trace("%n"); + } + } + } + } + } + } + } + if (pending.isEmpty()) { + for (Klass k : Klass.getAllClasses()) { + if (k.getFileSize() == 0) { + getKlassInfo(k.getClassName()).ensureParse(); + } + } + while ((md = interfaceMethodRefs.poll()) != null) { + addSubClassMethods(md); + } + } + } + } + + static void addSubClassMethods(MethodDescriptor md) throws IOException { + for (KlassInfo kinfo : getSubClasses(md.classname)) { + String methodname = kinfo.classname + "." + md.methodname; + MethodDescriptor other = new MethodDescriptor(methodname, md.descriptor, false); + if (!methods.contains(other) && !pending.contains(other)) { + trace("Warning: subclass from %s to %s%n", md.classname, other); + pending.add(other); + } + } + } + private final static String privilegedActionInterf = "java.security.PrivilegedAction"; + private final static String privilegedExceptionActionInterf = "java.security.PrivilegedExceptionAction"; + + static boolean isPrivilegedAction(String classname) { + if (classname.isEmpty()) { + return false; + } + KlassInfo kinfo = getKlassInfo(classname); + for (KlassInfo ki : kinfo.getInterfaces()) { + String interf = ki.classname; + if (interf.equals(privilegedActionInterf) || + interf.equals(privilegedExceptionActionInterf)) { + return true; + } + } + return false; + } + static Map cache = new HashMap(); + + static KlassInfo getKlassInfo(String classname) { + classname = classname.replace('/', '.'); + + KlassInfo kinfo = cache.get(classname); + if (kinfo == null) { + kinfo = new KlassInfo(classname); + cache.put(classname, kinfo); + } + return kinfo; + } + + static class KlassInfo { + + final String classname; + private ClassFileParser parser; + private KlassInfo superclass; + private List interfaces = new LinkedList(); + + KlassInfo(String classname) { + this.classname = classname; + } + + boolean isClass() { + ensureParse(); + return parser.classfile.isClass(); + } + + KlassInfo getSuperclass() { + ensureParse(); + return superclass; + } + + List getInterfaces() { + ensureParse(); + return java.util.Collections.unmodifiableList(interfaces); + } + + void ensureParse() { + try { + getClassFileParser(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + synchronized ClassFileParser getClassFileParser() throws IOException { + if (parser == null) { + parser = ClassPath.parserForClass(classname); + if (parser != null) { + parseClassFile(); + List descriptors = parse(new MethodDescriptor(classname + ".", "()V", false)); + } + } + return parser; + } + + List parse(MethodDescriptor md) { + ensureParse(); + try { + List descriptors = new LinkedList(); + for (Method m : parser.classfile.methods) { + String name = m.getName(parser.classfile.constant_pool); + String desc = parser.constantPoolParser.getDescriptor(m.descriptor.index); + if (name.equals(md.methodname)) { + if (md.descriptor.equals("*") || md.descriptor.equals(desc)) { + parseMethod(parser, m); + descriptors.add(desc); + } + } + } + return descriptors; + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + private void parseClassFile() throws IOException { + parser.parseClassInfo(); + + ClassFile classfile = parser.classfile; + try { + if (classfile.super_class > 0) { + superclass = getKlassInfo(classfile.getSuperclassName()); + } + if (classfile.interfaces != null) { + for (int i = 0; i < classfile.interfaces.length; i++) { + interfaces.add(getKlassInfo(classfile.getInterfaceName(i))); + } + } + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + } + + static List getSubClasses(String classname) throws IOException { + List result = new LinkedList(); + List list = new LinkedList(); + list.addAll(cache.values()); + for (KlassInfo kinfo : list) { + if (kinfo.getSuperclass() != null && classname.equals(kinfo.getSuperclass().classname)) { + result.add(kinfo); + } + for (KlassInfo interf : kinfo.getInterfaces()) { + if (classname.equals(interf.classname)) { + result.add(kinfo); + } + } + } + return result; + } + + private static void parseConfigFile(String config) throws IOException { + FileInputStream in = new FileInputStream(config); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String line; + int lineNumber = 0; + while ((line = reader.readLine()) != null) { + lineNumber++; + if ((line = line.trim()).length() > 0) { + if (line.startsWith("#")) { + continue; + } + + String[] s = line.split("\\s+"); + if ("exclude".equals(s[0])) { + filter.exclude(s[1]); + } else { + String name = s[0].replace('/', '.'); + if (name.length() > 0) { + String classname = name.replace('/', '.'); + if (s.length == 2) { + // method name + int pos = classname.lastIndexOf('.'); + classname = classname.substring(0, pos); + } + + KlassInfo kinfo = getKlassInfo(classname); + if (kinfo.getClassFileParser() != null) { + // class exists + MethodDescriptor md = (s.length == 1) ? new MethodDescriptor(name) : new MethodDescriptor(name, s[1], false); + if (!pending.contains(md)) { + pending.add(md); + } + } else { + // class not found + trace("Class %s not found%n", classname); + } + } + } + } + } + + } finally { + in.close(); + } + } + + private static void parseMethod(ClassFileParser cfparser, Method m) { + Klass.Method kmethod = cfparser.parseMethod(m); + Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); + if (c_attr != null) { + LineNumberTable_attribute lineNumTable = + (LineNumberTable_attribute) c_attr.attributes.get(Attribute.LineNumberTable); + InstructorVisitor visitor = new InstructorVisitor(cfparser, lineNumTable); + trace("parseMethod %s %s %n", cfparser.this_klass, kmethod); + for (Instruction instr : c_attr.getInstructions()) { + try { + instr.accept(visitor, kmethod); + } catch (ArrayIndexOutOfBoundsException e) { + throw new RuntimeException("error at or after byte " + instr.getPC()); + } + + } + + if (c_attr.exception_table_langth > 0) { + for (int i = 0; i < + c_attr.exception_table.length; i++) { + Code_attribute.Exception_data handler = c_attr.exception_table[i]; + int catch_type = handler.catch_type; + if (catch_type > 0) { + visitor.addConstantPoolRef(catch_type, kmethod, handler.start_pc); + } + + } + } + } + } + + static class MethodDescriptor { + + final String name; + final String classname; + final String methodname; + final String descriptor; + final boolean interfaceMethodRef; + + MethodDescriptor(String classname) { + this.classname = classname.replace('/', '.'); + this.name = this.classname; + this.methodname = ""; + this.descriptor = ""; + this.interfaceMethodRef = false; + if (this.classname.length() == 1) { + throw new RuntimeException("invalid " + this); + } + } + + MethodDescriptor(String name, String descriptor, boolean interfaceMethodRef) { + name = name.replace('/', '.'); + this.name = name; + int pos = name.lastIndexOf('.'); + this.classname = name.substring(0, pos); + this.methodname = name.substring(pos + 1, name.length()); + this.descriptor = descriptor; + this.interfaceMethodRef = interfaceMethodRef; + if (this.classname.length() == 1) { + throw new RuntimeException("invalid " + this); + } + } + + @Override + public boolean equals(Object obj) { + MethodDescriptor m = (MethodDescriptor) obj; + + return this.name.equals(m.name) && + this.descriptor.equals(m.descriptor); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0); + hash = 97 * hash + (this.descriptor != null ? this.descriptor.hashCode() : 0); + return hash; + } + + public String toString() { + if (descriptor.isEmpty()) { + return name; + } else { + return name + " : " + descriptor; + } + } + } + + static class Filter { + + private Set excludes = new TreeSet(); + + Filter exclude(String pattern) { + excludes.add(pattern); + return this; + } + + boolean isExcluded(String klass) { + for (String pattern : excludes) { + if (matches(klass, pattern)) { + return true; + } + } + return false; + } + + private boolean matches(String klass, String pattern) { + int pos = klass.lastIndexOf('.'); + String packageName = pos > 0 ? klass.substring(0, pos) : ""; + if (pattern.endsWith("**")) { + String p = pattern.substring(0, pattern.length() - 2); + return klass.startsWith(p); + } else if (pattern.endsWith("*")) { + pos = pattern.lastIndexOf('.'); + String pkg = pos > 0 ? pattern.substring(0, pos) : ""; + if (packageName.equals(pkg)) { + // package name has to be exact match + String p = pattern.substring(0, pattern.length() - 1); + return klass.startsWith(p); + } else { + return false; + } + } else { + // exact match or inner class + return klass.equals(pattern) || klass.startsWith(pattern + "$"); + } + } + } + + static class InstructorVisitor implements Instruction.KindVisitor { + + private final ClassFileParser parser; + private final LineNumberTable_attribute lineNumTable; + + InstructorVisitor(ClassFileParser parser, LineNumberTable_attribute lineNumTable) { + this.parser = parser; + this.lineNumTable = lineNumTable; + } + + int getLineNumber(int pc) { + if (lineNumTable != null) { + int start_pc = 0; + int lineno = 0; + for (int i = 0; i < lineNumTable.line_number_table_length; i++) { + int cur_start_pc = lineNumTable.line_number_table[i].start_pc; + if (pc == 0 && cur_start_pc == 0) { + return lineNumTable.line_number_table[i].line_number; + } else if (pc >= start_pc && pc < cur_start_pc) { + return lineno; + } + start_pc = cur_start_pc; + lineno = lineNumTable.line_number_table[i].line_number; + } + } + return 0; + } + + void addConstantPoolRef(int index, Klass.Method m, int pc) { + try { + CPInfo cpInfo = parser.classfile.constant_pool.get(index); + String name = cpInfo.accept(typeFinder, null); + if (name != null) { + trace(" %s %s at line %d%n", parser.constantPoolParser.tagName(index), name, getLineNumber(pc)); + } + } catch (InvalidIndex ex) { + throw new RuntimeException(ex); + } + } + + public Void visitNoOperands(Instruction instr, Klass.Method m) { + return null; + } + + public Void visitArrayType(Instruction instr, TypeKind kind, Klass.Method m) { + return null; + } + + public Void visitBranch(Instruction instr, int offset, Klass.Method m) { + return null; + } + + public Void visitConstantPoolRef(Instruction instr, int index, Klass.Method m) { + addConstantPoolRef(index, m, instr.getPC()); + return null; + } + + public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Klass.Method m) { + addConstantPoolRef(index, m, instr.getPC()); + return null; + } + + public Void visitLocal(Instruction instr, int index, Klass.Method m) { + return null; + } + + public Void visitLocalAndValue(Instruction instr, int index, int value, Klass.Method m) { + return null; + } + + public Void visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, Klass.Method m) { + return null; + } + + public Void visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, Klass.Method m) { + return null; + } + + public Void visitValue(Instruction instr, int value, Klass.Method m) { + return null; + } + + public Void visitUnknown(Instruction instr, Klass.Method m) { + return null; + } + private ConstantPool.Visitor typeFinder = new ConstantPool.Visitor() { + + String getClassName(CPRefInfo info, Void p) { + try { + return parser.checkClassName(info.getClassName()).replace('/', '.'); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + boolean addReferencedClass(String name) { + if (Klass.findKlass(name) == null) { + MethodDescriptor md = new MethodDescriptor(name); + if (!methods.contains(md) && !pending.contains(md)) { + pending.add(md); + } + return true; + } + return false; + } + private String privilegedActionClass = ""; + + void cachePrivilegedAction(String classname) { + trace(" found PrivilegedAction %s%n", classname); + privilegedActionClass = classname; + } + + void doPrivilegedCall(String method) { + if (privilegedActionClass.length() > 0) { + MethodDescriptor md = new MethodDescriptor(privilegedActionClass + ".run", "*", false); + if (!methods.contains(md) && !pending.contains(md)) { + trace(" doPrivileged %s%n", md); + pending.add(md); + } + } + } + + private String addMethodDescriptor(CPRefInfo info, Void p) { + try { + String classname = getClassName(info, null); + String method = classname + "." + info.getNameAndTypeInfo().getName(); + String descriptor = info.getNameAndTypeInfo().getType(); + + if (method.endsWith(".") && isPrivilegedAction(classname)) { + cachePrivilegedAction(classname); + } + if (method.equals("java.security.AccessController.doPrivileged")) { + doPrivilegedCall(method); + return method; + } + + boolean interfaceMethodRef = info instanceof CONSTANT_InterfaceMethodref_info; + MethodDescriptor md = new MethodDescriptor(method, descriptor, interfaceMethodRef); + if (!methods.contains(md) && !pending.contains(md)) { + pending.add(md); + } + return method; + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitClass(CONSTANT_Class_info info, Void p) { + try { + String classname = parser.checkClassName(info.getName()).replace('/', '.'); + if (classname.length() > 0) { + addReferencedClass(classname); + } + return classname; + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + public String visitDouble(CONSTANT_Double_info info, Void p) { + // skip + return null; + } + + public String visitFieldref(CONSTANT_Fieldref_info info, Void p) { + try { + String classname = getClassName(info, p); + if (classname.length() > 0) { + addReferencedClass(classname); + } + + String type = info.getNameAndTypeInfo().getType(); + String fieldType = parser.checkClassName(type).replace('/', '.'); + if (fieldType.length() > 0) { + addReferencedClass(classname); + } + return parser.constantPoolParser.stringValue(info); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitFloat(CONSTANT_Float_info info, Void p) { + // skip + return null; + } + + public String visitInteger(CONSTANT_Integer_info info, Void p) { + // skip + return null; + } + + public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { + return addMethodDescriptor(info, p); + } + + public String visitLong(CONSTANT_Long_info info, Void p) { + // skip + return null; + } + + public String visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + // skip + return null; + } + + public String visitMethodref(CONSTANT_Methodref_info info, Void p) { + return addMethodDescriptor(info, p); + } + + public String visitString(CONSTANT_String_info info, Void p) { + // skip + return null; + } + + public String visitUtf8(CONSTANT_Utf8_info info, Void p) { + return null; + } + }; + } + static boolean traceOn = System.getProperty("classanalyzer.debug") != null; + + private static void trace(String format, Object... args) { + if (traceOn) { + System.out.format(format, args); + } + } + + private static void usage() { + System.out.println("Usage: BootAnalyzer "); + System.out.println("Options: "); + System.out.println("\t-jdkhome where all jars will be parsed"); + System.out.println("\t-config "); + System.out.println("\t-output "); + System.out.println("\t-classlist print class list and summary"); + System.exit(-1); + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/CheckDeps.java b/make/modules/tools/src/com/sun/classanalyzer/CheckDeps.java new file mode 100644 index 0000000000000000000000000000000000000000..ea73b43e3fc330ac338963091de6ab99764551ca --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/CheckDeps.java @@ -0,0 +1,181 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.classanalyzer; + +import java.io.*; +import java.util.*; + +/** + * A simple tool to check module dependencies against a known list of + * dependencies. The tool fails (by throwing a RuntimeException) is an + * unexpected dependency is detected. + */ + +public class CheckDeps { + + /** + * Represents a dependency from one module to another module. The dependency + * may be optional. + */ + static class Dependency { + private final String module; + private final String other; + private final boolean optional; + + private Dependency(String module, String other, boolean optional) { + this.module = module; + this.other = other; + this.optional = optional; + } + + String module() { return module; } + String other() { return other; } + boolean isOptional() { return optional; } + + /** + * Parses a dependency in one of the following forms: + * a -> b + * [optional] a -> b + */ + static Dependency fromString(String s) { + String[] components = s.split(" "); + int count = components.length; + if (count != 3 && count != 4) + throw new IllegalArgumentException(s); + boolean optional = (count == 4); + if (optional && !components[0].equals("[optional]")) + throw new IllegalArgumentException(s); + String arrow = optional ? components[2] : components[1]; + if (!arrow.equals("->")) + throw new IllegalArgumentException(s); + String module = optional ? components[1] : components[0]; + String other = optional ? components[3] : components[2]; + return new Dependency(module, other, optional); + } + + @Override public String toString() { + StringBuilder sb = new StringBuilder(); + if (optional) + sb.append("[optional] "); + sb.append(module); + sb.append(" -> "); + sb.append(other); + return sb.toString(); + } + } + + /** + * Represents the "tail" + */ + static class DependencyTail { + private final String module; + private final boolean optional; + + DependencyTail(String module, boolean optional) { + this.module = module; + this.optional = optional; + } + String module() { return module; } + boolean isOptional() { return optional; } + } + + static void usage() { + System.out.println("java CheckDeps file1 file2"); + System.out.println(" where file1 is the expected dependencies and file2 is"); + System.out.println(" the actual dependencies. Both files are assumed to be"); + System.out.println(" in modules.summary format (see ClassAnalyzer tool)."); + System.out.println(); + System.out.println("Example usages:"); + System.out.println(" java CheckDeps make/modules/modules.summary " + + "$(OUTPUTDIR)/modules.summary"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + if (args.length != 2) + usage(); + + // maps a module to the list of modules that it depends on + Map> expected = + new HashMap>(); + + // parse the expected dependencies file + Scanner s; + s = new Scanner(new FileInputStream(args[0])); + try { + while (s.hasNextLine()) { + Dependency ref = Dependency.fromString(s.nextLine()); + if (ref != null) { + String module = ref.module(); + List list = expected.get(module); + if (list == null) { + list = new ArrayList(); + expected.put(module, list); + } + list.add(new DependencyTail(ref.other(), ref.isOptional())); + } + } + } finally { + s.close(); + } + + // parse the actual dependencies file, checking each dependency + // against the expected list. + boolean fail = false; + s = new Scanner(new FileInputStream(args[1])); + try { + while (s.hasNextLine()) { + Dependency dep = Dependency.fromString(s.nextLine()); + + // check if this dependency is expected + List list = expected.get(dep.module()); + DependencyTail tail = null; + if (list != null) { + for (DependencyTail t: list) { + if (t.module().equals(dep.other())) { + tail = t; + break; + } + } + } + if (tail == null) { + System.err.println("Unexpected dependency: " + dep); + fail = true; + } else { + // hard dependency when optional dependency is expected + if (tail.isOptional() != dep.isOptional()) { + if (tail.isOptional()) { + System.err.println("Unexpected dependency: " + dep); + fail = true; + } + } + } + } + } finally { + s.close(); + } + + if (fail) + throw new RuntimeException("Unexpected dependencies found"); + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/ClassAnalyzer.java b/make/modules/tools/src/com/sun/classanalyzer/ClassAnalyzer.java new file mode 100644 index 0000000000000000000000000000000000000000..fd570a7c0b1373101c3e0325fefc055446752a5e --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/ClassAnalyzer.java @@ -0,0 +1,354 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.classanalyzer; + +import com.sun.classanalyzer.AnnotatedDependency.*; +import com.sun.classanalyzer.Module.Dependency; +import com.sun.classanalyzer.Module.PackageInfo; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.io.File; +import java.io.PrintWriter; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class ClassAnalyzer { + + public static void main(String[] args) throws Exception { + String jdkhome = null; + String cpath = null; + List configs = new ArrayList(); + List depconfigs = new ArrayList(); + String output = "."; + boolean mergeModules = true; + boolean showDynamic = false; + + // process arguments + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-jdkhome")) { + if (i < args.length) { + jdkhome = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-cpath")) { + if (i < args.length) { + cpath = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-config")) { + if (i < args.length) { + configs.add(args[i++]); + } else { + usage(); + } + } else if (arg.equals("-depconfig")) { + if (i < args.length) { + depconfigs.add(args[i++]); + } else { + usage(); + } + } else if (arg.equals("-output")) { + if (i < args.length) { + output = args[i++]; + } else { + usage(); + } + } else if (arg.equals("-base")) { + ModuleConfig.setBaseModule(args[i++]); + } else if (arg.equals("-nomerge")) { + // analyze the fine-grained module dependencies + mergeModules = false; + } else if (arg.equals("-showdynamic")) { + showDynamic = true; + } else { + System.err.println("Invalid option: " + arg); + usage(); + } + } + + if ((jdkhome == null && cpath == null) || (jdkhome != null && cpath != null)) { + usage(); + } + if (configs.isEmpty()) { + usage(); + } + + if (jdkhome != null) { + ClassPath.setJDKHome(jdkhome); + } else if (cpath != null) { + ClassPath.setClassPath(cpath); + } + + // create output directory if it doesn't exist + File dir = new File(output); + if (!dir.isDirectory()) { + if (!dir.exists()) { + boolean created = dir.mkdir(); + if (!created) { + throw new RuntimeException("Unable to create `" + dir + "'"); + } + } + } + + buildModules(configs, depconfigs, mergeModules); + + // generate output files + for (Module m : modules) { + // only generate reports for top-level modules + if (m.group() == m) { + m.printClassListTo(resolve(dir, m.name(), "classlist")); + m.printResourceListTo(resolve(dir, m.name(), "resources")); + m.printSummaryTo(resolve(dir, m.name(), "summary")); + m.printDependenciesTo(resolve(dir, m.name(), "dependencies"), showDynamic); + } + } + + // Generate other summary reports + printModulesSummary(dir, showDynamic); + printModulesDot(dir, showDynamic); + printModulesList(dir); + printPackagesSummary(dir); + } + private static List modules = new ArrayList(); + + static void buildModules(List configs, + List depconfigs, + boolean mergeModules) throws IOException { + // create modules based on the input config files + for (String file : configs) { + for (ModuleConfig mconfig : ModuleConfig.readConfigurationFile(file)) { + modules.add(Module.addModule(mconfig)); + } + } + + // parse class files + ClassPath.parseAllClassFiles(); + + // Add additional dependencies if specified + if (depconfigs != null && depconfigs.size() > 0) { + DependencyConfig.parse(depconfigs); + } + + // process the roots and dependencies to get the classes for each module + for (Module m : modules) { + m.processRootsAndReferences(); + } + + // update the dependencies for classes that were subsequently allocated + // to modules + for (Module m : modules) { + m.fixupDependencies(); + } + + if (mergeModules) { + Module.buildModuleMembers(); + } + } + + private static void printModulesSummary(File dir, boolean showDynamic) throws IOException { + // print summary of dependencies + PrintWriter writer = new PrintWriter(new File(dir, "modules.summary")); + try { + for (Module m : modules) { + // only show top-level module dependencies + if (m.group() == m) { + for (Dependency dep : m.dependents()) { + if (!showDynamic && dep.dynamic && dep.optional) { + continue; + } + if (dep.module == null || !dep.module.isBase()) { + + String prefix = ""; + if (dep.optional) { + if (dep.dynamic) { + prefix = "[dynamic] "; + } else { + prefix = "[optional] "; + } + } + + Module other = dep != null ? dep.module : null; + writer.format("%s%s -> %s%n", prefix, m, other); + } + } + } + } + } finally { + writer.close(); + } + } + + private static void printModulesDot(File dir, boolean showDynamic) throws IOException { + PrintWriter writer = new PrintWriter(new File(dir, "modules.dot")); + try { + writer.println("digraph jdk {"); + for (Module m : modules) { + if (m.group() == m) { + for (Dependency dep : m.dependents()) { + if (!showDynamic && dep.dynamic && dep.optional) { + continue; + } + if (dep.module == null || !dep.module.isBase()) { + String style = ""; + String color = ""; + String property = ""; + if (dep.optional) { + style = "style=dotted"; + } + if (dep.dynamic) { + color = "color=red"; + } + if (style.length() > 0 || color.length() > 0) { + String comma = ""; + if (style.length() > 0 && color.length() > 0) { + comma = ", "; + } + property = String.format(" [%s%s%s]", style, comma, color); + } + Module other = dep != null ? dep.module : null; + writer.format(" \"%s\" -> \"%s\"%s;%n", m, other, property); + } + } + } + } + writer.println("}"); + } finally { + writer.close(); + } + } + + private static void printMembers(Module m, PrintWriter writer) { + for (Module member : m.members()) { + if (!member.isEmpty()) { + writer.format("%s ", member); + printMembers(member, writer); + } + } + } + + private static void printModulesList(File dir) throws IOException { + // print module group / members relationship + PrintWriter writer = new PrintWriter(new File(dir, "modules.list")); + try { + for (Module m : modules) { + if (m.group() == m && !m.isEmpty()) { + writer.format("%s ", m); + printMembers(m, writer); + writer.println(); + } + } + } finally { + writer.close(); + } + } + + private static void printPackagesSummary(File dir) throws IOException { + // print package / module relationship + PrintWriter writer = new PrintWriter(new File(dir, "modules.pkginfo")); + try { + Map> packages = new TreeMap>(); + Set splitPackages = new TreeSet(); + + for (Module m : modules) { + if (m.group() == m) { + for (PackageInfo info : m.getPackageInfos()) { + Set value = packages.get(info.pkgName); + if (value == null) { + value = new TreeSet(); + packages.put(info.pkgName, value); + } else { + // package in more than one module + splitPackages.add(info.pkgName); + } + value.add(m); + } + } + } + + // packages that are splitted among multiple modules + writer.println("Packages splitted across modules:-\n"); + writer.format("%-60s %s\n", "Package", "Module"); + + for (String pkgname : splitPackages) { + writer.format("%-60s", pkgname); + for (Module m : packages.get(pkgname)) { + writer.format(" %s", m); + } + writer.println(); + } + + writer.println("\nPackage-private dependencies:-"); + for (String pkgname : splitPackages) { + for (Klass k : Klass.getAllClasses()) { + if (k.getPackageName().equals(pkgname)) { + Module m = k.getModule(); + // check if this klass references a package-private + // class that is in a different module + for (Klass other : k.getReferencedClasses()) { + if (other.getModule() != m && + !other.isPublic() && + other.getPackageName().equals(pkgname)) { + String from = k.getClassName() + " (" + m + ")"; + writer.format("%-60s -> %s (%s)\n", from, other, other.getModule()); + } + } + } + } + } + } finally { + writer.close(); + } + + } + + private static String resolve(File dir, String mname, String suffix) { + File f = new File(dir, mname + "." + suffix); + return f.toString(); + + } + + private static void usage() { + System.out.println("Usage: ClassAnalyzer "); + System.out.println("Options: "); + System.out.println("\t-jdkhome where all jars will be parsed"); + System.out.println("\t-cpath where classes and jars will be parsed"); + System.out.println("\t Either -jdkhome or -cpath option can be used."); + System.out.println("\t-config "); + System.out.println("\t This option can be repeated for multiple module config files"); + System.out.println("\t-output "); + System.out.println("\t-nomerge specify not to merge modules"); + System.out.println("\t-showdynamic show dynamic dependencies in the reports"); + System.exit(-1); + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/ClassFileParser.java b/make/modules/tools/src/com/sun/classanalyzer/ClassFileParser.java new file mode 100644 index 0000000000000000000000000000000000000000..bbbeda7407f00c21a005662b0a359f6fe9640176 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/ClassFileParser.java @@ -0,0 +1,629 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ +package com.sun.classanalyzer; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.Type.*; +import com.sun.tools.classfile.Descriptor.InvalidDescriptor; +import static com.sun.tools.classfile.AccessFlags.*; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class ClassFileParser { + + final Klass this_klass; + final ClassFile classfile; + final ConstantPoolParser constantPoolParser; + final AnnotationParser annotationParser; + final CodeAttributeParser codeAttributeParser; + private final boolean buildDeps; + + protected ClassFileParser(InputStream in, long size, boolean buildDeps) throws IOException { + try { + this.classfile = ClassFile.read(in); + this.this_klass = getKlass(this.classfile); + this.buildDeps = buildDeps; + this.constantPoolParser = new ConstantPoolParser(this); + this.annotationParser = new AnnotationParser(this); + this.codeAttributeParser = new CodeAttributeParser(this); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + private Klass getKlass(ClassFile cf) throws ConstantPoolException { + Klass k = Klass.getKlass(cf.getName()); + k.setAccessFlags(cf.access_flags.flags); + k.setFileSize(cf.byteLength()); + return k; + } + + public static ClassFileParser newParser(InputStream in, long size, boolean buildDeps) throws IOException { + return new ClassFileParser(in, size, buildDeps); + } + + public static ClassFileParser newParser(String classPathname, boolean buildDeps) throws IOException { + return newParser(new File(classPathname), buildDeps); + } + + public static ClassFileParser newParser(File f, boolean buildDeps) throws IOException { + BufferedInputStream in = new BufferedInputStream(new FileInputStream(f)); + try { + return newParser(in, f.length(), buildDeps); + } finally { + in.close(); + } + } + + public void parseDependency(boolean publicAPIs) throws IOException { + if (publicAPIs && !classfile.access_flags.is(ACC_PUBLIC)) { + // process public APIs only + return; + } + + parseClassInfo(); + if (!publicAPIs) { + // parse all references in the classfile + constantPoolParser.parseDependency(); + } + parseMethods(publicAPIs); + parseFields(publicAPIs); + } + + void parseClassInfo() throws IOException { + ConstantPool cpool = classfile.constant_pool; + try { + Signature_attribute sigAttr = (Signature_attribute) classfile.attributes.get(Attribute.Signature); + if (sigAttr == null) { + // use info from class file header + if (classfile.isClass() && classfile.super_class != 0) { + String sn = classfile.getSuperclassName(); + addExtends(sn); + } + for (int i = 0; i < classfile.interfaces.length; i++) { + String interf = classfile.getInterfaceName(i); + if (classfile.isClass()) { + addImplements(interf); + } else { + addExtends(interf); + } + } + } else { + Type t = sigAttr.getParsedSignature().getType(cpool); + // The signature parser cannot disambiguate between a + // FieldType and a ClassSignatureType that only contains a superclass type. + if (t instanceof Type.ClassSigType) { + Type.ClassSigType cst = Type.ClassSigType.class.cast(t); + if (cst.superclassType != null) { + for (Klass k : getKlass(cst.superclassType)) { + addExtends(k); + } + } + if (cst.superinterfaceTypes != null) { + for (Type t1 : cst.superinterfaceTypes) { + for (Klass k : getKlass(t1)) { + addImplements(k); + } + } + } + } else { + for (Klass k : getKlass(t)) { + addExtends(k); + } + } + } + // parse attributes + annotationParser.parseAttributes(classfile.attributes); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + private void parseFields(boolean publicAPIs) throws IOException { + ConstantPool cpool = classfile.constant_pool; + for (Field f : classfile.fields) { + try { + AccessFlags flags = f.access_flags; + if (publicAPIs && !flags.is(ACC_PUBLIC) && !flags.is(ACC_PROTECTED)) { + continue; + } + String fieldname = f.getName(cpool); + Signature_attribute sigAttr = (Signature_attribute) f.attributes.get(Attribute.Signature); + + if (sigAttr == null) { + Set types = parseDescriptor(f.descriptor); + String info = getFlag(flags) + " " + f.descriptor.getFieldType(cpool) + " " + fieldname; + addFieldTypes(types, info, flags); + } else { + Type t = sigAttr.getParsedSignature().getType(cpool); + String info = getFlag(flags) + " " + t + " " + fieldname; + addFieldTypes(getKlass(t), info, flags); + } + // parse attributes + annotationParser.parseAttributes(f.attributes); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } catch (InvalidDescriptor ex) { + throw new RuntimeException(ex); + } + } + } + + private void parseMethods(boolean publicAPIs) { + for (Method m : classfile.methods) { + if (publicAPIs && !m.access_flags.is(ACC_PUBLIC) && !m.access_flags.is(ACC_PROTECTED)) { + // only interest in the API level + return; + } + + parseMethod(m); + } + } + + String checkClassName(String classname) { + int i = 0; + while (i < classname.length()) { + switch (classname.charAt(i)) { + case 'Z': + case 'B': + case 'C': + case 'S': + case 'I': + case 'J': + case 'F': + case 'D': + return ""; + case 'L': + if (!classname.endsWith(";")) { + throw new RuntimeException("Invalid classname " + classname); + } + return classname.substring(i + 1, classname.length() - 1); + case '[': + i++; + break; + default: + if (classname.endsWith(";")) { + throw new RuntimeException("Invalid classname " + classname); + } + return classname; + + } + } + throw new RuntimeException("Invalid classname " + classname); + } + + private void addExtends(String classname) throws IOException { + if (!buildDeps) { + return; + } + + addExtends(Klass.getKlass(classname)); + } + + private void addExtends(Klass k) { + if (!buildDeps) { + return; + } + + ResolutionInfo resInfo = ResolutionInfo.resolvedExtends(this_klass, k); + resInfo.setPublicAccess(classfile.access_flags.is(ACC_PUBLIC)); + this_klass.addDep(k, resInfo); + k.addReferrer(this_klass, resInfo); + } + + private void addImplements(String classname) throws IOException { + if (!buildDeps) { + return; + } + + addImplements(Klass.getKlass(classname)); + } + + private void addImplements(Klass k) { + if (!buildDeps) { + return; + } + + ResolutionInfo resInfo = ResolutionInfo.resolvedImplements(this_klass, k); + resInfo.setPublicAccess(classfile.access_flags.is(ACC_PUBLIC)); + + this_klass.addDep(k, resInfo); + + k.addReferrer(this_klass, resInfo); + } + + private Set getKlass(Type type) throws IOException { + Set refTypes = new TreeSet(); + if (!buildDeps) { + return refTypes; + } + + type.accept(typevisitor, refTypes); + return refTypes; + } + private Type.Visitor> typevisitor = new Type.Visitor>() { + + public Void visitSimpleType(SimpleType type, Set klasses) { + // nop + return null; + } + + public Void visitArrayType(ArrayType type, Set klasses) { + try { + klasses.addAll(getKlass(type.elemType)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + return null; + + } + + public Void visitMethodType(MethodType type, Set klasses) { + throw new InternalError("Unexpected type " + type); + } + + public Void visitClassSigType(ClassSigType type, Set klasses) { + try { + if (type.superclassType != null) { + klasses.addAll(getKlass(type.superclassType)); + } + if (type.superinterfaceTypes != null) { + for (Type t : type.superinterfaceTypes) { + klasses.addAll(getKlass(t)); + } + } + if (type.typeParamTypes != null) { + for (Type t : type.typeParamTypes) { + klasses.addAll(getKlass(t)); + } + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } + return null; + } + + public Void visitClassType(ClassType type, Set klasses) { + klasses.add(Klass.getKlass(type.getBinaryName())); + if (type.typeArgs != null) { + for (Type t : type.typeArgs) { + try { + klasses.addAll(getKlass(t)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + return null; + + } + + public Void visitTypeParamType(TypeParamType type, Set klasses) { + try { + if (type.classBound != null) { + klasses.addAll(getKlass(type.classBound)); + } + if (type.interfaceBounds != null) { + for (Type t : type.interfaceBounds) { + klasses.addAll(getKlass(t)); + } + } + + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + return null; + + } + + public Void visitWildcardType(WildcardType type, Set klasses) { + if (type.boundType != null) { + try { + klasses.addAll(getKlass(type.boundType)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + return null; + + } + }; + + private void printMethod(Method m) { + try { + System.out.println("parsing " + m.getName(classfile.constant_pool) + "(" + + m.descriptor.getParameterTypes(classfile.constant_pool) + ") return type " + + m.descriptor.getReturnType(classfile.constant_pool)); + + } catch (ConstantPoolException ex) { + } catch (InvalidDescriptor ex) { + } + } + + private static StringBuilder appendWord(StringBuilder sb, String word) { + if (sb.length() > 0) { + sb.append(" "); + } + sb.append(word); + return sb; + } + + private static String getFlag(AccessFlags flags) { + StringBuilder modifier = new StringBuilder(); + if (flags.is(ACC_PUBLIC)) { + modifier.append("public"); + } + if (flags.is(ACC_PRIVATE)) { + modifier.append("private"); + } + if (flags.is(ACC_PROTECTED)) { + modifier.append("protected"); + } + if (flags.is(ACC_STATIC)) { + appendWord(modifier, "static"); + } + if (flags.is(ACC_FINAL)) { + appendWord(modifier, "final"); + } + if (flags.is(ACC_SYNCHRONIZED)) { + // return "synchronized"; + } + if (flags.is(0x80)) { + // return (t == Type.Field ? "transient" : null); + // return "transient"; + } + if (flags.is(ACC_VOLATILE)) { + // return "volatile"; + } + if (flags.is(ACC_NATIVE)) { + // return "native"; + } + if (flags.is(ACC_ABSTRACT)) { + appendWord(modifier, "abstract"); + } + if (flags.is(ACC_STRICT)) { + // return "strictfp"; + } + if (flags.is(ACC_MODULE)) { + appendWord(modifier, "module"); + } + return modifier.toString(); + } + + private Klass.Method toKlassMethod(Method m, Descriptor d) { + try { + ConstantPool cpool = classfile.constant_pool; + String methodname = m.getName(cpool); + StringBuilder sb = new StringBuilder(); + sb.append(getFlag(m.access_flags)); + if (methodname.equals("")) { + String s = this_klass.getBasename() + d.getParameterTypes(cpool); + appendWord(sb, s); + } else if (methodname.equals("")) { + // + appendWord(sb, methodname); + } else { + String s = d.getReturnType(cpool) + " " + methodname + d.getParameterTypes(cpool); + appendWord(sb, s); + } + String signature = sb.toString().replace('/', '.'); + return this_klass.getMethod(methodname, signature); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } catch (InvalidDescriptor ex) { + throw new RuntimeException(ex); + } + } + + Klass.Method parseMethod(Method m) { + AccessFlags flags = m.access_flags; + Descriptor d; + List methodExceptions = null; + try { + ConstantPool cpool = classfile.constant_pool; + Klass.Method kmethod; + Signature_attribute sigAttr = (Signature_attribute) m.attributes.get(Attribute.Signature); + if (sigAttr == null) { + d = m.descriptor; + Set types = parseDescriptor(d); + + kmethod = toKlassMethod(m, d); + addMethodTypes(types, kmethod, flags); + } else { + Type.MethodType methodType; + Signature methodSig = sigAttr.getParsedSignature(); + d = methodSig; + try { + kmethod = toKlassMethod(m, d); + methodType = (Type.MethodType) methodSig.getType(cpool); + addMethodTypes(getKlass(methodType.returnType), kmethod, flags); + if (methodType.paramTypes != null) { + for (Type t : methodType.paramTypes) { + addMethodTypes(getKlass(t), kmethod, flags); + } + } + if (methodType.typeParamTypes != null) { + for (Type t : methodType.typeParamTypes) { + addMethodTypes(getKlass(t), kmethod, flags); + } + } + + methodExceptions = methodType.throwsTypes; + if (methodExceptions != null) { + if (methodExceptions.size() == 0) { + methodExceptions = null; + } else { + for (Type t : methodExceptions) { + addCheckedExceptionTypes(getKlass(t), kmethod, flags); + } + } + } + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + Attribute e_attr = m.attributes.get(Attribute.Exceptions); + if (e_attr != null && methodExceptions == null) { + // if there are generic exceptions, there must be erased exceptions + if (e_attr instanceof Exceptions_attribute) { + Exceptions_attribute exceptions = (Exceptions_attribute) e_attr; + for (int i = 0; i < exceptions.number_of_exceptions; i++) { + String classname = checkClassName(exceptions.getException(i, classfile.constant_pool)); + if (classname.length() > 0 && buildDeps) { + Klass to = Klass.getKlass(classname); + ResolutionInfo resInfo = ResolutionInfo.resolvedCheckedException(this_klass, to, kmethod); + resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); + + this_klass.addDep(to, resInfo); + to.addReferrer(this_klass, resInfo); + } + } + } else { + throw new RuntimeException("Invalid attribute: " + e_attr); + } + } + + Code_attribute c_attr = (Code_attribute) m.attributes.get(Attribute.Code); + if (c_attr != null) { + codeAttributeParser.parse(c_attr, kmethod); + } + kmethod.isAbstract = classfile.access_flags.is(ACC_ABSTRACT); + kmethod.setCodeLength(m.byteLength()); + + // parse annotation attributes + annotationParser.parseAttributes(m.attributes, kmethod); + return kmethod; + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + private void addFieldTypes(Set types, String info, AccessFlags flags) { + if (types.isEmpty() || !buildDeps) { + return; + } + + for (Klass to : types) { + ResolutionInfo resInfo = ResolutionInfo.resolvedField(this_klass, to, info); + resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); + + this_klass.addDep(to, resInfo); + to.addReferrer(this_klass, resInfo); + } + } + + private void addReferencedTypes(Method m, Descriptor d, AccessFlags flags) { + Set types = parseDescriptor(d); + + Klass.Method method = toKlassMethod(m, d); + addMethodTypes(types, method, flags); + } + + private void addMethodTypes(Set types, Klass.Method method, AccessFlags flags) { + if (types.isEmpty() || !buildDeps) { + return; + } + for (Klass to : types) { + ResolutionInfo resInfo = ResolutionInfo.resolvedMethodSignature(this_klass, to, method); + resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); + + this_klass.addDep(to, resInfo); + to.addReferrer(this_klass, resInfo); + } + } + + private void addCheckedExceptionTypes(Set types, Klass.Method method, AccessFlags flags) { + if (types.isEmpty() || !buildDeps) { + return; + } + for (Klass to : types) { + ResolutionInfo resInfo = ResolutionInfo.resolvedCheckedException(this_klass, to, method); + resInfo.setPublicAccess(flags.is(ACC_PUBLIC)); + + this_klass.addDep(to, resInfo); + to.addReferrer(this_klass, resInfo); + } + } + + private Set parseDescriptor(Descriptor d) { + Set types = new TreeSet(); + try { + String desc = d.getValue(classfile.constant_pool); + int p = 0; + while (p < desc.length()) { + String type; + char ch; + switch (ch = desc.charAt(p++)) { + case '(': + case ')': + case '[': + case 'B': + case 'C': + case 'D': + case 'F': + case 'I': + case 'J': + case 'S': + case 'Z': + case 'V': + continue; + case 'L': + int sep = desc.indexOf(';', p); + if (sep == -1) { + throw new RuntimeException("Invalid descriptor: " + (p - 1) + " " + desc); + } + type = checkClassName(desc.substring(p, sep)); + p = sep + 1; + break; + default: + throw new RuntimeException("Invalid descriptor: " + (p - 1) + " " + desc); + } + + if (!type.isEmpty() && buildDeps) { + Klass to = Klass.getKlass(type); + types.add(to); + + } + } + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + return types; + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/ClassPath.java b/make/modules/tools/src/com/sun/classanalyzer/ClassPath.java new file mode 100644 index 0000000000000000000000000000000000000000..bfdcdd97f5999c3dfc82e30af1a03fcbdc573154 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/ClassPath.java @@ -0,0 +1,275 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ +package com.sun.classanalyzer; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * + * @author mchung + */ +public class ClassPath { + + public class FileInfo { + + File file; + JarFile jarfile; + int classCount; + long filesize; + + FileInfo(File f) throws IOException { + this.file = f; + this.classCount = 0; + if (file.getName().endsWith(".jar")) { + this.filesize = file.length(); + jarfile = new JarFile(f); + } + } + + File getFile() { + return file; + } + + JarFile getJarFile() { + return jarfile; + } + + String getName() throws IOException { + return file.getCanonicalPath(); + } + } + private List fileList = new ArrayList(); + private static ClassPath instance = new ClassPath(); + + static List getFileInfos() { + return instance.fileList; + } + + static ClassPath setJDKHome(String jdkhome) throws IOException { + List files = new ArrayList(); + File jre = new File(jdkhome, "jre"); + File lib = new File(jdkhome, "lib"); + if (jre.exists() && jre.isDirectory()) { + listFiles(new File(jre, "lib"), ".jar", files); + } else if (lib.exists() && lib.isDirectory()) { + // either a JRE or a jdk build image + listFiles(lib, ".jar", files); + + File classes = new File(jdkhome, "classes"); + if (classes.exists() && classes.isDirectory()) { + // jdk build outputdir + instance.add(classes); + } + } else { + throw new RuntimeException("\"" + jdkhome + "\" not a JDK home"); + } + + for (File f : files) { + instance.add(f); + } + return instance; + } + + static ClassPath setClassPath(String path) throws IOException { + if (path.endsWith(".class")) { + // one class file + File f = new File(path); + if (!f.exists()) { + throw new RuntimeException("Classfile \"" + f + "\" doesn't exist"); + } + + instance.add(f); + } else { + List jarFiles = new ArrayList(); + String[] locs = path.split(File.pathSeparator); + for (String p : locs) { + File f = new File(p); + if (!f.exists()) { + throw new RuntimeException("\"" + f + "\" doesn't exist"); + } + + if (f.isDirectory()) { + instance.add(f); // add the directory to look up .class files + listFiles(f, ".jar", jarFiles); + } else if (p.endsWith(".jar")) { + // jar files + jarFiles.add(f); + } else { + throw new RuntimeException("Invalid file \"" + f); + } + } + // add jarFiles if any + for (File f : jarFiles) { + instance.add(f); + } + } + + return instance; + } + + private void add(File f) throws IOException { + fileList.add(new FileInfo(f)); + } + + public static InputStream open(String pathname) throws IOException { + for (FileInfo fi : instance.fileList) { + if (fi.getName().endsWith(".jar")) { + String path = pathname.replace(File.separatorChar, '/'); + JarEntry e = fi.jarfile.getJarEntry(path); + if (e != null) { + return fi.jarfile.getInputStream(e); + } + } else if (fi.getFile().isDirectory()) { + File f = new File(fi.getFile(), pathname); + if (f.exists()) { + return new FileInputStream(f); + } + } else if (fi.file.isFile()) { + if (fi.getName().endsWith(File.separator + pathname)) { + return new FileInputStream(fi.file); + } + } + } + return null; + } + + static ClassFileParser parserForClass(String classname) throws IOException { + String pathname = classname.replace('.', File.separatorChar) + ".class"; + + ClassFileParser cfparser = null; + for (FileInfo fi : instance.fileList) { + if (fi.getName().endsWith(".class")) { + if (fi.getName().endsWith(File.separator + pathname)) { + cfparser = ClassFileParser.newParser(fi.getFile(), true); + break; + } + } else if (fi.getName().endsWith(".jar")) { + JarEntry e = fi.jarfile.getJarEntry(classname.replace('.', '/') + ".class"); + if (e != null) { + cfparser = ClassFileParser.newParser(fi.jarfile.getInputStream(e), e.getSize(), true); + break; + } + } else if (fi.getFile().isDirectory()) { + File f = new File(fi.getFile(), pathname); + if (f.exists()) { + cfparser = ClassFileParser.newParser(f, true); + break; + } + } + } + return cfparser; + } + + public static void parseAllClassFiles() throws IOException { + instance.parseFiles(); + } + + private void parseFiles() throws IOException { + Set classes = new HashSet(); + + int count = 0; + for (FileInfo fi : fileList) { + // filter out public generated classes (i.e. not public API) + // javax.management.remote.rmi._RMIConnectionImpl_Tie + // javax.management.remote.rmi._RMIServerImpl_Tie + if (fi.getName().endsWith(".class")) { + parseClass(fi); + } else if (fi.getName().endsWith(".jar")) { + Enumeration entries = fi.jarfile.entries(); + while (entries.hasMoreElements()) { + JarEntry e = entries.nextElement(); + if (e.getName().endsWith(".class")) { + ClassFileParser cfparser = ClassFileParser.newParser(fi.jarfile.getInputStream(e), e.getSize(), true); + cfparser.parseDependency(false); + fi.classCount++; + } else if (!e.isDirectory() && ResourceFile.isResource(e.getName())) { + ResourceFile.addResource(e.getName(), fi.jarfile.getInputStream(e)); + } + } + } else if (fi.getFile().isDirectory()) { + List files = new ArrayList(); + listFiles(fi.getFile(), "", files); + for (File f : files) { + if (f.getName().endsWith(".class")) { + parseClass(fi, f); + } else if (!f.isDirectory() && ResourceFile.isResource(f.getCanonicalPath())) { + String pathname = f.getCanonicalPath(); + String dir = fi.getName(); + if (!pathname.startsWith(dir)) { + throw new RuntimeException("Incorrect pathname " + pathname); + } + String name = pathname.substring(dir.length() + 1, pathname.length()); + BufferedInputStream in = new BufferedInputStream(new FileInputStream(f)); + try { + ResourceFile.addResource(name, in); + } finally { + in.close(); + } + } + } + } else { + // should not reach here + throw new RuntimeException("Unexpected class path: " + fi.getFile()); + } + } + } + + private void parseClass(FileInfo fi) throws IOException { + parseClass(fi, fi.getFile()); + } + + private void parseClass(FileInfo fi, File f) throws IOException { + ClassFileParser cfparser = ClassFileParser.newParser(f, true); + cfparser.parseDependency(false); + fi.classCount++; + // need to update the filesize for this directory + fi.filesize += fi.getFile().length(); + + } + + public static void listFiles(File path, String suffix, List result) { + if (path.isDirectory()) { + File[] children = path.listFiles(); + for (File c : children) { + listFiles(c, suffix, result); + } + + } else { + if (suffix.isEmpty() || path.getName().endsWith(suffix)) { + result.add(path); + } + } + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/CodeAttributeParser.java b/make/modules/tools/src/com/sun/classanalyzer/CodeAttributeParser.java new file mode 100644 index 0000000000000000000000000000000000000000..98ff1a4927702b3d55e7909c1d9c663d1e416219 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/CodeAttributeParser.java @@ -0,0 +1,157 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.classanalyzer; + +import com.sun.classanalyzer.Klass.Method; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.Instruction.*; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class CodeAttributeParser { + private final ClassFileParser cfparser; + private final ConstantPool cpool; + private final ConstantPoolParser constantPoolParser; + + + static final Map> runtimeReferences = + new HashMap>(); + + + CodeAttributeParser(ClassFileParser parser) { + this.cfparser = parser; + this.cpool = cfparser.classfile.constant_pool; + this.constantPoolParser = cfparser.constantPoolParser; + } + + static boolean parseCodeAttribute = false; // by default don't parse code attribute + static void setParseCodeAttribute(boolean newValue) { + parseCodeAttribute = newValue; + } + + void parse(Code_attribute attr, Klass.Method method) { + if (!parseCodeAttribute) { + return; + } + + for (Instruction instr : attr.getInstructions()) { + try { + instr.accept(instructionVisitor, method); + } catch (ArrayIndexOutOfBoundsException e) { + throw new RuntimeException("error at or after byte " + instr.getPC()); + } + + } + + if (attr.exception_table_langth > 0) { + for (int i = 0; i < + attr.exception_table.length; i++) { + Code_attribute.Exception_data handler = attr.exception_table[i]; + int catch_type = handler.catch_type; + if (catch_type > 0) { + addMethodReference(catch_type, method); + } + + } + } + + } + + + private void addMethodReference(int index, Klass.Method m) { + String method = constantPoolParser.getMethodName(index); + + if (method != null && + (method.equals("java.lang.Class.forName") || + method.equals("java.lang.Class.loadClass") || + method.startsWith("java.util.ServiceLoader.load") || + method.equals("sun.misc.Service.providers"))) { + Set refs = runtimeReferences.get(method); + if (refs == null) { + refs = new TreeSet(); + runtimeReferences.put(method, refs); + } + refs.add(m); + } + } + + Instruction.KindVisitor instructionVisitor = + new Instruction.KindVisitor() { + + public Void visitNoOperands(Instruction instr, Klass.Method m) { + return null; + } + + public Void visitArrayType(Instruction instr, TypeKind kind, Klass.Method m) { + return null; + } + + public Void visitBranch(Instruction instr, int offset, Klass.Method m) { + return null; + } + + public Void visitConstantPoolRef(Instruction instr, int index, Klass.Method m) { + addMethodReference(index, m); + return null; + } + + public Void visitConstantPoolRefAndValue(Instruction instr, int index, int value, Klass.Method m) { + addMethodReference(index, m); + return null; + } + + public Void visitLocal(Instruction instr, int index, Klass.Method m) { + return null; + } + + public Void visitLocalAndValue(Instruction instr, int index, int value, Klass.Method m) { + return null; + } + + public Void visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, Klass.Method m) { + return null; + } + + public Void visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, Klass.Method m) { + return null; + } + + public Void visitValue(Instruction instr, int value, Klass.Method m) { + return null; + } + + public Void visitUnknown(Instruction instr, Klass.Method m) { + return null; + } + }; +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolAnalyzer.java b/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolAnalyzer.java new file mode 100644 index 0000000000000000000000000000000000000000..f79f2bf6c36a6d891beec6a59465d2436444e50d --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolAnalyzer.java @@ -0,0 +1,60 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package com.sun.classanalyzer; + +/** + * + * @author Mandy Chung + */ +public class ConstantPoolAnalyzer { + public static void main(String[] args) throws Exception { + String jdkhome = null; + + // process arguments + int i = 0; + while (i < args.length) { + String arg = args[i++]; + if (arg.equals("-jdkhome")) { + if (i < args.length) { + jdkhome = args[i++]; + } else { + usage(); + } + } + } + if (jdkhome == null) { + usage(); + } + ClassPath.setJDKHome(jdkhome); + ClassPath.parseAllClassFiles(); + } + + private static void usage() { + System.out.println("Usage: ConstantPoolAnalyzer "); + System.out.println("Options: "); + System.out.println("\t-jdkhome where all jars will be parsed"); + System.out.println("\t-cpath where classes and jars will be parsed"); + System.exit(-1); + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolParser.java b/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolParser.java new file mode 100644 index 0000000000000000000000000000000000000000..33e593df875c8889a3949800f69b7157774bc418 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/ConstantPoolParser.java @@ -0,0 +1,377 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.classanalyzer; + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.*; +import static com.sun.tools.classfile.ConstantPool.*; + +/** + * + * @author Mandy Chung + */ +public class ConstantPoolParser { + + private final ClassFileParser cfparser; + private final StringValueVisitor visitor; + private final ConstantPool cpool; + + ConstantPoolParser(ClassFileParser parser) { + this.cfparser = parser; + this.cpool = cfparser.classfile.constant_pool; + this.visitor = new StringValueVisitor(); + } + + public String stringValue(CPInfo cpInfo) { + return visitor.visit(cpInfo); + } + + public String stringValue(int constant_pool_index) { + try { + return stringValue(cpool.get(constant_pool_index)); + } catch (ConstantPool.InvalidIndex e) { + throw new RuntimeException(e); + } + } + + public void parseDependency() { + ConstantPool.Visitor v = new ConstantPool.Visitor() { + + public Integer visitClass(CONSTANT_Class_info info, Void p) { + try { + String classname = cfparser.checkClassName(info.getName()); + if (classname.isEmpty()) { + return 1; + } + + Klass from = cfparser.this_klass; + Klass to = Klass.getKlass(classname); + ResolutionInfo resInfo = ResolutionInfo.resolvedConstantPool(from, to, info.name_index); + + from.addDep(to, resInfo); + to.addReferrer(from, resInfo); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + return 1; + } + + public Integer visitDouble(CONSTANT_Double_info info, Void p) { + // skip + return 2; + } + + public Integer visitFieldref(CONSTANT_Fieldref_info info, Void p) { + // skip + return 1; + } + + public Integer visitFloat(CONSTANT_Float_info info, Void p) { + // skip + return 1; + } + + public Integer visitInteger(CONSTANT_Integer_info info, Void p) { + // skip + return 1; + } + + public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { + // skip + return 1; + } + + public Integer visitLong(CONSTANT_Long_info info, Void p) { + // skip + return 2; + } + + public Integer visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + // skip + return 1; + } + + public Integer visitMethodref(CONSTANT_Methodref_info info, Void p) { + // skip + return 1; + } + + public Integer visitString(CONSTANT_String_info info, Void p) { + // skip + return 1; + } + + public Integer visitUtf8(CONSTANT_Utf8_info info, Void p) { + // skip + return 1; + } + }; + int cpx = 1; + while (cpx < cpool.size()) { + try { + CPInfo cpInfo = cpool.get(cpx); + cpx += cpInfo.accept(v, null); + } catch (ConstantPool.InvalidIndex ex) { + throw new RuntimeException(ex); + } + } + } + + int getTag(int index) { + try { + return cpool.get(index).getTag(); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + + String getDescriptor(int index) { + CPInfo cpInfo; + try { + cpInfo = cpool.get(index); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + + int tag = cpInfo.getTag(); + switch (tag) { + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_Fieldref: + // simplify references within this class + CPRefInfo ref = (CPRefInfo) cpInfo; + try { + return ref.getNameAndTypeInfo().getType(); + } catch (ConstantPoolException ex) { + } + } + return stringValue(cpInfo); + } + + String getMethodName(int index) { + try { + CPInfo cpInfo = cpool.get(index); + if (cpInfo.getTag() == CONSTANT_Methodref || + cpInfo.getTag() == CONSTANT_InterfaceMethodref) { + + // simplify references within this class + CPRefInfo ref = (CPRefInfo) cpInfo; + String classname; + if (ref.class_index == cfparser.classfile.this_class) { + classname = cfparser.this_klass.getClassName(); + } else { + classname = cfparser.checkClassName(ref.getClassName()).replace('/', '.'); + } + String methodname = ref.getNameAndTypeInfo().getName(); + return classname + "." + methodname; + } else { + return null; + } + } catch (InvalidIndex ex) { + throw new RuntimeException(ex); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + + } + + class StringValueVisitor implements ConstantPool.Visitor { + + public StringValueVisitor() { + } + + public String visit(CPInfo info) { + return info.accept(this, null); + } + + public String visitClass(CONSTANT_Class_info info, Void p) { + return getCheckedName(info); + } + + String getCheckedName(CONSTANT_Class_info info) { + try { + return checkName(info.getName()); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitDouble(CONSTANT_Double_info info, Void p) { + return info.value + "d"; + } + + public String visitFieldref(CONSTANT_Fieldref_info info, Void p) { + return visitRef(info, p); + } + + public String visitFloat(CONSTANT_Float_info info, Void p) { + return info.value + "f"; + } + + public String visitInteger(CONSTANT_Integer_info info, Void p) { + return String.valueOf(info.value); + } + + public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) { + return visitRef(info, p); + } + + public String visitLong(CONSTANT_Long_info info, Void p) { + return info.value + "l"; + } + + public String visitNameAndType(CONSTANT_NameAndType_info info, Void p) { + return getCheckedName(info) + ":" + getType(info); + } + + String getCheckedName(CONSTANT_NameAndType_info info) { + try { + return checkName(info.getName()); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + String getType(CONSTANT_NameAndType_info info) { + try { + return info.getType(); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitMethodref(CONSTANT_Methodref_info info, Void p) { + return visitRef(info, p); + } + + public String visitString(CONSTANT_String_info info, Void p) { + try { + int string_index = info.string_index; + return cpool.getUTF8Info(string_index).accept(this, p); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + + public String visitUtf8(CONSTANT_Utf8_info info, Void p) { + String s = info.value; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '\t': + sb.append('\\').append('t'); + break; + case '\n': + sb.append('\\').append('n'); + break; + case '\r': + sb.append('\\').append('r'); + break; + case '\"': + sb.append('\\').append('\"'); + break; + default: + sb.append(c); + } + } + return sb.toString(); + } + + String visitRef(CPRefInfo info, Void p) { + String cn = getCheckedClassName(info); + String nat; + try { + nat = info.getNameAndTypeInfo().accept(this, p); + } catch (ConstantPoolException e) { + nat = e.getMessage(); + } + return cn + "." + nat; + } + + String getCheckedClassName(CPRefInfo info) { + try { + return checkName(info.getClassName()); + } catch (ConstantPoolException e) { + throw new RuntimeException(e); + } + } + } + /* If name is a valid binary name, return it; otherwise quote it. */ + + private static String checkName(String name) { + if (name == null) { + return "null"; + } + + int len = name.length(); + if (len == 0) { + return "\"\""; + } + + int cc = '/'; + int cp; + for (int k = 0; k < len; k += Character.charCount(cp)) { + cp = name.codePointAt(k); + if ((cc == '/' && !Character.isJavaIdentifierStart(cp)) || (cp != '/' && !Character.isJavaIdentifierPart(cp))) { + return "\"" + name + "\""; + } + cc = cp; + } + return name; + } + + String tagName(int index) { + try { + int tag = cpool.get(index).getTag(); + switch (tag) { + case CONSTANT_Utf8: + return "Utf8"; + case CONSTANT_Integer: + return "int"; + case CONSTANT_Float: + return "float"; + case CONSTANT_Long: + return "long"; + case CONSTANT_Double: + return "double"; + case CONSTANT_Class: + return "class"; + case CONSTANT_String: + return "String"; + case CONSTANT_Fieldref: + return "Field"; + case CONSTANT_Methodref: + return "Method"; + case CONSTANT_InterfaceMethodref: + return "InterfaceMethod"; + case CONSTANT_NameAndType: + return "NameAndType"; + default: + return "(unknown tag)"; + } + } catch (InvalidIndex e) { + throw new RuntimeException(e); + } + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/DependencyConfig.java b/make/modules/tools/src/com/sun/classanalyzer/DependencyConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..107e1d10c85d82baffb61161390ba112529db924 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/DependencyConfig.java @@ -0,0 +1,99 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.classanalyzer; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; + +/** + * Config file specifying additional dependency + * Each line consists of: + * -> + * where can be: + * @ClassForName and is its dependency + * @Provider and is the service name + * @Providers and is the list of the service names + * + * @author Mandy Chung + */ +public class DependencyConfig { + private DependencyConfig() { + } + + static void parse(List configs) throws IOException { + for (String s : configs) { + parse(s); + } + } + + private static void parse(String config) throws IOException { + // parse configuration file + FileInputStream in = new FileInputStream(config); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String line; + int lineNumber = 0; + String type = null; + while ((line = reader.readLine()) != null) { + lineNumber++; + line = line.trim(); + if (line.length() == 0 || line.charAt(0) == '#') { + continue; + } + if (line.charAt(0) == '@') { + if (AnnotatedDependency.isValidType(line)) { + type = line; + continue; + } else { + throw new RuntimeException(config + ", line " + + lineNumber + ", invalid annotation type."); + } + } + String[] s = line.split("\\s+"); + if (s.length < 3 || !s[1].equals("->")) { + throw new RuntimeException(config + ", line " + + lineNumber + ", is malformed"); + } + String classname = s[0].trim(); + String value = s[2].trim(); + + Klass k = Klass.findKlass(classname); + if (k == null) { + // System.out.println("Warning: " + classname + " cannot be found"); + continue; + } + AnnotatedDependency dep = AnnotatedDependency.newAnnotatedDependency(type, value, k); + if (dep == null) { + throw new RuntimeException(config + ", line " + + lineNumber + ", is malformed. Fail to construct the dependency."); + } + } + + } finally { + in.close(); + } + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/Klass.java b/make/modules/tools/src/com/sun/classanalyzer/Klass.java new file mode 100644 index 0000000000000000000000000000000000000000..a4d2eb277755dc4cc80170af102f7dcfbe6a1dc6 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/Klass.java @@ -0,0 +1,357 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.classanalyzer; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.TreeSet; + +import com.sun.tools.classfile.AccessFlags; + +/** + * + * @author Mandy Chung + */ +public class Klass implements Comparable { + private final String classname; + private final String packagename; + private Module module; + private boolean isJavaLangObject; + private String[] paths; + private Map> methods; + private AccessFlags accessFlags; + private long filesize; + + private SortedMap> deps; + private SortedMap> referrers; + private List annotatedDeps; + private Set classForNameRefs; + + private Klass(String classname) { + this.classname = classname; + this.paths = classname.replace('.', '/').split("/"); + this.isJavaLangObject = classname.equals("java.lang.Object"); + this.deps = new TreeMap>(); + this.referrers = new TreeMap>(); + this.methods = new HashMap>(); + this.annotatedDeps = new ArrayList(); + this.classForNameRefs = new TreeSet(); + + int pos = classname.lastIndexOf('.'); + this.packagename = (pos > 0) ? classname.substring(0, pos) : ""; + } + + String getBasename() { + return paths[paths.length - 1]; + } + + String getClassName() { + return classname; + } + + String getPackageName() { + return packagename; + } + + String getClassFilePathname() { + StringBuilder sb = new StringBuilder(paths[0]); + for (int i = 1; i < paths.length; i++) { + String p = paths[i]; + sb.append(File.separator).append(p); + } + return sb.append(".class").toString(); + } + + boolean isPublic() { + return accessFlags == null || accessFlags.is(AccessFlags.ACC_PUBLIC); + } + + Module getModule() { + return module; + } + + void setModule(Module m) { + if (module != null) { + throw new RuntimeException("Module for " + this + " already set"); + } + this.module = m; + } + + Set getReferencedClasses() { + return deps.keySet(); + } + + Set getReferencingClasses() { + return referrers.keySet(); + } + + void setAccessFlags(int flags) { + this.accessFlags = new AccessFlags(flags); + } + + void setFileSize(long size) { + this.filesize = size; + } + + long getFileSize() { + return this.filesize; + } + + boolean exists() { + return filesize > 0; + } + + boolean skip(Klass k) { + // skip if either class is a root or same class + return k.isJavaLangObject || this == k || k.classname.equals(classname); + } + + void addDep(Method callee, ResolutionInfo resInfo) { + addDep(callee.getKlass(), resInfo); + } + + void addDep(Klass ref, ResolutionInfo ri) { + if (skip(ref)) { + return; + } + Set resInfos; + if (!deps.containsKey(ref)) { + resInfos = new TreeSet(); + deps.put(ref, resInfos); + } else { + resInfos = deps.get(ref); + } + resInfos.add(ri); + } + + void addReferrer(Method caller, ResolutionInfo resInfo) { + addReferrer(caller.getKlass(), resInfo); + } + + void addReferrer(Klass k, ResolutionInfo ri) { + if (skip(k)) { + return; + } + Set resInfos; + if (!referrers.containsKey(k)) { + resInfos = new TreeSet(); + referrers.put(k, resInfos); + } else { + resInfos = referrers.get(k); + } + resInfos.add(ri); + } + + Method getMethod(String name) { + return getMethod(name, ""); + } + + Method getMethod(String name, String signature) { + Set set; + if (methods.containsKey(name)) { + set = methods.get(name); + } else { + set = new TreeSet(); + methods.put(name, set); + } + + for (Method m : set) { + if (m.getName().equals(name) && m.getSignature().equals(signature)) { + return m; + } + } + Method m = new Method(this, name, signature); + set.add(m); + return m; + } + + @Override + public String toString() { + return classname; + } + + @Override + public int compareTo(Klass o) { + return classname.compareTo(o.classname); + } + + void addAnnotatedDep(AnnotatedDependency dep) { + annotatedDeps.add(dep); + } + + void addClassForNameReference(String method) { + classForNameRefs.add(method); + } + + List getAnnotatedDeps() { + return annotatedDeps; + } + + private static Map classes = new TreeMap(); + static Set getAllClasses() { + return new TreeSet(classes.values()); + } + + static Klass findKlassFromPathname(String filename) { + String name = filename; + if (filename.endsWith(".class")) { + name = filename.substring(0, filename.length() - 6); + } + + // trim ".class" + name = name.replace('/', '.'); + for (Klass k : classes.values()) { + if (name.endsWith(k.getClassName())) { + return k; + } + } + return null; + } + + static Klass findKlass(String classname) { + return classes.get(classname); + } + + static Klass getKlass(String name) { + Klass k; + String classname = name.replace('/', '.'); + if (classname.charAt(classname.length() - 1) == ';') { + classname = classname.substring(0, classname.length() - 1); + } + if (classes.containsKey(classname)) { + k = classes.get(classname); + } else { + k = new Klass(classname); + classes.put(classname, k); + } + return k; + } + + public class Method implements Comparable { + + private final Klass k; + private final String method; + private final String signature; + private long codeLength; + // non-primitive types only + private final List argTypes; + private final Klass returnType; + boolean isAbstract = false; + boolean marked = false; + + public Method(Klass k, String method, String signature) { + this(k, method, signature, null, null); + } + + public Method(Klass k, String method, String signature, Klass returnType, List argTypes) { + this.k = k; + this.method = method; + this.signature = signature; + this.argTypes = argTypes; + this.returnType = returnType; + this.codeLength = 0; + } + + public Klass getKlass() { + return k; + } + + public String getName() { + return method; + } + + public String getSignature() { + return signature; + } + + public Klass getReturnType() { + return returnType; + } + + public List argTypes() { + return argTypes; + } + + public void setCodeLength(long len) { + this.codeLength = len; + } + + public long getCodeLength() { + return codeLength; + } + + @Override + public boolean equals(Object o) { + if (o instanceof Method) { + return compareTo((Method) o) == 0; + } else { + return false; + } + } + + @Override + public int hashCode() { + int hash = 3; + hash = 71 * hash + (this.k != null ? this.k.hashCode() : 0); + hash = 71 * hash + (this.method != null ? this.method.hashCode() : 0); + return hash; + } + + @Override + public String toString() { + if (signature.isEmpty()) { + return k.classname + "." + method; + } else { + return signature; + } + } + + public String toHtmlString() { + return toString().replace("<", "<").replace(">", ">"); + } + + boolean isClinit() { + return method.equals(""); + } + + public int compareTo(Method m) { + if (k == m.getKlass()) { + if (method.equals(m.method)) { + return signature.compareTo(m.signature); + } else { + return method.compareTo(m.method); + } + } else { + return k.compareTo(m.getKlass()); + } + } + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/Module.java b/make/modules/tools/src/com/sun/classanalyzer/Module.java new file mode 100644 index 0000000000000000000000000000000000000000..26af227763725c688da8f85ab646a3c67f5bc8ec --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/Module.java @@ -0,0 +1,693 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ +package com.sun.classanalyzer; + +import com.sun.classanalyzer.AnnotatedDependency.OptionalDependency; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Collections; +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class Module implements Comparable { + + private static Map modules = new LinkedHashMap(); + + public static Module addModule(ModuleConfig config) { + String name = config.module; + if (modules.containsKey(name)) { + throw new RuntimeException("module \"" + name + "\" already exists"); + } + + Module m = new Module(config); + modules.put(name, m); + return m; + } + + public static Module findModule(String name) { + return modules.get(name); + } + + static Collection getAllModules() { + return Collections.unmodifiableCollection(modules.values()); + } + private final String name; + private final ModuleConfig config; + private final Set classes; + private final Set resources; + private final Set unresolved; + private final Set dependents; + private final Map packages; + private final Set members; + private Module group; + private boolean isBaseModule; + + private Module(ModuleConfig config) { + this.name = config.module; + this.isBaseModule = config.isBase; + this.classes = new TreeSet(); + this.resources = new TreeSet(); + this.config = config; + this.unresolved = new HashSet(); + this.dependents = new TreeSet(); + this.packages = new TreeMap(); + this.members = new TreeSet(); + this.group = this; // initialize to itself + } + + String name() { + return name; + } + + Module group() { + return group; + } + + boolean isBase() { + return isBaseModule; + } + + Set members() { + return members; + } + + boolean contains(Klass k) { + return k != null && classes.contains(k); + } + + boolean isEmpty() { + return classes.isEmpty() && resources.isEmpty(); + } + + /** + * Returns an Iterable of Dependency, only one for each dependent + * module of the strongest dependency (i.e. + * hard static > hard dynamic > optional static > optional dynamic + */ + Iterable dependents() { + Map deps = new LinkedHashMap(); + for (Dependency dep : dependents) { + Dependency d = deps.get(dep.module); + if (d == null || dep.compareTo(d) > 0) { + deps.put(dep.module, dep); + } + } + return deps.values(); + } + + @Override + public int compareTo(Module o) { + if (o == null) { + return -1; + } + return name.compareTo(o.name); + } + + @Override + public String toString() { + return name; + } + + void addKlass(Klass k) { + classes.add(k); + k.setModule(this); + + // update package statistics + String pkg = k.getPackageName(); + PackageInfo pkginfo = packages.get(pkg); + if (pkginfo == null) { + pkginfo = new PackageInfo(pkg); + packages.put(pkg, pkginfo); + } + if (k.exists()) { + // only count the class that is parsed + pkginfo.add(k.getFileSize()); + } + } + + void addResource(ResourceFile res) { + resources.add(res); + res.setModule(this); + } + + void processRootsAndReferences() { + // start with the root set + Deque pending = new ArrayDeque(); + for (Klass k : Klass.getAllClasses()) { + if (k.getModule() != null) { + continue; + } + String classname = k.getClassName(); + if (config.matchesRoot(classname) && !config.isExcluded(classname)) { + addKlass(k); + pending.add(k); + } + } + + // follow all references + Klass k; + while ((k = pending.poll()) != null) { + if (!classes.contains(k)) { + addKlass(k); + } + for (Klass other : k.getReferencedClasses()) { + Module otherModule = other.getModule(); + if (otherModule != null && otherModule != this) { + // this module is dependent on otherModule + addDependency(k, other); + continue; + } + + if (!classes.contains(other)) { + if (config.isExcluded(other.getClassName())) { + // reference to an excluded class + unresolved.add(new Reference(k, other)); + } else { + pending.add(other); + } + } + } + } + + // add other matching classes that don't require dependency analysis + for (Klass c : Klass.getAllClasses()) { + if (c.getModule() == null) { + String classname = c.getClassName(); + if (config.matchesIncludes(classname) && !config.isExcluded(classname)) { + addKlass(c); + // dependencies + for (Klass other : c.getReferencedClasses()) { + Module otherModule = other.getModule(); + if (otherModule == null) { + unresolved.add(new Reference(c, other)); + } else { + if (otherModule != this) { + // this module is dependent on otherModule + addDependency(c, other); + } + } + } + } + } + } + + + // add other matching classes that don't require dependency analysis + for (ResourceFile res : ResourceFile.getAllResources()) { + if (res.getModule() == null) { + String name = res.getName(); + if (config.matchesIncludes(name) && !config.isExcluded(name)) { + addResource(res); + } + } + } + } + + void addDependency(Klass from, Klass to) { + Dependency dep = new Dependency(from, to); + dependents.add(dep); + } + + void fixupDependencies() { + // update dependencies for classes that were allocated to modules after + // this module was processed. + for (Reference ref : unresolved) { + Module m = ref.referree().getModule(); + if (m == null || m != this) { + addDependency(ref.referrer, ref.referree); + } + } + + fixupAnnotatedDependencies(); + } + + private void fixupAnnotatedDependencies() { + // add dependencies that this klass may depend on due to the AnnotatedDependency + dependents.addAll(AnnotatedDependency.getDependencies(this)); + } + + boolean isModuleDependence(Klass k) { + Module m = k.getModule(); + return m == null || (!classes.contains(k) && !m.isBase()); + } + + Module getModuleDependence(Klass k) { + if (isModuleDependence(k)) { + Module m = k.getModule(); + if (group == this && m != null) { + // top-level module + return m.group; + } else { + return m; + } + } + return null; + } + +

void visit(Set visited, Visitor

visitor, P p) { + if (!visited.contains(this)) { + visited.add(this); + visitor.preVisit(this, p); + for (Module m : members) { + m.visit(visited, visitor, p); + visitor.postVisit(this, m, p); + } + } else { + throw new RuntimeException("Cycle detected: module " + this.name); + } + } + + void addMember(Module m) { + // merge class list + for (Klass k : m.classes) { + classes.add(k); + } + + // merge resource list + for (ResourceFile res : m.resources) { + resources.add(res); + } + + // merge the package statistics + for (PackageInfo pinfo : m.getPackageInfos()) { + String packageName = pinfo.pkgName; + PackageInfo pkginfo = packages.get(packageName); + if (pkginfo == null) { + pkginfo = new PackageInfo(packageName); + packages.put(packageName, pkginfo); + } + pkginfo.add(pinfo); + } + } + + static void buildModuleMembers() { + // set up module member relationship + for (Module m : modules.values()) { + m.group = m; // initialize to itself + for (String name : m.config.members()) { + Module member = modules.get(name); + if (member == null) { + throw new RuntimeException("module \"" + name + "\" doesn't exist"); + } + m.members.add(member); + } + } + + // set up the top-level module + Visitor groupSetter = new Visitor() { + + public void preVisit(Module m, Module p) { + m.group = p; + if (p.isBaseModule) { + // all members are also base + m.isBaseModule = true; + } + } + + public void postVisit(Module m, Module child, Module p) { + // nop - breadth-first search + } + }; + + // propagate the top-level module to all its members + for (Module p : modules.values()) { + for (Module m : p.members) { + if (m.group == m) { + m.visit(new TreeSet(), groupSetter, p); + } + } + } + + Visitor mergeClassList = new Visitor() { + + public void preVisit(Module m, Module p) { + // nop - depth-first search + } + + public void postVisit(Module m, Module child, Module p) { + m.addMember(child); + } + }; + + Set visited = new TreeSet(); + for (Module m : modules.values()) { + if (m.group() == m) { + if (m.members().size() > 0) { + // merge class list from all its members + m.visit(visited, mergeClassList, m); + } + + // clear the dependencies before fixup + m.dependents.clear(); + + // fixup dependencies + for (Klass k : m.classes) { + for (Klass other : k.getReferencedClasses()) { + if (m.isModuleDependence(other)) { + // this module is dependent on otherModule + m.addDependency(k, other); + } + } + } + + // add dependencies that this klass may depend on due to the AnnotatedDependency + m.fixupAnnotatedDependencies(); + } + } + } + + class PackageInfo implements Comparable { + + final String pkgName; + int count; + long filesize; + + PackageInfo(String name) { + this.pkgName = name; + this.count = 0; + this.filesize = 0; + } + + void add(PackageInfo pkg) { + this.count += pkg.count; + this.filesize += pkg.filesize; + } + + void add(long size) { + count++; + filesize += size; + + } + + @Override + public int compareTo(Object o) { + return pkgName.compareTo(((PackageInfo) o).pkgName); + } + } + + Set getPackageInfos() { + return new TreeSet(packages.values()); + } + + void printSummaryTo(String output) throws IOException { + PrintWriter writer = new PrintWriter(output); + try { + long total = 0L; + int count = 0; + writer.format("%10s\t%10s\t%s\n", "Bytes", "Classes", "Package name"); + for (String pkg : packages.keySet()) { + PackageInfo info = packages.get(pkg); + if (info.count > 0) { + writer.format("%10d\t%10d\t%s\n", info.filesize, info.count, pkg); + total += info.filesize; + count += info.count; + } + } + + writer.format("\nTotal: %d bytes (uncompressed) %d classes\n", total, count); + } finally { + writer.close(); + } + + } + + void printClassListTo(String output) throws IOException { + // no file created if the module doesn't have any class + if (classes.isEmpty()) { + return; + } + + PrintWriter writer = new PrintWriter(output); + try { + for (Klass c : classes) { + if (c.exists()) { + writer.format("%s\n", c.getClassFilePathname()); + } else { + trace("%s in module %s missing\n", c, this); + } + } + + } finally { + writer.close(); + } + } + + void printResourceListTo(String output) throws IOException { + // no file created if the module doesn't have any resource file + if (resources.isEmpty()) { + return; + } + + PrintWriter writer = new PrintWriter(output); + try { + for (ResourceFile res : resources) { + writer.format("%s\n", res.getPathname()); + } + } finally { + writer.close(); + } + } + + void printDependenciesTo(String output, boolean showDynamic) throws IOException { + // no file created if the module doesn't have any class + if (classes.isEmpty()) { + return; + } + + PrintWriter writer = new PrintWriter(output); + try { + // classes that this klass may depend on due to the AnnotatedDependency + Map> annotatedDeps = AnnotatedDependency.getReferences(this); + + for (Klass klass : classes) { + Set references = klass.getReferencedClasses(); + for (Klass other : references) { + String classname = klass.getClassName(); + boolean optional = OptionalDependency.isOptional(klass, other); + if (optional) { + classname = "[optional] " + classname; + } + + Module m = getModuleDependence(other); + if (m != null || other.getModule() == null) { + writer.format("%-40s -> %s (%s)", classname, other, m); + Reference ref = new Reference(klass, other); + if (annotatedDeps.containsKey(ref)) { + for (AnnotatedDependency ad : annotatedDeps.get(ref)) { + writer.format(" %s", ad.getTag()); + } + // printed; so remove the dependency from the annotated deps list + annotatedDeps.remove(ref); + } + writer.format("\n"); + } + } + } + + + // print remaining dependencies specified in AnnotatedDependency list + if (annotatedDeps.size() > 0) { + for (Map.Entry> entry : annotatedDeps.entrySet()) { + Reference ref = entry.getKey(); + Module m = getModuleDependence(ref.referree); + if (m != null || ref.referree.getModule() == null) { + String classname = ref.referrer.getClassName(); + boolean optional = true; + boolean dynamic = true; + String tag = ""; + for (AnnotatedDependency ad : entry.getValue()) { + if (optional && !ad.isOptional()) { + optional = false; + tag = ad.getTag(); + } + if (!ad.isDynamic()) { + dynamic = false; + } + } + if (!showDynamic && optional && dynamic) { + continue; + } + if (optional) { + if (dynamic) { + classname = "[dynamic] " + classname; + } else { + classname = "[optional] " + classname; + } + } + writer.format("%-40s -> %s (%s) %s%n", classname, ref.referree, m, tag); + } + } + } + + } finally { + writer.close(); + } + } + + static class Dependency implements Comparable { + + final Module module; + final boolean optional; + final boolean dynamic; + + Dependency(Klass from, Klass to) { + // static dependency + this.module = to.getModule() != null ? to.getModule().group() : null; + this.optional = OptionalDependency.isOptional(from, to); + this.dynamic = false; + } + + Dependency(Module m, boolean optional, boolean dynamic) { + this.module = m != null ? m.group() : null; + this.optional = optional; + this.dynamic = dynamic; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Dependency)) { + return false; + } + if (this == obj) { + return true; + } + + Dependency d = (Dependency) obj; + if (this.module != d.module) { + return false; + } else { + return this.optional == d.optional && this.dynamic == d.dynamic; + } + } + + @Override + public int hashCode() { + int hash = 3; + hash = 19 * hash + (this.module != null ? this.module.hashCode() : 0); + hash = 19 * hash + (this.optional ? 1 : 0); + hash = 19 * hash + (this.dynamic ? 1 : 0); + return hash; + } + + @Override + public int compareTo(Dependency d) { + if (this.equals(d)) { + return 0; + } + + // Hard static > hard dynamic > optional static > optional dynamic + if (this.module == d.module) { + if (this.optional == d.optional) { + return this.dynamic ? -1 : 1; + } else { + return this.optional ? -1 : 1; + } + } else if (this.module != null && d.module != null) { + return (this.module.compareTo(d.module)); + } else { + return (this.module == null) ? -1 : 1; + } + } + + @Override + public String toString() { + String s = module.name(); + if (dynamic && optional) { + s += " (dynamic)"; + } else if (optional) { + s += " (optional)"; + } + return s; + } + } + + static class Reference implements Comparable { + + private final Klass referrer, referree; + + Reference(Klass referrer, Klass referree) { + this.referrer = referrer; + this.referree = referree; + } + + Klass referrer() { + return referrer; + } + + Klass referree() { + return referree; + } + + @Override + public int hashCode() { + return referrer.hashCode() ^ referree.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Reference)) { + return false; + } + if (this == obj) { + return true; + } + + Reference r = (Reference) obj; + return (this.referrer.equals(r.referrer) && + this.referree.equals(r.referree)); + } + + @Override + public int compareTo(Reference r) { + int ret = referrer.compareTo(r.referrer); + if (ret == 0) { + ret = referree.compareTo(r.referree); + } + return ret; + } + } + + interface Visitor

{ + + public void preVisit(Module m, P param); + + public void postVisit(Module m, Module child, P param); + } + private static boolean traceOn = System.getProperty("classanalyzer.debug") != null; + + private static void trace(String format, Object... params) { + System.err.format(format, params); + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/ModuleConfig.java b/make/modules/tools/src/com/sun/classanalyzer/ModuleConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..d5ead840e01b5eea3e03a35328b65f870e5ddb69 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/ModuleConfig.java @@ -0,0 +1,562 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.classanalyzer; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Pattern; + +/** + * + * @author Mandy Chung + */ +public class ModuleConfig { + + private static String baseModuleName = "base"; + private final Set roots; + private final Set includes; + private final Filter filter; + private List members; + final String module; + final boolean isBase; + + private ModuleConfig(String name) throws IOException { + this.roots = new TreeSet(); + this.includes = new TreeSet(); + this.module = name; + this.isBase = name.equals(baseModuleName); + this.filter = new Filter(this); + } + + List members() { + if (members == null) { + members = new LinkedList(); + + for (String s : includes) { + if (!s.contains("*") && Module.findModule(s) != null) { + // module member + members.add(s); + } + } + } + return members; + } + + boolean matchesRoot(String name) { + for (String pattern : roots) { + if (matches(name, pattern)) { + return true; + } + } + return false; + } + + boolean matchesIncludes(String name) { + for (String pattern : includes) { + if (matches(name, pattern)) { + return true; + } + } + return false; + } + + boolean isExcluded(String name) { + return filter.isExcluded(name); + } + + boolean matchesPackage(String packageName, String pattern) { + int pos = pattern.lastIndexOf('.'); + String pkg = pos > 0 ? pattern.substring(0, pos) : ""; + return packageName.equals(pkg); + } + + + boolean matches(String name, String pattern) { + if (pattern.contains("**") && !pattern.endsWith("**")) { + throw new UnsupportedOperationException("Not yet implemented"); + } + + String javaName = name; + + boolean isResourceFile = name.indexOf('/') >= 0; + if (isResourceFile) { + // it's a resource file; convert the name as a java + javaName = name.replace('/', '.'); + } + if (pattern.indexOf('/') < 0) { + // if the pattern doesn't contain '/ + return matchesJavaName(javaName, pattern); + } else { + if (isResourceFile) { + // the pattern is for matching resource file + return matchesNameWithSlash(name, pattern); + } else { + return false; + } + } + } + + boolean matchesJavaName(String name, String pattern) { + int pos = name.lastIndexOf('.'); + String packageName = pos > 0 ? name.substring(0, pos) : ""; + if (pattern.endsWith("**")) { + String p = pattern.substring(0, pattern.length() - 2); + return name.startsWith(p); + } else if (pattern.endsWith("*") && pattern.indexOf('*') == pattern.lastIndexOf('*')) { + if (matchesPackage(packageName, pattern)) { + // package name has to be exact match + String p = pattern.substring(0, pattern.length() - 1); + return name.startsWith(p); + } else { + return false; + } + } else if (pattern.contains("*")) { + String basename = pos > 0 ? name.substring(pos + 1, name.length()) : name; + pos = pattern.indexOf('*'); + String prefix = pattern.substring(0, pos); + String suffix = pattern.substring(pos + 1, pattern.length()); + if (name.startsWith(prefix) && matchesPackage(packageName, prefix)) { + // package name has to be exact match + if (suffix.contains("*")) { + return name.matches(convertToRegex(pattern)); + } else { + return basename.endsWith(suffix); + } + } else { + // we don't support wildcard be used in the package name + return false; + } + } else { + // exact match or inner class + return name.equals(pattern) || name.startsWith(pattern + "$"); + } + } + + boolean matchesNameWithSlash(String name, String pattern) { + if (pattern.endsWith("**")) { + String p = pattern.substring(0, pattern.length() - 2); + return name.startsWith(p); + } else if (pattern.contains("*")) { + int pos = pattern.indexOf('*'); + String prefix = pattern.substring(0, pos); + String suffix = pattern.substring(pos + 1, pattern.length()); + String tail = name.substring(pos, name.length()); + + if (!name.startsWith(prefix)) { + // prefix has to exact match + return false; + } + + if (pattern.indexOf('*') == pattern.lastIndexOf('*')) { + // exact match prefix with no '/' in the tail string + String wildcard = tail.substring(0, tail.length() - suffix.length()); + return tail.indexOf('/') < 0 && tail.endsWith(suffix); + } + + if (suffix.contains("*")) { + return matchesNameWithSlash(tail, suffix); + } else { + // tail ends with the suffix while no '/' in the wildcard matched string + String any = tail.substring(0, tail.length() - suffix.length()); + return tail.endsWith(suffix) && any.indexOf('/') < 0; + } + } else { + // exact match + return name.equals(pattern); + } + } + + private String convertToRegex(String pattern) { + StringBuilder sb = new StringBuilder(); + int i = 0; + int index = 0; + int plen = pattern.length(); + while (i < plen) { + char p = pattern.charAt(i); + if (p == '*') { + sb.append("(").append(pattern.substring(index, i)).append(")"); + if (i + 1 < plen && pattern.charAt(i + 1) == '*') { + sb.append(".*"); + index = i + 2; + } else { + sb.append("[^\\.]*"); + index = i + 1; + } + } + i++; + } + if (index < plen) { + sb.append("(").append(pattern.substring(index, plen)).append(")"); + } + return sb.toString(); + } + + static class Filter { + + final ModuleConfig config; + final Set exclude = new TreeSet(); + final Set allow = new TreeSet(); + + Filter(ModuleConfig config) { + this.config = config; + } + + Filter exclude(String pattern) { + exclude.add(pattern); + return this; + } + + Filter allow(String pattern) { + allow.add(pattern); + return this; + } + + String allowedBy(String name) { + String allowedBy = null; + for (String pattern : allow) { + if (config.matches(name, pattern)) { + if (name.equals(pattern)) { + return pattern; // exact match + } + if (allowedBy == null) { + allowedBy = pattern; + } else { + if (pattern.length() > allowedBy.length()) { + allowedBy = pattern; + } + } + } + } + return allowedBy; + } + + String excludedBy(String name) { + String allowedBy = allowedBy(name); + String excludedBy = null; + + if (allowedBy != null && name.equals(allowedBy)) { + return null; // exact match + } + for (String pattern : exclude) { + if (config.matches(name, pattern)) { + // not matched by allowed rule or exact match + if (allowedBy == null || name.equals(pattern)) { + return pattern; + } + if (excludedBy == null) { + excludedBy = pattern; + } else { + if (pattern.length() > excludedBy.length()) { + excludedBy = pattern; + } + } + } + } + return excludedBy; + } + + boolean isExcluded(String name) { + String allowedBy = allowedBy(name); + String excludedBy = excludedBy(name); + + if (excludedBy == null) { + return false; + } + // not matched by allowed rule or exact match + if (allowedBy == null || name.equals(excludedBy)) { + return true; + } + + if (allowedBy == null) { + return true; + } + if (allowedBy != null && + excludedBy.length() > allowedBy.length()) { + return true; + } + return false; + } + } + + private static String trimComment(String line) { + StringBuilder sb = new StringBuilder(); + + int pos = 0; + while (pos >= 0 && pos < line.length()) { + int c1 = line.indexOf("//", pos); + if (c1 > 0 && !Character.isWhitespace(line.charAt(c1-1))) { + // not a comment + c1 = -1; + } + + int c2 = line.indexOf("/*", pos); + if (c2 > 0 && !Character.isWhitespace(line.charAt(c2-1))) { + // not a comment + c2 = -1; + } + + int c = line.length(); + int n = line.length(); + if (c1 >= 0 || c2 >= 0) { + if (c1 >= 0) { + c = c1; + } + if (c2 >= 0 && c2 < c) { + c = c2; + } + int c3 = line.indexOf("*/", c2 + 2); + if (c == c2 && c3 > c2) { + n = c3 + 2; + } + } + if (c > 0) { + if (sb.length() > 0) { + // add a whitespace if multiple comments on one line + sb.append(" "); + } + sb.append(line.substring(pos, c)); + } + pos = n; + } + return sb.toString(); + } + + private static boolean beginBlockComment(String line) { + int pos = 0; + while (pos >= 0 && pos < line.length()) { + int c = line.indexOf("/*", pos); + if (c < 0) { + return false; + } + + if (c > 0 && !Character.isWhitespace(line.charAt(c-1))) { + return false; + } + + int c1 = line.indexOf("//", pos); + if (c1 >= 0 && c1 < c) { + return false; + } + + int c2 = line.indexOf("*/", c + 2); + if (c2 < 0) { + return true; + } + pos = c + 2; + } + return false; + } + + static void setBaseModule(String name) { + baseModuleName = name; + } + // TODO: we shall remove "-" from the regex once we define + // the naming convention for the module names without dashes + static final Pattern classNamePattern = Pattern.compile("[\\w\\.\\*_$-/]+"); + + static List readConfigurationFile(String file) throws IOException { + List result = new ArrayList(); + // parse configuration file + FileInputStream in = new FileInputStream(file); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + String line; + + int lineNumber = 0; + boolean inRoots = false; + boolean inIncludes = false; + boolean inAllows = false; + boolean inExcludes = false; + boolean inBlockComment = false; + ModuleConfig config = null; + + while ((line = reader.readLine()) != null) { + lineNumber++; + + if (inBlockComment) { + int c = line.indexOf("*/"); + if (c >= 0) { + line = line.substring(c + 2, line.length()); + inBlockComment = false; + } else { + // skip lines until end of comment block + continue; + } + } + + inBlockComment = beginBlockComment(line); + + line = trimComment(line).trim(); + // ignore empty lines + if (line.length() == 0) { + continue; + } + + String values; + if (inRoots || inIncludes || inExcludes || inAllows) { + values = line; + } else { + String[] s = line.split("\\s+"); + String keyword = s[0].trim(); + if (keyword.equals("module")) { + if (s.length != 3 || !s[2].trim().equals("{")) { + throw new RuntimeException(file + ", line " + + lineNumber + ", is malformed"); + } + config = new ModuleConfig(s[1].trim()); + result.add(config); + // switch to a new module; so reset the flags + inRoots = false; + inIncludes = false; + inExcludes = false; + inAllows = false; + continue; + } else if (keyword.equals("roots")) { + inRoots = true; + } else if (keyword.equals("include")) { + inIncludes = true; + } else if (keyword.equals("exclude")) { + inExcludes = true; + } else if (keyword.equals("allow")) { + inAllows = true; + } else if (keyword.equals("}")) { + if (config == null || s.length != 1) { + throw new RuntimeException(file + ", line " + + lineNumber + ", is malformed"); + } else { + // end of a module + config = null; + continue; + } + } else { + throw new RuntimeException(file + ", \"" + keyword + "\" on line " + + lineNumber + ", is not recognized"); + } + values = line.substring(keyword.length(), line.length()).trim(); + } + + if (config == null) { + throw new RuntimeException(file + ", module not specified"); + } + + int len = values.length(); + if (len == 0) { + continue; + } + char lastchar = values.charAt(len - 1); + if (lastchar != ',' && lastchar != ';') { + throw new RuntimeException(file + ", line " + + lineNumber + ", is malformed:" + + " ',' or ';' is missing."); + } + + values = values.substring(0, len - 1); + // parse the values specified for a keyword specified + for (String s : values.split(",")) { + s = s.trim(); + if (s.length() > 0) { + if (!classNamePattern.matcher(s).matches()) { + throw new RuntimeException(file + ", line " + + lineNumber + ", is malformed: \"" + s + "\""); + } + if (inRoots) { + config.roots.add(s); + } else if (inIncludes) { + config.includes.add(s); + } else if (inExcludes) { + config.filter.exclude(s); + } else if (inAllows) { + config.filter.allow(s); + } + + } + } + if (lastchar == ';') { + inRoots = false; + inIncludes = false; + inExcludes = false; + inAllows = false; + } + } + + if (inBlockComment) { + throw new RuntimeException(file + ", line " + + lineNumber + ", missing \"*/\" to end a block comment"); + } + if (config != null) { + throw new RuntimeException(file + ", line " + + lineNumber + ", missing \"}\" to end module definition" + + " for \"" + config.module + "\""); + } + + } finally { + in.close(); + } + + return result; + } + + private String format(String keyword, Collection values) { + if (values.size() == 0) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + String format = "%4s%-9s"; + String spaces = String.format(format, "", ""); + sb.append(String.format(format, "", keyword)); + int count = 0; + for (String s : values) { + if (count > 0) { + sb.append(",\n").append(spaces); + } else if (count++ > 0) { + sb.append(", "); + } + sb.append(s); + } + if (count > 0) { + sb.append(";\n"); + } + return sb.toString(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("module " + module).append(" {\n"); + sb.append(format("include", includes)); + sb.append(format("root", roots)); + sb.append(format("allow", filter.allow)); + sb.append(format("exclude", filter.exclude)); + sb.append("}\n"); + return sb.toString(); + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/ResolutionInfo.java b/make/modules/tools/src/com/sun/classanalyzer/ResolutionInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..19746a49648b415d064a745d31902e35ae873a8c --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/ResolutionInfo.java @@ -0,0 +1,201 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package com.sun.classanalyzer; + +import com.sun.classanalyzer.Klass.Method; + +/** + * + * @author mchung + */ +public class ResolutionInfo implements Comparable { + + enum Type { + + REFLECTION("reflection", true), + NATIVE("native", true), + INTERFACE("interface", false), + SUPER("super", false), + EXPLICIT("explicit", false), + VERIFICATION("verification", false), + METHODTRACE("method trace", true), + CONSTANT_POOL("constant pool", true), + CHECKED_EXCEPTION("throws", true), + METHOD("method", true), + FIELD("field", true), + EXTENDS("extends", true), + IMPLEMENTS("implements", true), + NOINFO("No info", false); + + private final String name; + private final boolean hasInfo; + + private Type(String name, boolean hasInfo) { + this.name = name; + this.hasInfo = hasInfo; + } + + public String getName() { + return name; + } + + public boolean hasInfo() { + return hasInfo; + } + + public static Type getType(String s) { + if (s.isEmpty()) { + return NOINFO; + } + for (Type t : values()) { + if (s.equals(t.name)) { + return t; + } + } + // Need to fix the VM output to add "native" + // throw new IllegalArgumentException("Invalid ResolutionInfo.type \"" + s + "\""); + System.out.println("WARNING: Invalid ResolutionInfo.type \"" + s + "\""); + return null; + } + } + final Klass fromClass; + final Method method; + final Klass toClass; + final int linenumber; + final Type type; + final String info; + private boolean isPublic = false; + + private ResolutionInfo(Klass from, Klass to, int linenumber, Type type, String info) { + this.fromClass = from; + this.method = null; + this.toClass = to; + this.linenumber = linenumber; + this.type = type; + this.info = info; + } + + private ResolutionInfo(Klass from, Method m, Klass to, int linenumber, Type type) { + this.fromClass = from; + this.method = m; + this.toClass = to; + this.linenumber = linenumber; + this.type = type; + this.info = m.toString(); + } + + public boolean isPublic() { + return isPublic; + } + + public void setPublicAccess(boolean value) { + isPublic = value; + } + static ResolutionInfo resolved(Klass from, Klass to) { + return new ResolutionInfo(from, to, 0, Type.NOINFO, ""); + } + + static ResolutionInfo resolved(Klass from, Klass to, int linenumber) { + return new ResolutionInfo(from, to, linenumber, Type.NOINFO, ""); + } + + static ResolutionInfo resolved(Klass from, Klass to, int linenumber, String reason) { + String[] ss = reason.split("\\s+"); + Type type; + String info; + if (linenumber == -1) { + type = Type.NATIVE; + info = ss[0]; // native method name + } else { + info = ss.length == 2 ? ss[1] : ""; + type = Type.getType(ss[0]); + if (type == null) { + if (reason.isEmpty()) { + throw new IllegalArgumentException("Invalid type: " + reason + " (" + ss[0] + ")" + ss.length); + } + // assume it's native + type = Type.NATIVE; + info = reason.isEmpty() ? ss[0] : reason; + } + } + + return new ResolutionInfo(from, to, linenumber, type, info); + } + + static ResolutionInfo resolved(Klass from, Klass to, Method callee) { + return new ResolutionInfo(from, callee, to, 0, Type.METHODTRACE); + } + + static ResolutionInfo resolvedConstantPool(Klass from, Klass to, int index) { + return new ResolutionInfo(from, to, 0, Type.CONSTANT_POOL, "#" + index); + } + + static ResolutionInfo resolvedField(Klass from, Klass to, String fieldname) { + return new ResolutionInfo(from, to, 0, Type.FIELD, fieldname); + } + + static ResolutionInfo resolvedMethodSignature(Klass from, Klass to, Method m) { + return new ResolutionInfo(from, m, to, 0, Type.METHOD); + } + + static ResolutionInfo resolvedCheckedException(Klass from, Klass to, Method m) { + return new ResolutionInfo(from, m, to, 0, Type.CHECKED_EXCEPTION); + } + + static ResolutionInfo resolvedExtends(Klass from, Klass to) { + String info = from.getClassName() + " implements " + to.getClassName(); + return new ResolutionInfo(from, to, 0, Type.EXTENDS, info); + } + + static ResolutionInfo resolvedImplements(Klass from, Klass to) { + String info = from.getClassName() + " implements " + to.getClassName(); + return new ResolutionInfo(from, to, 0, Type.IMPLEMENTS, info); + } + + @Override + public int compareTo(ResolutionInfo ri) { + if (this.fromClass == ri.fromClass && + this.toClass == ri.toClass && + this.linenumber == ri.linenumber && + this.type == ri.type && + this.info.equals(ri.info)) { + return 0; + } else if (this.fromClass == ri.fromClass) { + if (this.linenumber > ri.linenumber) { + return 1; + } else if (this.linenumber < ri.linenumber) { + return -1; + } else if (this.type != ri.type) { + return this.type.getName().compareTo(ri.type.getName()); + } else if (this.toClass != ri.toClass) { + return this.toClass.compareTo(ri.toClass); + } else { + return this.info.compareTo(ri.info); + } + } else { + return this.fromClass.compareTo(ri.fromClass); + } + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/ResourceFile.java b/make/modules/tools/src/com/sun/classanalyzer/ResourceFile.java new file mode 100644 index 0000000000000000000000000000000000000000..8c6714085a63f9269fe45ba8e0b9030c7377888e --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/ResourceFile.java @@ -0,0 +1,186 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ +package com.sun.classanalyzer; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +/** + * + * @author Mandy Chung + */ +public class ResourceFile implements Comparable { + + private final String pathname; + private Module module; + + ResourceFile(String pathname) { + this.pathname = pathname.replace(File.separatorChar, '/'); + } + + Module getModule() { + return module; + } + + void setModule(Module m) { + if (module != null) { + throw new RuntimeException("Module for " + this + " already set"); + } + this.module = m; + } + + String getName() { + return pathname; + } + + String getPathname() { + return pathname; + } + + @Override + public String toString() { + return pathname; + } + + @Override + public int compareTo(ResourceFile o) { + return pathname.compareTo(o.pathname); + } + static Set resources = new TreeSet(); + + static boolean isResource(String pathname) { + String name = pathname.replace(File.separatorChar, '/'); + + if (name.endsWith("META-INF/MANIFEST.MF")) { + return false; + } + if (name.contains("META-INF/JCE_RSA.")) { + return false; + } + + return true; + } + + static void addResource(String name, InputStream in) { + ResourceFile res; + name = name.replace(File.separatorChar, '/'); + if (name.startsWith("META-INF/services")) { + res = new ServiceProviderConfigFile(name, in); + } else { + res = new ResourceFile(name); + } + resources.add(res); + } + + static Set getAllResources() { + return Collections.unmodifiableSet(resources); + } + + static class ServiceProviderConfigFile extends ResourceFile { + + private final List providers = new ArrayList(); + private final String service; + ServiceProviderConfigFile(String pathname, InputStream in) { + super(pathname); + readServiceConfiguration(in, providers); + this.service = pathname.substring("META-INF/services".length() + 1, pathname.length()); + } + + @Override + String getName() { + if (providers.isEmpty()) { + return service; + } else { + // just use the first one for matching + return providers.get(0); + } + } + + @SuppressWarnings("empty-statement") + void readServiceConfiguration(InputStream in, List names) { + BufferedReader br = null; + try { + if (in != null) { + // Properties doesn't perserve the order of the input file + br = new BufferedReader(new InputStreamReader(in, "utf-8")); + int lc = 1; + while ((lc = parseLine(br, lc, names)) >= 0); + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + } + + // Parse a single line from the given configuration file, adding the name + // on the line to the names list. + // + private int parseLine(BufferedReader r, int lc, List names) throws IOException { + String ln = r.readLine(); + if (ln == null) { + return -1; + } + int ci = ln.indexOf('#'); + if (ci >= 0) { + ln = ln.substring(0, ci); + } + ln = ln.trim(); + int n = ln.length(); + if (n != 0) { + if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0)) { + throw new RuntimeException("Illegal configuration-file syntax"); + } + int cp = ln.codePointAt(0); + if (!Character.isJavaIdentifierStart(cp)) { + throw new RuntimeException("Illegal provider-class name: " + ln); + } + for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) { + cp = ln.codePointAt(i); + if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) { + throw new RuntimeException("Illegal provider-class name: " + ln); + } + } + if (!names.contains(ln)) { + names.add(ln); + } + } + return lc + 1; + } + } +} diff --git a/make/modules/tools/src/com/sun/classanalyzer/ShowDeps.java b/make/modules/tools/src/com/sun/classanalyzer/ShowDeps.java new file mode 100644 index 0000000000000000000000000000000000000000..ce585553ba6941f23d827dcdaf87a1b46da7ea02 --- /dev/null +++ b/make/modules/tools/src/com/sun/classanalyzer/ShowDeps.java @@ -0,0 +1,100 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ +package com.sun.classanalyzer; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * A simple tool to print out the static dependencies for a given set of JAR, + * class files, or combinations of. The tools supports an -ignore option to + * ignore references to classes listed in the file (including .classlists + * created by the ClassAnalyzer tool). + */ + +public class ShowDeps { + + static void usage() { + System.out.println("java ShowDeps [-ignore ] file..."); + System.out.println(" where is a class or JAR file, or a directory"); + System.out.println(); + System.out.println("Example usages:"); + System.out.println(" java ShowDeps Foo.jar"); + System.out.println(" java ShowDeps -ignore base.classlist Foo.jar"); + System.out.println(" java ShowDeps -ignore base.classlist -ignore " + + "jaxp-parsers.classlist

"); + System.exit(-1); + } + + public static void main(String[] args) throws IOException { + // process -ignore options + int argi = 0; + Set ignore = new HashSet(); + while (argi < args.length && args[argi].equals("-ignore")) { + argi++; + Scanner s = new Scanner(new File(args[argi++])); + try { + while (s.hasNextLine()) { + String line = s.nextLine(); + if (!line.endsWith(".class")) + continue; + int len = line.length(); + // convert to class names + String clazz = line.replace('\\', '.').replace('/', '.') + .substring(0, len-6); + ignore.add(clazz); + } + } finally { + s.close(); + } + } + + if (argi >= args.length) + usage(); + + // parse all classes + while (argi < args.length) + ClassPath.setClassPath(args[argi++]); + ClassPath.parseAllClassFiles(); + + // find the classes that don't exist + Set unresolved = new TreeSet(); + for (Klass k : Klass.getAllClasses()) { + if (k.getFileSize() == 0) + unresolved.add(k); + } + + // print references to classes that don't exist + for (Klass k: Klass.getAllClasses()) { + for (Klass other : k.getReferencedClasses()) { + if (unresolved.contains(other)) { + String name = other.toString(); + if (!ignore.contains(name)) { + System.out.format("%s -> %s\n", k, other); + } + } + } + } + } +}