OpenJDK / bsd-port / jdk9 / jdk
changeset 13487:2d65c7859d7e
Merge
author | twisti |
---|---|
date | Tue, 22 Dec 2015 13:41:12 -0800 |
parents | abcef5a34091 fb2a4d3c555b |
children | cb31a76eecd1 |
files | src/java.base/share/classes/java/lang/ref/Reference.java src/java.base/share/classes/sun/misc/BASE64Decoder.java src/java.base/share/classes/sun/misc/BASE64Encoder.java src/java.base/share/classes/sun/misc/CharacterDecoder.java src/java.base/share/classes/sun/misc/CharacterEncoder.java src/java.base/share/classes/sun/misc/HexDumpEncoder.java src/java.base/share/classes/sun/misc/ProxyGenerator.java src/java.base/share/classes/sun/misc/Queue.java src/java.base/share/classes/sun/misc/Request.java src/java.base/share/classes/sun/misc/RequestProcessor.java src/java.base/share/classes/sun/misc/UCDecoder.java src/java.base/share/classes/sun/misc/UCEncoder.java src/java.base/share/classes/sun/misc/UUDecoder.java src/java.base/share/classes/sun/misc/UUEncoder.java src/java.base/share/native/libzip/ZipFile.c test/sun/misc/Encode/DecodeBuffer.java test/sun/misc/Encode/Encode.java test/sun/misc/Encode/GetBytes.java |
diffstat | 168 files changed, 4977 insertions(+), 5418 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Fri Dec 18 10:00:55 2015 -0800 +++ b/.hgtags Tue Dec 22 13:41:12 2015 -0800 @@ -339,3 +339,4 @@ 559b626b01179420a94feb9c3d0f246970d2e3fa jdk9-b94 8581faf0d474472e32f589bbc16db7eec912d83f jdk-9+95 c021b855f51e572e63982654b17742cb1f814fb4 jdk-9+96 +fdd84b2265ddce7f50e084b7c8635189bba6f012 jdk-9+97
--- a/make/CompileDemos.gmk Fri Dec 18 10:00:55 2015 -0800 +++ b/make/CompileDemos.gmk Tue Dec 22 13:41:12 2015 -0800 @@ -309,7 +309,7 @@ ifeq ($$($1_TOOLCHAIN), TOOLCHAIN_LINK_CXX) # For C++, we also need some special treatment. - $1_LDFLAGS := $(LDFLAGS_CXX_JDK) + $1_LDFLAGS := $$(LDFLAGS_CXX_JDK) $1_LIBS := $(LIBCXX) ifeq ($(OPENJDK_TARGET_CPU_ARCH), sparc) @@ -324,9 +324,9 @@ OPTIMIZATION := LOW, \ CFLAGS := $$($1_CFLAGS_INCLUDE) $$(CFLAGS_JDKLIB) $$(CFLAGS_DEBUG_SYMBOLS), \ CXXFLAGS := $$($1_CXXFLAGS), \ - LDFLAGS := $(filter-out -incremental:no -opt:ref, $(LDFLAGS_JDKLIB)) \ + LDFLAGS := $(filter-out -incremental:no -opt:ref, $$(LDFLAGS_JDKLIB)) \ $$($1_LDFLAGS), \ - LDFLAGS_macosx := $(call SET_EXECUTABLE_ORIGIN), \ + LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN), \ LIBS := $$($1_LIBS), \ LIBS_solaris := -lc, \ VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
--- a/make/launcher/Launcher-java.base.gmk Fri Dec 18 10:00:55 2015 -0800 +++ b/make/launcher/Launcher-java.base.gmk Tue Dec 22 13:41:12 2015 -0800 @@ -127,8 +127,7 @@ $(BUILD_JEXEC_INC), \ CFLAGS_linux := -fPIC, \ CFLAGS_solaris := -KPIC, \ - LDFLAGS := $(LDFLAGS_JDKEXE) \ - $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)), \ + LDFLAGS := $(LDFLAGS_JDKEXE), \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/jexec_obj, \ OUTPUT_DIR := $(BUILD_JEXEC_DST_DIR), \ DEBUG_SYMBOLS := true, \
--- a/make/launcher/Launcher-jdk.pack200.gmk Fri Dec 18 10:00:55 2015 -0800 +++ b/make/launcher/Launcher-jdk.pack200.gmk Tue Dec 22 13:41:12 2015 -0800 @@ -89,7 +89,6 @@ MAPFILE := $(UNPACK_MAPFILE),\ LDFLAGS := $(UNPACKEXE_ZIPOBJS) \ $(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \ - $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)unpack$(SHARED_LIBRARY_SUFFIX)) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS := $(UNPACKEXE_LIBS) $(LIBCXX), \ LIBS_solaris := -lc, \
--- a/make/launcher/LauncherCommon.gmk Fri Dec 18 10:00:55 2015 -0800 +++ b/make/launcher/LauncherCommon.gmk Tue Dec 22 13:41:12 2015 -0800 @@ -25,6 +25,12 @@ include NativeCompilation.gmk +# SetupNativeCompilation now supports debug symbols on macosx for hotspot. +# Disable it here for the jdk binaries until we decide to enable them. +ifeq ($(OPENJDK_TARGET_OS), macosx) + ENABLE_DEBUG_SYMBOLS := false +endif + # Prepare the find cache. $(eval $(call FillCacheFind, $(JDK_TOPDIR)/src/java.base/share/native/launcher)) @@ -180,15 +186,12 @@ CFLAGS_linux := -fPIC, \ CFLAGS_solaris := -KPIC -DHAVE_GETHRTIME, \ CFLAGS_windows := $$($1_CFLAGS_windows), \ - LDFLAGS := $(LDFLAGS_JDKEXE) \ + LDFLAGS := $$(LDFLAGS_JDKEXE) \ $$(ORIGIN_ARG) \ $$($1_LDFLAGS), \ LDFLAGS_linux := \ - $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)) \ -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \ - LDFLAGS_macosx := $(call SET_SHARED_LIBRARY_NAME,$1), \ LDFLAGS_solaris := $$($1_LDFLAGS_solaris) \ - $(call SET_SHARED_LIBRARY_NAME,$(LIBRARY_PREFIX)$(SHARED_LIBRARY_SUFFIX)) \ -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)/jli, \ MAPFILE := $$($1_MAPFILE), \ LIBS := $(JDKEXE_LIBS) $$($1_LIBS), \
--- a/make/lib/Awt2dLibraries.gmk Fri Dec 18 10:00:55 2015 -0800 +++ b/make/lib/Awt2dLibraries.gmk Tue Dec 22 13:41:12 2015 -0800 @@ -683,7 +683,7 @@ WARNINGS_AS_ERRORS_gcc := false, \ WARNINGS_AS_ERRORS_solstudio := false, \ MAPFILE := $(BUILD_LIBFONTMANAGER_MAPFILE), \ - LDFLAGS := $(subst -Xlinker -z -Xlinker defs,,$(LDFLAGS_JDKLIB)) $(LDFLAGS_CXX_JDK) \ + LDFLAGS := $(subst -Wl$(COMMA)-z$(COMMA)defs,,$(LDFLAGS_JDKLIB)) $(LDFLAGS_CXX_JDK) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ LDFLAGS_macosx := -undefined dynamic_lookup, \ @@ -799,7 +799,7 @@ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ - LDFLAGS_macosx := -Xlinker -rpath -Xlinker @loader_path, \ + LDFLAGS_macosx := -Wl$(COMMA)-rpath$(COMMA)@loader_path, \ LIBS_unix := $(JAWT_LIBS) $(JDKLIB_LIBS), \ LIBS_solaris := $(X_LIBS) -lXrender, \ LIBS_macosx := -framework Cocoa, \ @@ -1034,7 +1034,7 @@ -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN) \ - -Xlinker -rpath -Xlinker @loader_path \ + -Wl$(COMMA)-rpath$(COMMA)@loader_path \ -L$(INSTALL_LIBRARIES_HERE), \ LIBS := -lawt -losxapp -lawt_lwawt \ -framework Cocoa \
--- a/make/lib/Lib-java.instrument.gmk Fri Dec 18 10:00:55 2015 -0800 +++ b/make/lib/Lib-java.instrument.gmk Tue Dec 22 13:41:12 2015 -0800 @@ -65,7 +65,7 @@ -L$(call FindLibDirForModule, java.base)/jli, \ LDFLAGS_solaris := $(call SET_SHARED_LIBRARY_ORIGIN,/jli) \ -L$(call FindLibDirForModule, java.base)/jli, \ - LDFLAGS_macosx := -Xlinker -all_load $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a, \ + LDFLAGS_macosx := -Wl$(COMMA)-all_load, \ LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \ LDFLAGS_windows := -export:Agent_OnAttach, \ LIBS := $(JDKLIB_LIBS), \ @@ -74,7 +74,8 @@ LIBS_solaris := -ljli $(LIBDL), \ LIBS_aix := -liconv -ljli_static $(LIBDL), \ LIBS_macosx := -liconv -framework Cocoa -framework Security \ - -framework ApplicationServices, \ + -framework ApplicationServices \ + $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a, \ LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib \ $(SUPPORT_OUTPUTDIR)/native/java.base/jli_static.lib, \ VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
--- a/make/lib/LibCommon.gmk Fri Dec 18 10:00:55 2015 -0800 +++ b/make/lib/LibCommon.gmk Tue Dec 22 13:41:12 2015 -0800 @@ -46,6 +46,12 @@ endif endif +# SetupNativeCompilation now supports debug symbols on macosx for hotspot. +# Disable it here for the jdk libraries until we decide to enable them. +ifeq ($(OPENJDK_TARGET_OS), macosx) + ENABLE_DEBUG_SYMBOLS := false +endif + ################################################################################ # Find the default set of src dirs for a native library. # Param 1 - module name
--- a/make/mapfiles/libzip/mapfile-vers Fri Dec 18 10:00:55 2015 -0800 +++ b/make/mapfiles/libzip/mapfile-vers Tue Dec 22 13:41:12 2015 -0800 @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ SUNWprivate_1.1 { global: - Java_java_util_jar_JarFile_getMetaInfEntryNames; Java_java_util_zip_Adler32_update; Java_java_util_zip_Adler32_updateBytes; Java_java_util_zip_Adler32_updateByteBuffer; @@ -48,25 +47,6 @@ Java_java_util_zip_Inflater_initIDs; Java_java_util_zip_Inflater_reset; Java_java_util_zip_Inflater_setDictionary; - Java_java_util_zip_ZipFile_close; - Java_java_util_zip_ZipFile_getCommentBytes; - Java_java_util_zip_ZipFile_freeEntry; - Java_java_util_zip_ZipFile_getEntry; - Java_java_util_zip_ZipFile_getEntryBytes; - Java_java_util_zip_ZipFile_getEntryCrc; - Java_java_util_zip_ZipFile_getEntryCSize; - Java_java_util_zip_ZipFile_getEntryFlag; - Java_java_util_zip_ZipFile_getEntryMethod; - Java_java_util_zip_ZipFile_getEntrySize; - Java_java_util_zip_ZipFile_getEntryTime; - Java_java_util_zip_ZipFile_getNextEntry; - Java_java_util_zip_ZipFile_getZipMessage; - Java_java_util_zip_ZipFile_getTotal; - Java_java_util_zip_ZipFile_initIDs; - Java_java_util_zip_ZipFile_open; - Java_java_util_zip_ZipFile_read; - Java_java_util_zip_ZipFile_startsWithLOC; - ZIP_Close; ZIP_CRC32; ZIP_FindEntry;
--- a/make/mapfiles/libzip/reorder-sparc Fri Dec 18 10:00:55 2015 -0800 +++ b/make/mapfiles/libzip/reorder-sparc Tue Dec 22 13:41:12 2015 -0800 @@ -16,30 +16,14 @@ text: .text%ZIP_Lock; text: .text%ZIP_Unlock; text: .text%ZIP_FreeEntry; -text: .text%Java_java_util_zip_ZipFile_initIDs; -text: .text%Java_java_util_zip_ZipFile_open; -text: .text%Java_java_util_zip_ZipFile_getTotal; -text: .text%Java_java_util_zip_ZipFile_startsWithLOC; -text: .text%Java_java_util_zip_ZipFile_getEntry; -text: .text%Java_java_util_zip_ZipFile_freeEntry; -text: .text%Java_java_util_zip_ZipFile_getEntryTime; -text: .text%Java_java_util_zip_ZipFile_getEntryCrc; -text: .text%Java_java_util_zip_ZipFile_getEntryCSize; -text: .text%Java_java_util_zip_ZipFile_getEntrySize; -text: .text%Java_java_util_zip_ZipFile_getEntryFlag; -text: .text%Java_java_util_zip_ZipFile_getEntryMethod; -text: .text%Java_java_util_zip_ZipFile_getEntryBytes; text: .text%Java_java_util_zip_Inflater_initIDs; text: .text%Java_java_util_zip_Inflater_init; text: .text%inflateInit2_; text: .text%zcalloc; text: .text%Java_java_util_zip_Inflater_inflateBytes; -text: .text%Java_java_util_zip_ZipFile_read; text: .text%ZIP_Read; text: .text%zcfree; -text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames; text: .text%Java_java_util_zip_Inflater_reset; text: .text%Java_java_util_zip_Inflater_end; text: .text%inflateEnd; -text: .text%Java_java_util_zip_ZipFile_close; text: .text%ZIP_Close;
--- a/make/mapfiles/libzip/reorder-sparcv9 Fri Dec 18 10:00:55 2015 -0800 +++ b/make/mapfiles/libzip/reorder-sparcv9 Tue Dec 22 13:41:12 2015 -0800 @@ -15,19 +15,6 @@ text: .text%ZIP_Lock; text: .text%ZIP_Unlock; text: .text%ZIP_FreeEntry; -text: .text%Java_java_util_zip_ZipFile_initIDs; -text: .text%Java_java_util_zip_ZipFile_open; -text: .text%Java_java_util_zip_ZipFile_getTotal; -text: .text%Java_java_util_zip_ZipFile_startsWithLOC; -text: .text%Java_java_util_zip_ZipFile_getEntry; -text: .text%Java_java_util_zip_ZipFile_freeEntry; -text: .text%Java_java_util_zip_ZipFile_getEntryTime; -text: .text%Java_java_util_zip_ZipFile_getEntryCrc; -text: .text%Java_java_util_zip_ZipFile_getEntryCSize; -text: .text%Java_java_util_zip_ZipFile_getEntrySize; -text: .text%Java_java_util_zip_ZipFile_getEntryFlag; -text: .text%Java_java_util_zip_ZipFile_getEntryMethod; -text: .text%Java_java_util_zip_ZipFile_getEntryBytes; text: .text%Java_java_util_zip_Inflater_initIDs; text: .text%Java_java_util_zip_Inflater_init; text: .text%inflateInit2_; @@ -35,7 +22,6 @@ text: .text%inflateReset; text: .text%Java_java_util_zip_Inflater_inflateBytes; text: .text%inflate; -text: .text%Java_java_util_zip_ZipFile_read; text: .text%ZIP_Read; text: .text%zcfree; text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames; @@ -43,6 +29,5 @@ text: .text%InflateFully; text: .text%inflateEnd; text: .text%Java_java_util_zip_Inflater_reset; -text: .text%Java_java_util_zip_ZipFile_close; text: .text%ZIP_Close; text: .text%Java_java_util_zip_Inflater_end;
--- a/make/mapfiles/libzip/reorder-x86 Fri Dec 18 10:00:55 2015 -0800 +++ b/make/mapfiles/libzip/reorder-x86 Tue Dec 22 13:41:12 2015 -0800 @@ -16,34 +16,16 @@ text: .text%ZIP_Lock; text: .text%ZIP_Unlock; text: .text%ZIP_FreeEntry; -text: .text%Java_java_util_zip_ZipFile_initIDs; -text: .text%Java_java_util_zip_ZipFile_open; -text: .text%Java_java_util_zip_ZipFile_getTotal; -text: .text%Java_java_util_zip_ZipFile_startsWithLOC; -text: .text%Java_java_util_zip_ZipFile_getEntry; -text: .text%Java_java_util_zip_ZipFile_freeEntry; -text: .text%Java_java_util_zip_ZipFile_getEntryTime; -text: .text%Java_java_util_zip_ZipFile_getEntryCrc; -text: .text%Java_java_util_zip_ZipFile_getEntryCSize; -text: .text%Java_java_util_zip_ZipFile_getEntrySize; -text: .text%Java_java_util_zip_ZipFile_getEntryFlag; -text: .text%Java_java_util_zip_ZipFile_getEntryMethod; -text: .text%Java_java_util_zip_ZipFile_getEntryBytes; -text: .text%Java_java_util_zip_Inflater_initIDs; -text: .text%Java_java_util_zip_Inflater_init; text: .text%inflateInit2_; text: .text%zcalloc; text: .text%inflateReset; text: .text%Java_java_util_zip_Inflater_inflateBytes; text: .text%inflate; -text: .text%Java_java_util_zip_ZipFile_read; text: .text%ZIP_Read; text: .text%zcfree; -text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames; text: .text%ZIP_ReadEntry; text: .text%InflateFully; text: .text%inflateEnd; text: .text%Java_java_util_zip_Inflater_reset; -text: .text%Java_java_util_zip_ZipFile_close; text: .text%ZIP_Close; text: .text%Java_java_util_zip_Inflater_end;
--- a/src/java.base/share/classes/com/sun/crypto/provider/BlockCipherParamsCore.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/com/sun/crypto/provider/BlockCipherParamsCore.java Tue Dec 22 13:41:12 2015 -0800 @@ -27,7 +27,7 @@ import java.io.*; import sun.security.util.*; -import sun.misc.HexDumpEncoder; +import sun.security.util.HexDumpEncoder; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.IvParameterSpec;
--- a/src/java.base/share/classes/com/sun/crypto/provider/GCMParameters.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/com/sun/crypto/provider/GCMParameters.java Tue Dec 22 13:41:12 2015 -0800 @@ -30,7 +30,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.GCMParameterSpec; -import sun.misc.HexDumpEncoder; +import sun.security.util.HexDumpEncoder; import sun.security.util.*; /**
--- a/src/java.base/share/classes/com/sun/crypto/provider/PBEParameters.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEParameters.java Tue Dec 22 13:41:12 2015 -0800 @@ -31,7 +31,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.PBEParameterSpec; -import sun.misc.HexDumpEncoder; +import sun.security.util.HexDumpEncoder; import sun.security.util.*;
--- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Parameters.java Tue Dec 22 13:41:12 2015 -0800 @@ -33,7 +33,7 @@ import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEParameterSpec; -import sun.misc.HexDumpEncoder; +import sun.security.util.HexDumpEncoder; import sun.security.util.*; /**
--- a/src/java.base/share/classes/com/sun/crypto/provider/RC2Parameters.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/com/sun/crypto/provider/RC2Parameters.java Tue Dec 22 13:41:12 2015 -0800 @@ -30,7 +30,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.RC2ParameterSpec; -import sun.misc.HexDumpEncoder; +import sun.security.util.HexDumpEncoder; import sun.security.util.*; /**
--- a/src/java.base/share/classes/com/sun/security/ntlm/NTLM.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/com/sun/security/ntlm/NTLM.java Tue Dec 22 13:41:12 2015 -0800 @@ -118,7 +118,7 @@ public void debug(byte[] bytes) { if (DEBUG) { try { - new sun.misc.HexDumpEncoder().encodeBuffer(bytes, System.out); + new sun.security.util.HexDumpEncoder().encodeBuffer(bytes, System.out); } catch (IOException ioe) { // Impossible }
--- a/src/java.base/share/classes/java/io/CharArrayReader.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/io/CharArrayReader.java Tue Dec 22 13:41:12 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -225,9 +225,12 @@ * Closes the stream and releases any system resources associated with * it. Once the stream has been closed, further read(), ready(), * mark(), reset(), or skip() invocations will throw an IOException. - * Closing a previously closed stream has no effect. + * Closing a previously closed stream has no effect. This method will block + * while there is another thread blocking on the reader. */ public void close() { - buf = null; + synchronized (lock) { + buf = null; + } } }
--- a/src/java.base/share/classes/java/io/PushbackReader.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/io/PushbackReader.java Tue Dec 22 13:41:12 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,13 +241,16 @@ * Closes the stream and releases any system resources associated with * it. Once the stream has been closed, further read(), * unread(), ready(), or skip() invocations will throw an IOException. - * Closing a previously closed stream has no effect. + * Closing a previously closed stream has no effect. This method will block + * while there is another thread blocking on the reader. * * @exception IOException If an I/O error occurs */ public void close() throws IOException { - super.close(); - buf = null; + synchronized (lock) { + super.close(); + buf = null; + } } /**
--- a/src/java.base/share/classes/java/io/StringReader.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/io/StringReader.java Tue Dec 22 13:41:12 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -194,9 +194,12 @@ * Closes the stream and releases any system resources associated with * it. Once the stream has been closed, further read(), * ready(), mark(), or reset() invocations will throw an IOException. - * Closing a previously closed stream has no effect. + * Closing a previously closed stream has no effect. This method will block + * while there is another thread blocking on the reader. */ public void close() { - str = null; + synchronized (lock) { + str = null; + } } }
--- a/src/java.base/share/classes/java/lang/InheritableThreadLocal.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/InheritableThreadLocal.java Tue Dec 22 13:41:12 2015 -0800 @@ -40,6 +40,11 @@ * maintained in the variable (e.g., User ID, Transaction ID) must be * automatically transmitted to any child threads that are created. * + * <p>Note: During the creation of a new {@link + * Thread#Thread(ThreadGroup,Runnable,String,long,boolean) thread}, it is + * possible to <i>opt out</i> of receiving initial values for inheritable + * thread-local variables. + * * @author Josh Bloch and Doug Lea * @see ThreadLocal * @since 1.2
--- a/src/java.base/share/classes/java/lang/StackWalker.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/StackWalker.java Tue Dec 22 13:41:12 2015 -0800 @@ -304,8 +304,8 @@ } /** - * Returns a {@code StackWalker} instance with the given {@ocde options} specifying - * the stack frame information it can access. If the given {@ocde options} + * Returns a {@code StackWalker} instance with the given {@code options} specifying + * the stack frame information it can access. If the given {@code options} * is empty, this {@code StackWalker} is configured to skip all * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} and no * {@linkplain Option#RETAIN_CLASS_REFERENCE class reference} is retained.
--- a/src/java.base/share/classes/java/lang/StringUTF16.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/StringUTF16.java Tue Dec 22 13:41:12 2015 -0800 @@ -120,7 +120,8 @@ public static byte[] toBytes(char[] value, int off, int len) { byte[] val = newBytesFor(len); for (int i = 0; i < len; i++) { - putChar(val, i, value[off++]); + putChar(val, i, value[off]); + off++; } return val; } @@ -145,11 +146,14 @@ @HotSpotIntrinsicCandidate private static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) { for (int i = 0; i < len; i++) { - int c = src[srcOff++]; - if (c >>> 8 != 0) { - return 0; + char c = src[srcOff]; + if (c > 0xFF) { + len = 0; + break; } - dst[dstOff++] = (byte)c; + dst[dstOff] = (byte)c; + srcOff++; + dstOff++; } return len; } @@ -160,11 +164,14 @@ // We need a range check here because 'getChar' has no checks checkBoundsOffCount(srcOff, len, src.length); for (int i = 0; i < len; i++) { - int c = getChar(src, srcOff++); - if (c >>> 8 != 0) { - return 0; + char c = getChar(src, srcOff); + if (c > 0xFF) { + len = 0; + break; } - dst[dstOff++] = (byte)c; + dst[dstOff] = (byte)c; + srcOff++; + dstOff++; } return len; } @@ -581,7 +588,7 @@ bits |= cp; putChar(result, i, cp); } - if (bits >>> 8 != 0) { + if (bits > 0xFF) { return new String(result, UTF16); } else { return newString(result, 0, len); @@ -678,7 +685,7 @@ bits |= cp; putChar(result, i, cp); } - if (bits >>> 8 != 0) { + if (bits > 0xFF) { return new String(result, UTF16); } else { return newString(result, 0, len);
--- a/src/java.base/share/classes/java/lang/Thread.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/Thread.java Tue Dec 22 13:41:12 2015 -0800 @@ -344,11 +344,11 @@ /** * Initializes a Thread with the current AccessControlContext. - * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext) + * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean) */ private void init(ThreadGroup g, Runnable target, String name, long stackSize) { - init(g, target, name, stackSize, null); + init(g, target, name, stackSize, null, true); } /** @@ -361,9 +361,12 @@ * zero to indicate that this parameter is to be ignored. * @param acc the AccessControlContext to inherit, or * AccessController.getContext() if null + * @param inheritThreadLocals if {@code true}, inherit initial values for + * inheritable thread-locals from the constructing thread */ private void init(ThreadGroup g, Runnable target, String name, - long stackSize, AccessControlContext acc) { + long stackSize, AccessControlContext acc, + boolean inheritThreadLocals) { if (name == null) { throw new NullPointerException("name cannot be null"); } @@ -414,7 +417,7 @@ acc != null ? acc : AccessController.getContext(); this.target = target; setPriority(priority); - if (parent.inheritableThreadLocals != null) + if (inheritThreadLocals && parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ @@ -468,7 +471,7 @@ * This is not a public constructor. */ Thread(Runnable target, AccessControlContext acc) { - init(null, target, "Thread-" + nextThreadNum(), 0, acc); + init(null, target, "Thread-" + nextThreadNum(), 0, acc, true); } /** @@ -678,6 +681,62 @@ } /** + * Allocates a new {@code Thread} object so that it has {@code target} + * as its run object, has the specified {@code name} as its name, + * belongs to the thread group referred to by {@code group}, has + * the specified {@code stackSize}, and inherits initial values for + * {@linkplain InheritableThreadLocal inheritable thread-local} variables + * if {@code inheritThreadLocals} is {@code true}. + * + * <p> This constructor is identical to {@link + * #Thread(ThreadGroup,Runnable,String,long)} with the added ability to + * suppress, or not, the inheriting of initial values for inheritable + * thread-local variables from the constructing thread. This allows for + * finer grain control over inheritable thread-locals. Care must be taken + * when passing a value of {@code false} for {@code inheritThreadLocals}, + * as it may lead to unexpected behavior if the new thread executes code + * that expects a specific thread-local value to be inherited. + * + * <p> Specifying a value of {@code true} for the {@code inheritThreadLocals} + * parameter will cause this constructor to behave exactly like the + * {@code Thread(ThreadGroup, Runnable, String, long)} constructor. + * + * @param group + * the thread group. If {@code null} and there is a security + * manager, the group is determined by {@linkplain + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}. + * If there is not a security manager or {@code + * SecurityManager.getThreadGroup()} returns {@code null}, the group + * is set to the current thread's thread group. + * + * @param target + * the object whose {@code run} method is invoked when this thread + * is started. If {@code null}, this thread's run method is invoked. + * + * @param name + * the name of the new thread + * + * @param stackSize + * the desired stack size for the new thread, or zero to indicate + * that this parameter is to be ignored + * + * @param inheritThreadLocals + * if {@code true}, inherit initial values for inheritable + * thread-locals from the constructing thread, otherwise no initial + * values are inherited + * + * @throws SecurityException + * if the current thread cannot create a thread in the specified + * thread group + * + * @since 9 + */ + public Thread(ThreadGroup group, Runnable target, String name, + long stackSize, boolean inheritThreadLocals) { + init(group, target, name, stackSize, null, inheritThreadLocals); + } + + /** * Causes this thread to begin execution; the Java Virtual Machine * calls the <code>run</code> method of this thread. * <p>
--- a/src/java.base/share/classes/java/lang/ref/Finalizer.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/ref/Finalizer.java Tue Dec 22 13:41:12 2015 -0800 @@ -29,7 +29,6 @@ import java.security.AccessController; import jdk.internal.misc.JavaLangAccess; import jdk.internal.misc.SharedSecrets; -import sun.misc.ManagedLocalsThread; import sun.misc.VM; final class Finalizer extends FinalReference<Object> { /* Package-private; must be in @@ -131,7 +130,7 @@ for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()); - Thread sft = new ManagedLocalsThread(tg, proc, "Secondary finalizer"); + Thread sft = new Thread(tg, proc, "Secondary finalizer", 0, false); sft.start(); try { sft.join(); @@ -190,10 +189,10 @@ }}}); } - private static class FinalizerThread extends ManagedLocalsThread { + private static class FinalizerThread extends Thread { private volatile boolean running; FinalizerThread(ThreadGroup g) { - super(g, "Finalizer"); + super(g, null, "Finalizer", 0, false); } public void run() { // in case of recursive call to run()
--- a/src/java.base/share/classes/java/lang/ref/Reference.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/ref/Reference.java Tue Dec 22 13:41:12 2015 -0800 @@ -30,7 +30,6 @@ import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.misc.JavaLangRefAccess; import jdk.internal.misc.SharedSecrets; -import sun.misc.ManagedLocalsThread; /** * Abstract base class for reference objects. This class defines the @@ -129,7 +128,7 @@ /* High-priority thread to enqueue pending References */ - private static class ReferenceHandler extends ManagedLocalsThread { + private static class ReferenceHandler extends Thread { private static void ensureClassInitialized(Class<?> clazz) { try { @@ -148,7 +147,7 @@ } ReferenceHandler(ThreadGroup g, String name) { - super(g, name); + super(g, null, name, 0, false); } public void run() {
--- a/src/java.base/share/classes/java/lang/reflect/AnnotatedArrayType.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/reflect/AnnotatedArrayType.java Tue Dec 22 13:41:12 2015 -0800 @@ -42,4 +42,19 @@ * @see GenericArrayType#getGenericComponentType() */ AnnotatedType getAnnotatedGenericComponentType(); + + /** + * Returns the potentially annotated type that this type is a member of, if + * this type represents a nested type. For example, if this type is + * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}. + * + * <p>Returns {@code null} for an {@code AnnotatedType} that is an instance + * of {@code AnnotatedArrayType}. + * + * @return {@code null} + * + * @since 1.9 + */ + @Override + AnnotatedType getAnnotatedOwnerType(); }
--- a/src/java.base/share/classes/java/lang/reflect/AnnotatedParameterizedType.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/reflect/AnnotatedParameterizedType.java Tue Dec 22 13:41:12 2015 -0800 @@ -41,4 +41,26 @@ * @see ParameterizedType#getActualTypeArguments() */ AnnotatedType[] getAnnotatedActualTypeArguments(); + + /** + * Returns the potentially annotated type that this type is a member of, if + * this type represents a nested type. For example, if this type is + * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}. + * + * <p>Returns {@code null} if this {@code AnnotatedType} represents a + * top-level type, or a local or anonymous class, or a primitive type, or + * void. + * + * @return an {@code AnnotatedType} object representing the potentially + * annotated type that this type is a member of, or {@code null} + * @throws TypeNotPresentException if the owner type + * refers to a non-existent type declaration + * @throws MalformedParameterizedTypeException if the owner type + * refers to a parameterized type that cannot be instantiated + * for any reason + * + * @since 1.9 + */ + @Override + AnnotatedType getAnnotatedOwnerType(); }
--- a/src/java.base/share/classes/java/lang/reflect/AnnotatedType.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/reflect/AnnotatedType.java Tue Dec 22 13:41:12 2015 -0800 @@ -36,6 +36,37 @@ public interface AnnotatedType extends AnnotatedElement { /** + * Returns the potentially annotated type that this type is a member of, if + * this type represents a nested type. For example, if this type is + * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}. + * + * <p>Returns {@code null} if this {@code AnnotatedType} represents a + * top-level type, or a local or anonymous class, or a primitive type, or + * void. + * + * <p>Returns {@code null} if this {@code AnnotatedType} is an instance of + * {@code AnnotatedArrayType}, {@code AnnotatedTypeVariable}, or + * {@code AnnotatedWildcardType}. + * + * @implSpec + * This default implementation returns {@code null} and performs no other + * action. + * + * @return an {@code AnnotatedType} object representing the potentially + * annotated type that this type is a member of, or {@code null} + * @throws TypeNotPresentException if the owner type + * refers to a non-existent type declaration + * @throws MalformedParameterizedTypeException if the owner type + * refers to a parameterized type that cannot be instantiated + * for any reason + * + * @since 1.9 + */ + default AnnotatedType getAnnotatedOwnerType() { + return null; + } + + /** * Returns the underlying type that this annotated type represents. * * @return the type this annotated type represents
--- a/src/java.base/share/classes/java/lang/reflect/AnnotatedTypeVariable.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/reflect/AnnotatedTypeVariable.java Tue Dec 22 13:41:12 2015 -0800 @@ -43,4 +43,19 @@ * @see TypeVariable#getBounds() */ AnnotatedType[] getAnnotatedBounds(); + + /** + * Returns the potentially annotated type that this type is a member of, if + * this type represents a nested type. For example, if this type is + * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}. + * + * <p>Returns {@code null} for an {@code AnnotatedType} that is an instance + * of {@code AnnotatedTypeVariable}. + * + * @return {@code null} + * + * @since 1.9 + */ + @Override + AnnotatedType getAnnotatedOwnerType(); }
--- a/src/java.base/share/classes/java/lang/reflect/AnnotatedWildcardType.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/reflect/AnnotatedWildcardType.java Tue Dec 22 13:41:12 2015 -0800 @@ -54,4 +54,19 @@ * @see WildcardType#getUpperBounds() */ AnnotatedType[] getAnnotatedUpperBounds(); + + /** + * Returns the potentially annotated type that this type is a member of, if + * this type represents a nested type. For example, if this type is + * {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}. + * + * <p>Returns {@code null} for an {@code AnnotatedType} that is an instance + * of {@code AnnotatedWildcardType}. + * + * @return {@code null} + * + * @since 1.9 + */ + @Override + AnnotatedType getAnnotatedOwnerType(); }
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java Tue Dec 22 13:41:12 2015 -0800 @@ -34,7 +34,6 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiFunction; -import sun.misc.ProxyGenerator; import sun.misc.VM; import sun.reflect.CallerSensitive; import sun.reflect.Reflection;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java Tue Dec 22 13:41:12 2015 -0800 @@ -0,0 +1,2031 @@ +/* + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.reflect; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import sun.security.action.GetBooleanAction; + +/** + * ProxyGenerator contains the code to generate a dynamic proxy class + * for the java.lang.reflect.Proxy API. + * + * The external interfaces to ProxyGenerator is the static + * "generateProxyClass" method. + * + * @author Peter Jones + * @since 1.3 + */ +class ProxyGenerator { + /* + * In the comments below, "JVMS" refers to The Java Virtual Machine + * Specification Second Edition and "JLS" refers to the original + * version of The Java Language Specification, unless otherwise + * specified. + */ + + /* generate 1.5-era class file version */ + private static final int CLASSFILE_MAJOR_VERSION = 49; + private static final int CLASSFILE_MINOR_VERSION = 0; + + /* + * beginning of constants copied from + * sun.tools.java.RuntimeConstants (which no longer exists): + */ + + /* constant pool tags */ + private static final int CONSTANT_UTF8 = 1; + private static final int CONSTANT_UNICODE = 2; + private static final int CONSTANT_INTEGER = 3; + private static final int CONSTANT_FLOAT = 4; + private static final int CONSTANT_LONG = 5; + private static final int CONSTANT_DOUBLE = 6; + private static final int CONSTANT_CLASS = 7; + private static final int CONSTANT_STRING = 8; + private static final int CONSTANT_FIELD = 9; + private static final int CONSTANT_METHOD = 10; + private static final int CONSTANT_INTERFACEMETHOD = 11; + private static final int CONSTANT_NAMEANDTYPE = 12; + + /* access and modifier flags */ + private static final int ACC_PUBLIC = 0x00000001; + private static final int ACC_PRIVATE = 0x00000002; +// private static final int ACC_PROTECTED = 0x00000004; + private static final int ACC_STATIC = 0x00000008; + private static final int ACC_FINAL = 0x00000010; +// private static final int ACC_SYNCHRONIZED = 0x00000020; +// private static final int ACC_VOLATILE = 0x00000040; +// private static final int ACC_TRANSIENT = 0x00000080; +// private static final int ACC_NATIVE = 0x00000100; +// private static final int ACC_INTERFACE = 0x00000200; +// private static final int ACC_ABSTRACT = 0x00000400; + private static final int ACC_SUPER = 0x00000020; +// private static final int ACC_STRICT = 0x00000800; + + /* opcodes */ +// private static final int opc_nop = 0; + private static final int opc_aconst_null = 1; +// private static final int opc_iconst_m1 = 2; + private static final int opc_iconst_0 = 3; +// private static final int opc_iconst_1 = 4; +// private static final int opc_iconst_2 = 5; +// private static final int opc_iconst_3 = 6; +// private static final int opc_iconst_4 = 7; +// private static final int opc_iconst_5 = 8; +// private static final int opc_lconst_0 = 9; +// private static final int opc_lconst_1 = 10; +// private static final int opc_fconst_0 = 11; +// private static final int opc_fconst_1 = 12; +// private static final int opc_fconst_2 = 13; +// private static final int opc_dconst_0 = 14; +// private static final int opc_dconst_1 = 15; + private static final int opc_bipush = 16; + private static final int opc_sipush = 17; + private static final int opc_ldc = 18; + private static final int opc_ldc_w = 19; +// private static final int opc_ldc2_w = 20; + private static final int opc_iload = 21; + private static final int opc_lload = 22; + private static final int opc_fload = 23; + private static final int opc_dload = 24; + private static final int opc_aload = 25; + private static final int opc_iload_0 = 26; +// private static final int opc_iload_1 = 27; +// private static final int opc_iload_2 = 28; +// private static final int opc_iload_3 = 29; + private static final int opc_lload_0 = 30; +// private static final int opc_lload_1 = 31; +// private static final int opc_lload_2 = 32; +// private static final int opc_lload_3 = 33; + private static final int opc_fload_0 = 34; +// private static final int opc_fload_1 = 35; +// private static final int opc_fload_2 = 36; +// private static final int opc_fload_3 = 37; + private static final int opc_dload_0 = 38; +// private static final int opc_dload_1 = 39; +// private static final int opc_dload_2 = 40; +// private static final int opc_dload_3 = 41; + private static final int opc_aload_0 = 42; +// private static final int opc_aload_1 = 43; +// private static final int opc_aload_2 = 44; +// private static final int opc_aload_3 = 45; +// private static final int opc_iaload = 46; +// private static final int opc_laload = 47; +// private static final int opc_faload = 48; +// private static final int opc_daload = 49; +// private static final int opc_aaload = 50; +// private static final int opc_baload = 51; +// private static final int opc_caload = 52; +// private static final int opc_saload = 53; +// private static final int opc_istore = 54; +// private static final int opc_lstore = 55; +// private static final int opc_fstore = 56; +// private static final int opc_dstore = 57; + private static final int opc_astore = 58; +// private static final int opc_istore_0 = 59; +// private static final int opc_istore_1 = 60; +// private static final int opc_istore_2 = 61; +// private static final int opc_istore_3 = 62; +// private static final int opc_lstore_0 = 63; +// private static final int opc_lstore_1 = 64; +// private static final int opc_lstore_2 = 65; +// private static final int opc_lstore_3 = 66; +// private static final int opc_fstore_0 = 67; +// private static final int opc_fstore_1 = 68; +// private static final int opc_fstore_2 = 69; +// private static final int opc_fstore_3 = 70; +// private static final int opc_dstore_0 = 71; +// private static final int opc_dstore_1 = 72; +// private static final int opc_dstore_2 = 73; +// private static final int opc_dstore_3 = 74; + private static final int opc_astore_0 = 75; +// private static final int opc_astore_1 = 76; +// private static final int opc_astore_2 = 77; +// private static final int opc_astore_3 = 78; +// private static final int opc_iastore = 79; +// private static final int opc_lastore = 80; +// private static final int opc_fastore = 81; +// private static final int opc_dastore = 82; + private static final int opc_aastore = 83; +// private static final int opc_bastore = 84; +// private static final int opc_castore = 85; +// private static final int opc_sastore = 86; + private static final int opc_pop = 87; +// private static final int opc_pop2 = 88; + private static final int opc_dup = 89; +// private static final int opc_dup_x1 = 90; +// private static final int opc_dup_x2 = 91; +// private static final int opc_dup2 = 92; +// private static final int opc_dup2_x1 = 93; +// private static final int opc_dup2_x2 = 94; +// private static final int opc_swap = 95; +// private static final int opc_iadd = 96; +// private static final int opc_ladd = 97; +// private static final int opc_fadd = 98; +// private static final int opc_dadd = 99; +// private static final int opc_isub = 100; +// private static final int opc_lsub = 101; +// private static final int opc_fsub = 102; +// private static final int opc_dsub = 103; +// private static final int opc_imul = 104; +// private static final int opc_lmul = 105; +// private static final int opc_fmul = 106; +// private static final int opc_dmul = 107; +// private static final int opc_idiv = 108; +// private static final int opc_ldiv = 109; +// private static final int opc_fdiv = 110; +// private static final int opc_ddiv = 111; +// private static final int opc_irem = 112; +// private static final int opc_lrem = 113; +// private static final int opc_frem = 114; +// private static final int opc_drem = 115; +// private static final int opc_ineg = 116; +// private static final int opc_lneg = 117; +// private static final int opc_fneg = 118; +// private static final int opc_dneg = 119; +// private static final int opc_ishl = 120; +// private static final int opc_lshl = 121; +// private static final int opc_ishr = 122; +// private static final int opc_lshr = 123; +// private static final int opc_iushr = 124; +// private static final int opc_lushr = 125; +// private static final int opc_iand = 126; +// private static final int opc_land = 127; +// private static final int opc_ior = 128; +// private static final int opc_lor = 129; +// private static final int opc_ixor = 130; +// private static final int opc_lxor = 131; +// private static final int opc_iinc = 132; +// private static final int opc_i2l = 133; +// private static final int opc_i2f = 134; +// private static final int opc_i2d = 135; +// private static final int opc_l2i = 136; +// private static final int opc_l2f = 137; +// private static final int opc_l2d = 138; +// private static final int opc_f2i = 139; +// private static final int opc_f2l = 140; +// private static final int opc_f2d = 141; +// private static final int opc_d2i = 142; +// private static final int opc_d2l = 143; +// private static final int opc_d2f = 144; +// private static final int opc_i2b = 145; +// private static final int opc_i2c = 146; +// private static final int opc_i2s = 147; +// private static final int opc_lcmp = 148; +// private static final int opc_fcmpl = 149; +// private static final int opc_fcmpg = 150; +// private static final int opc_dcmpl = 151; +// private static final int opc_dcmpg = 152; +// private static final int opc_ifeq = 153; +// private static final int opc_ifne = 154; +// private static final int opc_iflt = 155; +// private static final int opc_ifge = 156; +// private static final int opc_ifgt = 157; +// private static final int opc_ifle = 158; +// private static final int opc_if_icmpeq = 159; +// private static final int opc_if_icmpne = 160; +// private static final int opc_if_icmplt = 161; +// private static final int opc_if_icmpge = 162; +// private static final int opc_if_icmpgt = 163; +// private static final int opc_if_icmple = 164; +// private static final int opc_if_acmpeq = 165; +// private static final int opc_if_acmpne = 166; +// private static final int opc_goto = 167; +// private static final int opc_jsr = 168; +// private static final int opc_ret = 169; +// private static final int opc_tableswitch = 170; +// private static final int opc_lookupswitch = 171; + private static final int opc_ireturn = 172; + private static final int opc_lreturn = 173; + private static final int opc_freturn = 174; + private static final int opc_dreturn = 175; + private static final int opc_areturn = 176; + private static final int opc_return = 177; + private static final int opc_getstatic = 178; + private static final int opc_putstatic = 179; + private static final int opc_getfield = 180; +// private static final int opc_putfield = 181; + private static final int opc_invokevirtual = 182; + private static final int opc_invokespecial = 183; + private static final int opc_invokestatic = 184; + private static final int opc_invokeinterface = 185; + private static final int opc_new = 187; +// private static final int opc_newarray = 188; + private static final int opc_anewarray = 189; +// private static final int opc_arraylength = 190; + private static final int opc_athrow = 191; + private static final int opc_checkcast = 192; +// private static final int opc_instanceof = 193; +// private static final int opc_monitorenter = 194; +// private static final int opc_monitorexit = 195; + private static final int opc_wide = 196; +// private static final int opc_multianewarray = 197; +// private static final int opc_ifnull = 198; +// private static final int opc_ifnonnull = 199; +// private static final int opc_goto_w = 200; +// private static final int opc_jsr_w = 201; + + // end of constants copied from sun.tools.java.RuntimeConstants + + /** name of the superclass of proxy classes */ + private static final String superclassName = "java/lang/reflect/Proxy"; + + /** name of field for storing a proxy instance's invocation handler */ + private static final String handlerFieldName = "h"; + + /** debugging flag for saving generated class files */ + private static final boolean saveGeneratedFiles = + java.security.AccessController.doPrivileged( + new GetBooleanAction( + "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue(); + + /** + * Generate a public proxy class given a name and a list of proxy interfaces. + */ + static byte[] generateProxyClass(final String name, + Class<?>[] interfaces) { + return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER)); + } + + /** + * Generate a proxy class given a name and a list of proxy interfaces. + * + * @param name the class name of the proxy class + * @param interfaces proxy interfaces + * @param accessFlags access flags of the proxy class + */ + static byte[] generateProxyClass(final String name, + Class<?>[] interfaces, + int accessFlags) + { + ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags); + final byte[] classFile = gen.generateClassFile(); + + if (saveGeneratedFiles) { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction<Void>() { + public Void run() { + try { + int i = name.lastIndexOf('.'); + Path path; + if (i > 0) { + Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar)); + Files.createDirectories(dir); + path = dir.resolve(name.substring(i+1, name.length()) + ".class"); + } else { + path = Paths.get(name + ".class"); + } + Files.write(path, classFile); + return null; + } catch (IOException e) { + throw new InternalError( + "I/O exception saving generated file: " + e); + } + } + }); + } + + return classFile; + } + + /* preloaded Method objects for methods in java.lang.Object */ + private static Method hashCodeMethod; + private static Method equalsMethod; + private static Method toStringMethod; + static { + try { + hashCodeMethod = Object.class.getMethod("hashCode"); + equalsMethod = + Object.class.getMethod("equals", new Class<?>[] { Object.class }); + toStringMethod = Object.class.getMethod("toString"); + } catch (NoSuchMethodException e) { + throw new NoSuchMethodError(e.getMessage()); + } + } + + /** name of proxy class */ + private String className; + + /** proxy interfaces */ + private Class<?>[] interfaces; + + /** proxy class access flags */ + private int accessFlags; + + /** constant pool of class being generated */ + private ConstantPool cp = new ConstantPool(); + + /** FieldInfo struct for each field of generated class */ + private List<FieldInfo> fields = new ArrayList<>(); + + /** MethodInfo struct for each method of generated class */ + private List<MethodInfo> methods = new ArrayList<>(); + + /** + * maps method signature string to list of ProxyMethod objects for + * proxy methods with that signature + */ + private Map<String, List<ProxyMethod>> proxyMethods = new HashMap<>(); + + /** count of ProxyMethod objects added to proxyMethods */ + private int proxyMethodCount = 0; + + /** + * Construct a ProxyGenerator to generate a proxy class with the + * specified name and for the given interfaces. + * + * A ProxyGenerator object contains the state for the ongoing + * generation of a particular proxy class. + */ + private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) { + this.className = className; + this.interfaces = interfaces; + this.accessFlags = accessFlags; + } + + /** + * Generate a class file for the proxy class. This method drives the + * class file generation process. + */ + private byte[] generateClassFile() { + + /* ============================================================ + * Step 1: Assemble ProxyMethod objects for all methods to + * generate proxy dispatching code for. + */ + + /* + * Record that proxy methods are needed for the hashCode, equals, + * and toString methods of java.lang.Object. This is done before + * the methods from the proxy interfaces so that the methods from + * java.lang.Object take precedence over duplicate methods in the + * proxy interfaces. + */ + addProxyMethod(hashCodeMethod, Object.class); + addProxyMethod(equalsMethod, Object.class); + addProxyMethod(toStringMethod, Object.class); + + /* + * Now record all of the methods from the proxy interfaces, giving + * earlier interfaces precedence over later ones with duplicate + * methods. + */ + for (Class<?> intf : interfaces) { + for (Method m : intf.getMethods()) { + addProxyMethod(m, intf); + } + } + + /* + * For each set of proxy methods with the same signature, + * verify that the methods' return types are compatible. + */ + for (List<ProxyMethod> sigmethods : proxyMethods.values()) { + checkReturnTypes(sigmethods); + } + + /* ============================================================ + * Step 2: Assemble FieldInfo and MethodInfo structs for all of + * fields and methods in the class we are generating. + */ + try { + methods.add(generateConstructor()); + + for (List<ProxyMethod> sigmethods : proxyMethods.values()) { + for (ProxyMethod pm : sigmethods) { + + // add static field for method's Method object + fields.add(new FieldInfo(pm.methodFieldName, + "Ljava/lang/reflect/Method;", + ACC_PRIVATE | ACC_STATIC)); + + // generate code for proxy method and add it + methods.add(pm.generateMethod()); + } + } + + methods.add(generateStaticInitializer()); + + } catch (IOException e) { + throw new InternalError("unexpected I/O Exception", e); + } + + if (methods.size() > 65535) { + throw new IllegalArgumentException("method limit exceeded"); + } + if (fields.size() > 65535) { + throw new IllegalArgumentException("field limit exceeded"); + } + + /* ============================================================ + * Step 3: Write the final class file. + */ + + /* + * Make sure that constant pool indexes are reserved for the + * following items before starting to write the final class file. + */ + cp.getClass(dotToSlash(className)); + cp.getClass(superclassName); + for (Class<?> intf: interfaces) { + cp.getClass(dotToSlash(intf.getName())); + } + + /* + * Disallow new constant pool additions beyond this point, since + * we are about to write the final constant pool table. + */ + cp.setReadOnly(); + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + DataOutputStream dout = new DataOutputStream(bout); + + try { + /* + * Write all the items of the "ClassFile" structure. + * See JVMS section 4.1. + */ + // u4 magic; + dout.writeInt(0xCAFEBABE); + // u2 minor_version; + dout.writeShort(CLASSFILE_MINOR_VERSION); + // u2 major_version; + dout.writeShort(CLASSFILE_MAJOR_VERSION); + + cp.write(dout); // (write constant pool) + + // u2 access_flags; + dout.writeShort(accessFlags); + // u2 this_class; + dout.writeShort(cp.getClass(dotToSlash(className))); + // u2 super_class; + dout.writeShort(cp.getClass(superclassName)); + + // u2 interfaces_count; + dout.writeShort(interfaces.length); + // u2 interfaces[interfaces_count]; + for (Class<?> intf : interfaces) { + dout.writeShort(cp.getClass( + dotToSlash(intf.getName()))); + } + + // u2 fields_count; + dout.writeShort(fields.size()); + // field_info fields[fields_count]; + for (FieldInfo f : fields) { + f.write(dout); + } + + // u2 methods_count; + dout.writeShort(methods.size()); + // method_info methods[methods_count]; + for (MethodInfo m : methods) { + m.write(dout); + } + + // u2 attributes_count; + dout.writeShort(0); // (no ClassFile attributes for proxy classes) + + } catch (IOException e) { + throw new InternalError("unexpected I/O Exception", e); + } + + return bout.toByteArray(); + } + + /** + * Add another method to be proxied, either by creating a new + * ProxyMethod object or augmenting an old one for a duplicate + * method. + * + * "fromClass" indicates the proxy interface that the method was + * found through, which may be different from (a subinterface of) + * the method's "declaring class". Note that the first Method + * object passed for a given name and descriptor identifies the + * Method object (and thus the declaring class) that will be + * passed to the invocation handler's "invoke" method for a given + * set of duplicate methods. + */ + private void addProxyMethod(Method m, Class<?> fromClass) { + String name = m.getName(); + Class<?>[] parameterTypes = m.getParameterTypes(); + Class<?> returnType = m.getReturnType(); + Class<?>[] exceptionTypes = m.getExceptionTypes(); + + String sig = name + getParameterDescriptors(parameterTypes); + List<ProxyMethod> sigmethods = proxyMethods.get(sig); + if (sigmethods != null) { + for (ProxyMethod pm : sigmethods) { + if (returnType == pm.returnType) { + /* + * Found a match: reduce exception types to the + * greatest set of exceptions that can thrown + * compatibly with the throws clauses of both + * overridden methods. + */ + List<Class<?>> legalExceptions = new ArrayList<>(); + collectCompatibleTypes( + exceptionTypes, pm.exceptionTypes, legalExceptions); + collectCompatibleTypes( + pm.exceptionTypes, exceptionTypes, legalExceptions); + pm.exceptionTypes = new Class<?>[legalExceptions.size()]; + pm.exceptionTypes = + legalExceptions.toArray(pm.exceptionTypes); + return; + } + } + } else { + sigmethods = new ArrayList<>(3); + proxyMethods.put(sig, sigmethods); + } + sigmethods.add(new ProxyMethod(name, parameterTypes, returnType, + exceptionTypes, fromClass)); + } + + /** + * For a given set of proxy methods with the same signature, check + * that their return types are compatible according to the Proxy + * specification. + * + * Specifically, if there is more than one such method, then all + * of the return types must be reference types, and there must be + * one return type that is assignable to each of the rest of them. + */ + private static void checkReturnTypes(List<ProxyMethod> methods) { + /* + * If there is only one method with a given signature, there + * cannot be a conflict. This is the only case in which a + * primitive (or void) return type is allowed. + */ + if (methods.size() < 2) { + return; + } + + /* + * List of return types that are not yet known to be + * assignable from ("covered" by) any of the others. + */ + LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>(); + + nextNewReturnType: + for (ProxyMethod pm : methods) { + Class<?> newReturnType = pm.returnType; + if (newReturnType.isPrimitive()) { + throw new IllegalArgumentException( + "methods with same signature " + + getFriendlyMethodSignature(pm.methodName, + pm.parameterTypes) + + " but incompatible return types: " + + newReturnType.getName() + " and others"); + } + boolean added = false; + + /* + * Compare the new return type to the existing uncovered + * return types. + */ + ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator(); + while (liter.hasNext()) { + Class<?> uncoveredReturnType = liter.next(); + + /* + * If an existing uncovered return type is assignable + * to this new one, then we can forget the new one. + */ + if (newReturnType.isAssignableFrom(uncoveredReturnType)) { + assert !added; + continue nextNewReturnType; + } + + /* + * If the new return type is assignable to an existing + * uncovered one, then should replace the existing one + * with the new one (or just forget the existing one, + * if the new one has already be put in the list). + */ + if (uncoveredReturnType.isAssignableFrom(newReturnType)) { + // (we can assume that each return type is unique) + if (!added) { + liter.set(newReturnType); + added = true; + } else { + liter.remove(); + } + } + } + + /* + * If we got through the list of existing uncovered return + * types without an assignability relationship, then add + * the new return type to the list of uncovered ones. + */ + if (!added) { + uncoveredReturnTypes.add(newReturnType); + } + } + + /* + * We shouldn't end up with more than one return type that is + * not assignable from any of the others. + */ + if (uncoveredReturnTypes.size() > 1) { + ProxyMethod pm = methods.get(0); + throw new IllegalArgumentException( + "methods with same signature " + + getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) + + " but incompatible return types: " + uncoveredReturnTypes); + } + } + + /** + * A FieldInfo object contains information about a particular field + * in the class being generated. The class mirrors the data items of + * the "field_info" structure of the class file format (see JVMS 4.5). + */ + private class FieldInfo { + public int accessFlags; + public String name; + public String descriptor; + + public FieldInfo(String name, String descriptor, int accessFlags) { + this.name = name; + this.descriptor = descriptor; + this.accessFlags = accessFlags; + + /* + * Make sure that constant pool indexes are reserved for the + * following items before starting to write the final class file. + */ + cp.getUtf8(name); + cp.getUtf8(descriptor); + } + + public void write(DataOutputStream out) throws IOException { + /* + * Write all the items of the "field_info" structure. + * See JVMS section 4.5. + */ + // u2 access_flags; + out.writeShort(accessFlags); + // u2 name_index; + out.writeShort(cp.getUtf8(name)); + // u2 descriptor_index; + out.writeShort(cp.getUtf8(descriptor)); + // u2 attributes_count; + out.writeShort(0); // (no field_info attributes for proxy classes) + } + } + + /** + * An ExceptionTableEntry object holds values for the data items of + * an entry in the "exception_table" item of the "Code" attribute of + * "method_info" structures (see JVMS 4.7.3). + */ + private static class ExceptionTableEntry { + public short startPc; + public short endPc; + public short handlerPc; + public short catchType; + + public ExceptionTableEntry(short startPc, short endPc, + short handlerPc, short catchType) + { + this.startPc = startPc; + this.endPc = endPc; + this.handlerPc = handlerPc; + this.catchType = catchType; + } + }; + + /** + * A MethodInfo object contains information about a particular method + * in the class being generated. This class mirrors the data items of + * the "method_info" structure of the class file format (see JVMS 4.6). + */ + private class MethodInfo { + public int accessFlags; + public String name; + public String descriptor; + public short maxStack; + public short maxLocals; + public ByteArrayOutputStream code = new ByteArrayOutputStream(); + public List<ExceptionTableEntry> exceptionTable = + new ArrayList<ExceptionTableEntry>(); + public short[] declaredExceptions; + + public MethodInfo(String name, String descriptor, int accessFlags) { + this.name = name; + this.descriptor = descriptor; + this.accessFlags = accessFlags; + + /* + * Make sure that constant pool indexes are reserved for the + * following items before starting to write the final class file. + */ + cp.getUtf8(name); + cp.getUtf8(descriptor); + cp.getUtf8("Code"); + cp.getUtf8("Exceptions"); + } + + public void write(DataOutputStream out) throws IOException { + /* + * Write all the items of the "method_info" structure. + * See JVMS section 4.6. + */ + // u2 access_flags; + out.writeShort(accessFlags); + // u2 name_index; + out.writeShort(cp.getUtf8(name)); + // u2 descriptor_index; + out.writeShort(cp.getUtf8(descriptor)); + // u2 attributes_count; + out.writeShort(2); // (two method_info attributes:) + + // Write "Code" attribute. See JVMS section 4.7.3. + + // u2 attribute_name_index; + out.writeShort(cp.getUtf8("Code")); + // u4 attribute_length; + out.writeInt(12 + code.size() + 8 * exceptionTable.size()); + // u2 max_stack; + out.writeShort(maxStack); + // u2 max_locals; + out.writeShort(maxLocals); + // u2 code_length; + out.writeInt(code.size()); + // u1 code[code_length]; + code.writeTo(out); + // u2 exception_table_length; + out.writeShort(exceptionTable.size()); + for (ExceptionTableEntry e : exceptionTable) { + // u2 start_pc; + out.writeShort(e.startPc); + // u2 end_pc; + out.writeShort(e.endPc); + // u2 handler_pc; + out.writeShort(e.handlerPc); + // u2 catch_type; + out.writeShort(e.catchType); + } + // u2 attributes_count; + out.writeShort(0); + + // write "Exceptions" attribute. See JVMS section 4.7.4. + + // u2 attribute_name_index; + out.writeShort(cp.getUtf8("Exceptions")); + // u4 attributes_length; + out.writeInt(2 + 2 * declaredExceptions.length); + // u2 number_of_exceptions; + out.writeShort(declaredExceptions.length); + // u2 exception_index_table[number_of_exceptions]; + for (short value : declaredExceptions) { + out.writeShort(value); + } + } + + } + + /** + * A ProxyMethod object represents a proxy method in the proxy class + * being generated: a method whose implementation will encode and + * dispatch invocations to the proxy instance's invocation handler. + */ + private class ProxyMethod { + + public String methodName; + public Class<?>[] parameterTypes; + public Class<?> returnType; + public Class<?>[] exceptionTypes; + public Class<?> fromClass; + public String methodFieldName; + + private ProxyMethod(String methodName, Class<?>[] parameterTypes, + Class<?> returnType, Class<?>[] exceptionTypes, + Class<?> fromClass) + { + this.methodName = methodName; + this.parameterTypes = parameterTypes; + this.returnType = returnType; + this.exceptionTypes = exceptionTypes; + this.fromClass = fromClass; + this.methodFieldName = "m" + proxyMethodCount++; + } + + /** + * Return a MethodInfo object for this method, including generating + * the code and exception table entry. + */ + private MethodInfo generateMethod() throws IOException { + String desc = getMethodDescriptor(parameterTypes, returnType); + MethodInfo minfo = new MethodInfo(methodName, desc, + ACC_PUBLIC | ACC_FINAL); + + int[] parameterSlot = new int[parameterTypes.length]; + int nextSlot = 1; + for (int i = 0; i < parameterSlot.length; i++) { + parameterSlot[i] = nextSlot; + nextSlot += getWordsPerType(parameterTypes[i]); + } + int localSlot0 = nextSlot; + short pc, tryBegin = 0, tryEnd; + + DataOutputStream out = new DataOutputStream(minfo.code); + + code_aload(0, out); + + out.writeByte(opc_getfield); + out.writeShort(cp.getFieldRef( + superclassName, + handlerFieldName, "Ljava/lang/reflect/InvocationHandler;")); + + code_aload(0, out); + + out.writeByte(opc_getstatic); + out.writeShort(cp.getFieldRef( + dotToSlash(className), + methodFieldName, "Ljava/lang/reflect/Method;")); + + if (parameterTypes.length > 0) { + + code_ipush(parameterTypes.length, out); + + out.writeByte(opc_anewarray); + out.writeShort(cp.getClass("java/lang/Object")); + + for (int i = 0; i < parameterTypes.length; i++) { + + out.writeByte(opc_dup); + + code_ipush(i, out); + + codeWrapArgument(parameterTypes[i], parameterSlot[i], out); + + out.writeByte(opc_aastore); + } + } else { + + out.writeByte(opc_aconst_null); + } + + out.writeByte(opc_invokeinterface); + out.writeShort(cp.getInterfaceMethodRef( + "java/lang/reflect/InvocationHandler", + "invoke", + "(Ljava/lang/Object;Ljava/lang/reflect/Method;" + + "[Ljava/lang/Object;)Ljava/lang/Object;")); + out.writeByte(4); + out.writeByte(0); + + if (returnType == void.class) { + + out.writeByte(opc_pop); + + out.writeByte(opc_return); + + } else { + + codeUnwrapReturnValue(returnType, out); + } + + tryEnd = pc = (short) minfo.code.size(); + + List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes); + if (catchList.size() > 0) { + + for (Class<?> ex : catchList) { + minfo.exceptionTable.add(new ExceptionTableEntry( + tryBegin, tryEnd, pc, + cp.getClass(dotToSlash(ex.getName())))); + } + + out.writeByte(opc_athrow); + + pc = (short) minfo.code.size(); + + minfo.exceptionTable.add(new ExceptionTableEntry( + tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable"))); + + code_astore(localSlot0, out); + + out.writeByte(opc_new); + out.writeShort(cp.getClass( + "java/lang/reflect/UndeclaredThrowableException")); + + out.writeByte(opc_dup); + + code_aload(localSlot0, out); + + out.writeByte(opc_invokespecial); + + out.writeShort(cp.getMethodRef( + "java/lang/reflect/UndeclaredThrowableException", + "<init>", "(Ljava/lang/Throwable;)V")); + + out.writeByte(opc_athrow); + } + + if (minfo.code.size() > 65535) { + throw new IllegalArgumentException("code size limit exceeded"); + } + + minfo.maxStack = 10; + minfo.maxLocals = (short) (localSlot0 + 1); + minfo.declaredExceptions = new short[exceptionTypes.length]; + for (int i = 0; i < exceptionTypes.length; i++) { + minfo.declaredExceptions[i] = cp.getClass( + dotToSlash(exceptionTypes[i].getName())); + } + + return minfo; + } + + /** + * Generate code for wrapping an argument of the given type + * whose value can be found at the specified local variable + * index, in order for it to be passed (as an Object) to the + * invocation handler's "invoke" method. The code is written + * to the supplied stream. + */ + private void codeWrapArgument(Class<?> type, int slot, + DataOutputStream out) + throws IOException + { + if (type.isPrimitive()) { + PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type); + + if (type == int.class || + type == boolean.class || + type == byte.class || + type == char.class || + type == short.class) + { + code_iload(slot, out); + } else if (type == long.class) { + code_lload(slot, out); + } else if (type == float.class) { + code_fload(slot, out); + } else if (type == double.class) { + code_dload(slot, out); + } else { + throw new AssertionError(); + } + + out.writeByte(opc_invokestatic); + out.writeShort(cp.getMethodRef( + prim.wrapperClassName, + "valueOf", prim.wrapperValueOfDesc)); + + } else { + + code_aload(slot, out); + } + } + + /** + * Generate code for unwrapping a return value of the given + * type from the invocation handler's "invoke" method (as type + * Object) to its correct type. The code is written to the + * supplied stream. + */ + private void codeUnwrapReturnValue(Class<?> type, DataOutputStream out) + throws IOException + { + if (type.isPrimitive()) { + PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type); + + out.writeByte(opc_checkcast); + out.writeShort(cp.getClass(prim.wrapperClassName)); + + out.writeByte(opc_invokevirtual); + out.writeShort(cp.getMethodRef( + prim.wrapperClassName, + prim.unwrapMethodName, prim.unwrapMethodDesc)); + + if (type == int.class || + type == boolean.class || + type == byte.class || + type == char.class || + type == short.class) + { + out.writeByte(opc_ireturn); + } else if (type == long.class) { + out.writeByte(opc_lreturn); + } else if (type == float.class) { + out.writeByte(opc_freturn); + } else if (type == double.class) { + out.writeByte(opc_dreturn); + } else { + throw new AssertionError(); + } + + } else { + + out.writeByte(opc_checkcast); + out.writeShort(cp.getClass(dotToSlash(type.getName()))); + + out.writeByte(opc_areturn); + } + } + + /** + * Generate code for initializing the static field that stores + * the Method object for this proxy method. The code is written + * to the supplied stream. + */ + private void codeFieldInitialization(DataOutputStream out) + throws IOException + { + codeClassForName(fromClass, out); + + code_ldc(cp.getString(methodName), out); + + code_ipush(parameterTypes.length, out); + + out.writeByte(opc_anewarray); + out.writeShort(cp.getClass("java/lang/Class")); + + for (int i = 0; i < parameterTypes.length; i++) { + + out.writeByte(opc_dup); + + code_ipush(i, out); + + if (parameterTypes[i].isPrimitive()) { + PrimitiveTypeInfo prim = + PrimitiveTypeInfo.get(parameterTypes[i]); + + out.writeByte(opc_getstatic); + out.writeShort(cp.getFieldRef( + prim.wrapperClassName, "TYPE", "Ljava/lang/Class;")); + + } else { + codeClassForName(parameterTypes[i], out); + } + + out.writeByte(opc_aastore); + } + + out.writeByte(opc_invokevirtual); + out.writeShort(cp.getMethodRef( + "java/lang/Class", + "getMethod", + "(Ljava/lang/String;[Ljava/lang/Class;)" + + "Ljava/lang/reflect/Method;")); + + out.writeByte(opc_putstatic); + out.writeShort(cp.getFieldRef( + dotToSlash(className), + methodFieldName, "Ljava/lang/reflect/Method;")); + } + } + + /** + * Generate the constructor method for the proxy class. + */ + private MethodInfo generateConstructor() throws IOException { + MethodInfo minfo = new MethodInfo( + "<init>", "(Ljava/lang/reflect/InvocationHandler;)V", + ACC_PUBLIC); + + DataOutputStream out = new DataOutputStream(minfo.code); + + code_aload(0, out); + + code_aload(1, out); + + out.writeByte(opc_invokespecial); + out.writeShort(cp.getMethodRef( + superclassName, + "<init>", "(Ljava/lang/reflect/InvocationHandler;)V")); + + out.writeByte(opc_return); + + minfo.maxStack = 10; + minfo.maxLocals = 2; + minfo.declaredExceptions = new short[0]; + + return minfo; + } + + /** + * Generate the static initializer method for the proxy class. + */ + private MethodInfo generateStaticInitializer() throws IOException { + MethodInfo minfo = new MethodInfo( + "<clinit>", "()V", ACC_STATIC); + + int localSlot0 = 1; + short pc, tryBegin = 0, tryEnd; + + DataOutputStream out = new DataOutputStream(minfo.code); + + for (List<ProxyMethod> sigmethods : proxyMethods.values()) { + for (ProxyMethod pm : sigmethods) { + pm.codeFieldInitialization(out); + } + } + + out.writeByte(opc_return); + + tryEnd = pc = (short) minfo.code.size(); + + minfo.exceptionTable.add(new ExceptionTableEntry( + tryBegin, tryEnd, pc, + cp.getClass("java/lang/NoSuchMethodException"))); + + code_astore(localSlot0, out); + + out.writeByte(opc_new); + out.writeShort(cp.getClass("java/lang/NoSuchMethodError")); + + out.writeByte(opc_dup); + + code_aload(localSlot0, out); + + out.writeByte(opc_invokevirtual); + out.writeShort(cp.getMethodRef( + "java/lang/Throwable", "getMessage", "()Ljava/lang/String;")); + + out.writeByte(opc_invokespecial); + out.writeShort(cp.getMethodRef( + "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V")); + + out.writeByte(opc_athrow); + + pc = (short) minfo.code.size(); + + minfo.exceptionTable.add(new ExceptionTableEntry( + tryBegin, tryEnd, pc, + cp.getClass("java/lang/ClassNotFoundException"))); + + code_astore(localSlot0, out); + + out.writeByte(opc_new); + out.writeShort(cp.getClass("java/lang/NoClassDefFoundError")); + + out.writeByte(opc_dup); + + code_aload(localSlot0, out); + + out.writeByte(opc_invokevirtual); + out.writeShort(cp.getMethodRef( + "java/lang/Throwable", "getMessage", "()Ljava/lang/String;")); + + out.writeByte(opc_invokespecial); + out.writeShort(cp.getMethodRef( + "java/lang/NoClassDefFoundError", + "<init>", "(Ljava/lang/String;)V")); + + out.writeByte(opc_athrow); + + if (minfo.code.size() > 65535) { + throw new IllegalArgumentException("code size limit exceeded"); + } + + minfo.maxStack = 10; + minfo.maxLocals = (short) (localSlot0 + 1); + minfo.declaredExceptions = new short[0]; + + return minfo; + } + + + /* + * =============== Code Generation Utility Methods =============== + */ + + /* + * The following methods generate code for the load or store operation + * indicated by their name for the given local variable. The code is + * written to the supplied stream. + */ + + private void code_iload(int lvar, DataOutputStream out) + throws IOException + { + codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out); + } + + private void code_lload(int lvar, DataOutputStream out) + throws IOException + { + codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out); + } + + private void code_fload(int lvar, DataOutputStream out) + throws IOException + { + codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out); + } + + private void code_dload(int lvar, DataOutputStream out) + throws IOException + { + codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out); + } + + private void code_aload(int lvar, DataOutputStream out) + throws IOException + { + codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out); + } + +// private void code_istore(int lvar, DataOutputStream out) +// throws IOException +// { +// codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out); +// } + +// private void code_lstore(int lvar, DataOutputStream out) +// throws IOException +// { +// codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out); +// } + +// private void code_fstore(int lvar, DataOutputStream out) +// throws IOException +// { +// codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out); +// } + +// private void code_dstore(int lvar, DataOutputStream out) +// throws IOException +// { +// codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out); +// } + + private void code_astore(int lvar, DataOutputStream out) + throws IOException + { + codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out); + } + + /** + * Generate code for a load or store instruction for the given local + * variable. The code is written to the supplied stream. + * + * "opcode" indicates the opcode form of the desired load or store + * instruction that takes an explicit local variable index, and + * "opcode_0" indicates the corresponding form of the instruction + * with the implicit index 0. + */ + private void codeLocalLoadStore(int lvar, int opcode, int opcode_0, + DataOutputStream out) + throws IOException + { + assert lvar >= 0 && lvar <= 0xFFFF; + if (lvar <= 3) { + out.writeByte(opcode_0 + lvar); + } else if (lvar <= 0xFF) { + out.writeByte(opcode); + out.writeByte(lvar & 0xFF); + } else { + /* + * Use the "wide" instruction modifier for local variable + * indexes that do not fit into an unsigned byte. + */ + out.writeByte(opc_wide); + out.writeByte(opcode); + out.writeShort(lvar & 0xFFFF); + } + } + + /** + * Generate code for an "ldc" instruction for the given constant pool + * index (the "ldc_w" instruction is used if the index does not fit + * into an unsigned byte). The code is written to the supplied stream. + */ + private void code_ldc(int index, DataOutputStream out) + throws IOException + { + assert index >= 0 && index <= 0xFFFF; + if (index <= 0xFF) { + out.writeByte(opc_ldc); + out.writeByte(index & 0xFF); + } else { + out.writeByte(opc_ldc_w); + out.writeShort(index & 0xFFFF); + } + } + + /** + * Generate code to push a constant integer value on to the operand + * stack, using the "iconst_<i>", "bipush", or "sipush" instructions + * depending on the size of the value. The code is written to the + * supplied stream. + */ + private void code_ipush(int value, DataOutputStream out) + throws IOException + { + if (value >= -1 && value <= 5) { + out.writeByte(opc_iconst_0 + value); + } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { + out.writeByte(opc_bipush); + out.writeByte(value & 0xFF); + } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { + out.writeByte(opc_sipush); + out.writeShort(value & 0xFFFF); + } else { + throw new AssertionError(); + } + } + + /** + * Generate code to invoke the Class.forName with the name of the given + * class to get its Class object at runtime. The code is written to + * the supplied stream. Note that the code generated by this method + * may caused the checked ClassNotFoundException to be thrown. + */ + private void codeClassForName(Class<?> cl, DataOutputStream out) + throws IOException + { + code_ldc(cp.getString(cl.getName()), out); + + out.writeByte(opc_invokestatic); + out.writeShort(cp.getMethodRef( + "java/lang/Class", + "forName", "(Ljava/lang/String;)Ljava/lang/Class;")); + } + + + /* + * ==================== General Utility Methods ==================== + */ + + /** + * Convert a fully qualified class name that uses '.' as the package + * separator, the external representation used by the Java language + * and APIs, to a fully qualified class name that uses '/' as the + * package separator, the representation used in the class file + * format (see JVMS section 4.2). + */ + private static String dotToSlash(String name) { + return name.replace('.', '/'); + } + + /** + * Return the "method descriptor" string for a method with the given + * parameter types and return type. See JVMS section 4.3.3. + */ + private static String getMethodDescriptor(Class<?>[] parameterTypes, + Class<?> returnType) + { + return getParameterDescriptors(parameterTypes) + + ((returnType == void.class) ? "V" : getFieldType(returnType)); + } + + /** + * Return the list of "parameter descriptor" strings enclosed in + * parentheses corresponding to the given parameter types (in other + * words, a method descriptor without a return descriptor). This + * string is useful for constructing string keys for methods without + * regard to their return type. + */ + private static String getParameterDescriptors(Class<?>[] parameterTypes) { + StringBuilder desc = new StringBuilder("("); + for (int i = 0; i < parameterTypes.length; i++) { + desc.append(getFieldType(parameterTypes[i])); + } + desc.append(')'); + return desc.toString(); + } + + /** + * Return the "field type" string for the given type, appropriate for + * a field descriptor, a parameter descriptor, or a return descriptor + * other than "void". See JVMS section 4.3.2. + */ + private static String getFieldType(Class<?> type) { + if (type.isPrimitive()) { + return PrimitiveTypeInfo.get(type).baseTypeString; + } else if (type.isArray()) { + /* + * According to JLS 20.3.2, the getName() method on Class does + * return the VM type descriptor format for array classes (only); + * using that should be quicker than the otherwise obvious code: + * + * return "[" + getTypeDescriptor(type.getComponentType()); + */ + return type.getName().replace('.', '/'); + } else { + return "L" + dotToSlash(type.getName()) + ";"; + } + } + + /** + * Returns a human-readable string representing the signature of a + * method with the given name and parameter types. + */ + private static String getFriendlyMethodSignature(String name, + Class<?>[] parameterTypes) + { + StringBuilder sig = new StringBuilder(name); + sig.append('('); + for (int i = 0; i < parameterTypes.length; i++) { + if (i > 0) { + sig.append(','); + } + Class<?> parameterType = parameterTypes[i]; + int dimensions = 0; + while (parameterType.isArray()) { + parameterType = parameterType.getComponentType(); + dimensions++; + } + sig.append(parameterType.getName()); + while (dimensions-- > 0) { + sig.append("[]"); + } + } + sig.append(')'); + return sig.toString(); + } + + /** + * Return the number of abstract "words", or consecutive local variable + * indexes, required to contain a value of the given type. See JVMS + * section 3.6.1. + * + * Note that the original version of the JVMS contained a definition of + * this abstract notion of a "word" in section 3.4, but that definition + * was removed for the second edition. + */ + private static int getWordsPerType(Class<?> type) { + if (type == long.class || type == double.class) { + return 2; + } else { + return 1; + } + } + + /** + * Add to the given list all of the types in the "from" array that + * are not already contained in the list and are assignable to at + * least one of the types in the "with" array. + * + * This method is useful for computing the greatest common set of + * declared exceptions from duplicate methods inherited from + * different interfaces. + */ + private static void collectCompatibleTypes(Class<?>[] from, + Class<?>[] with, + List<Class<?>> list) + { + for (Class<?> fc: from) { + if (!list.contains(fc)) { + for (Class<?> wc: with) { + if (wc.isAssignableFrom(fc)) { + list.add(fc); + break; + } + } + } + } + } + + /** + * Given the exceptions declared in the throws clause of a proxy method, + * compute the exceptions that need to be caught from the invocation + * handler's invoke method and rethrown intact in the method's + * implementation before catching other Throwables and wrapping them + * in UndeclaredThrowableExceptions. + * + * The exceptions to be caught are returned in a List object. Each + * exception in the returned list is guaranteed to not be a subclass of + * any of the other exceptions in the list, so the catch blocks for + * these exceptions may be generated in any order relative to each other. + * + * Error and RuntimeException are each always contained by the returned + * list (if none of their superclasses are contained), since those + * unchecked exceptions should always be rethrown intact, and thus their + * subclasses will never appear in the returned list. + * + * The returned List will be empty if java.lang.Throwable is in the + * given list of declared exceptions, indicating that no exceptions + * need to be caught. + */ + private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) { + List<Class<?>> uniqueList = new ArrayList<>(); + // unique exceptions to catch + + uniqueList.add(Error.class); // always catch/rethrow these + uniqueList.add(RuntimeException.class); + + nextException: + for (Class<?> ex: exceptions) { + if (ex.isAssignableFrom(Throwable.class)) { + /* + * If Throwable is declared to be thrown by the proxy method, + * then no catch blocks are necessary, because the invoke + * can, at most, throw Throwable anyway. + */ + uniqueList.clear(); + break; + } else if (!Throwable.class.isAssignableFrom(ex)) { + /* + * Ignore types that cannot be thrown by the invoke method. + */ + continue; + } + /* + * Compare this exception against the current list of + * exceptions that need to be caught: + */ + for (int j = 0; j < uniqueList.size();) { + Class<?> ex2 = uniqueList.get(j); + if (ex2.isAssignableFrom(ex)) { + /* + * if a superclass of this exception is already on + * the list to catch, then ignore this one and continue; + */ + continue nextException; + } else if (ex.isAssignableFrom(ex2)) { + /* + * if a subclass of this exception is on the list + * to catch, then remove it; + */ + uniqueList.remove(j); + } else { + j++; // else continue comparing. + } + } + // This exception is unique (so far): add it to the list to catch. + uniqueList.add(ex); + } + return uniqueList; + } + + /** + * A PrimitiveTypeInfo object contains assorted information about + * a primitive type in its public fields. The struct for a particular + * primitive type can be obtained using the static "get" method. + */ + private static class PrimitiveTypeInfo { + + /** "base type" used in various descriptors (see JVMS section 4.3.2) */ + public String baseTypeString; + + /** name of corresponding wrapper class */ + public String wrapperClassName; + + /** method descriptor for wrapper class "valueOf" factory method */ + public String wrapperValueOfDesc; + + /** name of wrapper class method for retrieving primitive value */ + public String unwrapMethodName; + + /** descriptor of same method */ + public String unwrapMethodDesc; + + private static Map<Class<?>,PrimitiveTypeInfo> table = new HashMap<>(); + static { + add(byte.class, Byte.class); + add(char.class, Character.class); + add(double.class, Double.class); + add(float.class, Float.class); + add(int.class, Integer.class); + add(long.class, Long.class); + add(short.class, Short.class); + add(boolean.class, Boolean.class); + } + + private static void add(Class<?> primitiveClass, Class<?> wrapperClass) { + table.put(primitiveClass, + new PrimitiveTypeInfo(primitiveClass, wrapperClass)); + } + + private PrimitiveTypeInfo(Class<?> primitiveClass, Class<?> wrapperClass) { + assert primitiveClass.isPrimitive(); + + baseTypeString = + Array.newInstance(primitiveClass, 0) + .getClass().getName().substring(1); + wrapperClassName = dotToSlash(wrapperClass.getName()); + wrapperValueOfDesc = + "(" + baseTypeString + ")L" + wrapperClassName + ";"; + unwrapMethodName = primitiveClass.getName() + "Value"; + unwrapMethodDesc = "()" + baseTypeString; + } + + public static PrimitiveTypeInfo get(Class<?> cl) { + return table.get(cl); + } + } + + + /** + * A ConstantPool object represents the constant pool of a class file + * being generated. This representation of a constant pool is designed + * specifically for use by ProxyGenerator; in particular, it assumes + * that constant pool entries will not need to be resorted (for example, + * by their type, as the Java compiler does), so that the final index + * value can be assigned and used when an entry is first created. + * + * Note that new entries cannot be created after the constant pool has + * been written to a class file. To prevent such logic errors, a + * ConstantPool instance can be marked "read only", so that further + * attempts to add new entries will fail with a runtime exception. + * + * See JVMS section 4.4 for more information about the constant pool + * of a class file. + */ + private static class ConstantPool { + + /** + * list of constant pool entries, in constant pool index order. + * + * This list is used when writing the constant pool to a stream + * and for assigning the next index value. Note that element 0 + * of this list corresponds to constant pool index 1. + */ + private List<Entry> pool = new ArrayList<>(32); + + /** + * maps constant pool data of all types to constant pool indexes. + * + * This map is used to look up the index of an existing entry for + * values of all types. + */ + private Map<Object,Short> map = new HashMap<>(16); + + /** true if no new constant pool entries may be added */ + private boolean readOnly = false; + + /** + * Get or assign the index for a CONSTANT_Utf8 entry. + */ + public short getUtf8(String s) { + if (s == null) { + throw new NullPointerException(); + } + return getValue(s); + } + + /** + * Get or assign the index for a CONSTANT_Integer entry. + */ + public short getInteger(int i) { + return getValue(i); + } + + /** + * Get or assign the index for a CONSTANT_Float entry. + */ + public short getFloat(float f) { + return getValue(new Float(f)); + } + + /** + * Get or assign the index for a CONSTANT_Class entry. + */ + public short getClass(String name) { + short utf8Index = getUtf8(name); + return getIndirect(new IndirectEntry( + CONSTANT_CLASS, utf8Index)); + } + + /** + * Get or assign the index for a CONSTANT_String entry. + */ + public short getString(String s) { + short utf8Index = getUtf8(s); + return getIndirect(new IndirectEntry( + CONSTANT_STRING, utf8Index)); + } + + /** + * Get or assign the index for a CONSTANT_FieldRef entry. + */ + public short getFieldRef(String className, + String name, String descriptor) + { + short classIndex = getClass(className); + short nameAndTypeIndex = getNameAndType(name, descriptor); + return getIndirect(new IndirectEntry( + CONSTANT_FIELD, classIndex, nameAndTypeIndex)); + } + + /** + * Get or assign the index for a CONSTANT_MethodRef entry. + */ + public short getMethodRef(String className, + String name, String descriptor) + { + short classIndex = getClass(className); + short nameAndTypeIndex = getNameAndType(name, descriptor); + return getIndirect(new IndirectEntry( + CONSTANT_METHOD, classIndex, nameAndTypeIndex)); + } + + /** + * Get or assign the index for a CONSTANT_InterfaceMethodRef entry. + */ + public short getInterfaceMethodRef(String className, String name, + String descriptor) + { + short classIndex = getClass(className); + short nameAndTypeIndex = getNameAndType(name, descriptor); + return getIndirect(new IndirectEntry( + CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex)); + } + + /** + * Get or assign the index for a CONSTANT_NameAndType entry. + */ + public short getNameAndType(String name, String descriptor) { + short nameIndex = getUtf8(name); + short descriptorIndex = getUtf8(descriptor); + return getIndirect(new IndirectEntry( + CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex)); + } + + /** + * Set this ConstantPool instance to be "read only". + * + * After this method has been called, further requests to get + * an index for a non-existent entry will cause an InternalError + * to be thrown instead of creating of the entry. + */ + public void setReadOnly() { + readOnly = true; + } + + /** + * Write this constant pool to a stream as part of + * the class file format. + * + * This consists of writing the "constant_pool_count" and + * "constant_pool[]" items of the "ClassFile" structure, as + * described in JVMS section 4.1. + */ + public void write(OutputStream out) throws IOException { + DataOutputStream dataOut = new DataOutputStream(out); + + // constant_pool_count: number of entries plus one + dataOut.writeShort(pool.size() + 1); + + for (Entry e : pool) { + e.write(dataOut); + } + } + + /** + * Add a new constant pool entry and return its index. + */ + private short addEntry(Entry entry) { + pool.add(entry); + /* + * Note that this way of determining the index of the + * added entry is wrong if this pool supports + * CONSTANT_Long or CONSTANT_Double entries. + */ + if (pool.size() >= 65535) { + throw new IllegalArgumentException( + "constant pool size limit exceeded"); + } + return (short) pool.size(); + } + + /** + * Get or assign the index for an entry of a type that contains + * a direct value. The type of the given object determines the + * type of the desired entry as follows: + * + * java.lang.String CONSTANT_Utf8 + * java.lang.Integer CONSTANT_Integer + * java.lang.Float CONSTANT_Float + * java.lang.Long CONSTANT_Long + * java.lang.Double CONSTANT_DOUBLE + */ + private short getValue(Object key) { + Short index = map.get(key); + if (index != null) { + return index.shortValue(); + } else { + if (readOnly) { + throw new InternalError( + "late constant pool addition: " + key); + } + short i = addEntry(new ValueEntry(key)); + map.put(key, i); + return i; + } + } + + /** + * Get or assign the index for an entry of a type that contains + * references to other constant pool entries. + */ + private short getIndirect(IndirectEntry e) { + Short index = map.get(e); + if (index != null) { + return index.shortValue(); + } else { + if (readOnly) { + throw new InternalError("late constant pool addition"); + } + short i = addEntry(e); + map.put(e, i); + return i; + } + } + + /** + * Entry is the abstact superclass of all constant pool entry types + * that can be stored in the "pool" list; its purpose is to define a + * common method for writing constant pool entries to a class file. + */ + private abstract static class Entry { + public abstract void write(DataOutputStream out) + throws IOException; + } + + /** + * ValueEntry represents a constant pool entry of a type that + * contains a direct value (see the comments for the "getValue" + * method for a list of such types). + * + * ValueEntry objects are not used as keys for their entries in the + * Map "map", so no useful hashCode or equals methods are defined. + */ + private static class ValueEntry extends Entry { + private Object value; + + public ValueEntry(Object value) { + this.value = value; + } + + public void write(DataOutputStream out) throws IOException { + if (value instanceof String) { + out.writeByte(CONSTANT_UTF8); + out.writeUTF((String) value); + } else if (value instanceof Integer) { + out.writeByte(CONSTANT_INTEGER); + out.writeInt(((Integer) value).intValue()); + } else if (value instanceof Float) { + out.writeByte(CONSTANT_FLOAT); + out.writeFloat(((Float) value).floatValue()); + } else if (value instanceof Long) { + out.writeByte(CONSTANT_LONG); + out.writeLong(((Long) value).longValue()); + } else if (value instanceof Double) { + out.writeDouble(CONSTANT_DOUBLE); + out.writeDouble(((Double) value).doubleValue()); + } else { + throw new InternalError("bogus value entry: " + value); + } + } + } + + /** + * IndirectEntry represents a constant pool entry of a type that + * references other constant pool entries, i.e., the following types: + * + * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref, + * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and + * CONSTANT_NameAndType. + * + * Each of these entry types contains either one or two indexes of + * other constant pool entries. + * + * IndirectEntry objects are used as the keys for their entries in + * the Map "map", so the hashCode and equals methods are overridden + * to allow matching. + */ + private static class IndirectEntry extends Entry { + private int tag; + private short index0; + private short index1; + + /** + * Construct an IndirectEntry for a constant pool entry type + * that contains one index of another entry. + */ + public IndirectEntry(int tag, short index) { + this.tag = tag; + this.index0 = index; + this.index1 = 0; + } + + /** + * Construct an IndirectEntry for a constant pool entry type + * that contains two indexes for other entries. + */ + public IndirectEntry(int tag, short index0, short index1) { + this.tag = tag; + this.index0 = index0; + this.index1 = index1; + } + + public void write(DataOutputStream out) throws IOException { + out.writeByte(tag); + out.writeShort(index0); + /* + * If this entry type contains two indexes, write + * out the second, too. + */ + if (tag == CONSTANT_FIELD || + tag == CONSTANT_METHOD || + tag == CONSTANT_INTERFACEMETHOD || + tag == CONSTANT_NAMEANDTYPE) + { + out.writeShort(index1); + } + } + + public int hashCode() { + return tag + index0 + index1; + } + + public boolean equals(Object obj) { + if (obj instanceof IndirectEntry) { + IndirectEntry other = (IndirectEntry) obj; + if (tag == other.tag && + index0 == other.index0 && index1 == other.index1) + { + return true; + } + } + return false; + } + } + } +}
--- a/src/java.base/share/classes/java/security/cert/PolicyQualifierInfo.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/security/cert/PolicyQualifierInfo.java Tue Dec 22 13:41:12 2015 -0800 @@ -27,7 +27,7 @@ import java.io.IOException; -import sun.misc.HexDumpEncoder; +import sun.security.util.HexDumpEncoder; import sun.security.util.DerValue; /**
--- a/src/java.base/share/classes/java/security/cert/X509CertSelector.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/security/cert/X509CertSelector.java Tue Dec 22 13:41:12 2015 -0800 @@ -31,7 +31,7 @@ import java.util.*; import javax.security.auth.x500.X500Principal; -import sun.misc.HexDumpEncoder; +import sun.security.util.HexDumpEncoder; import sun.security.util.Debug; import sun.security.util.DerInputStream; import sun.security.util.DerValue;
--- a/src/java.base/share/classes/java/text/SimpleDateFormat.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java Tue Dec 22 13:41:12 2015 -0800 @@ -1856,6 +1856,7 @@ if (patternCharIndex == PATTERN_HOUR_OF_DAY1 || patternCharIndex == PATTERN_HOUR1 || (patternCharIndex == PATTERN_MONTH && count <= 2) || + (patternCharIndex == PATTERN_MONTH_STANDALONE && count <= 2) || patternCharIndex == PATTERN_YEAR || patternCharIndex == PATTERN_WEEK_YEAR) { // It would be good to unify this with the obeyCount logic below, @@ -1976,6 +1977,20 @@ } break parsing; + case PATTERN_MONTH_STANDALONE: // 'L' + if (count <= 2) { + // Don't want to parse the month if it is a string + // while pattern uses numeric style: L or LL + //[we computed 'value' above.] + calb.set(Calendar.MONTH, value - 1); + return pos.index; + } + Map<String, Integer> maps = getDisplayNamesMap(field, locale); + if ((index = matchString(text, start, field, maps, calb)) > 0) { + return index; + } + break parsing; + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59 if (!isLenient()) { // Validate the hour value in non-lenient
--- a/src/java.base/share/classes/java/time/Duration.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/time/Duration.java Tue Dec 22 13:41:12 2015 -0800 @@ -997,6 +997,24 @@ } /** + * Returns number of whole times a specified Duration occurs within this Duration. + * <p> + * This instance is immutable and unaffected by this method call. + * + * @param divisor the value to divide the duration by, positive or negative, not null + * @return number of whole times, rounded toward zero, a specified + * {@code Duration} occurs within this Duration, may be negative + * @throws ArithmeticException if the divisor is zero, or if numeric overflow occurs + * @since 9 + */ + public long dividedBy(Duration divisor) { + Objects.requireNonNull(divisor, "divisor"); + BigDecimal dividendBigD = toBigDecimalSeconds(); + BigDecimal divisorBigD = divisor.toBigDecimalSeconds(); + return dividendBigD.divideToIntegralValue(divisorBigD).longValueExact(); + } + + /** * Converts this duration to the total length in seconds and * fractional nanoseconds expressed as a {@code BigDecimal}. *
--- a/src/java.base/share/classes/java/util/AbstractMap.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/AbstractMap.java Tue Dec 22 13:41:12 2015 -0800 @@ -304,9 +304,28 @@ * Each of these fields are initialized to contain an instance of the * appropriate view the first time this view is requested. The views are * stateless, so there's no reason to create more than one of each. + * + * <p>Since there is no synchronization performed while accessing these fields, + * it is expected that java.util.Map view classes using these fields have + * no non-final fields (or any fields at all except for outer-this). Adhering + * to this rule would make the races on these fields benign. + * + * <p>It is also imperative that implementations read the field only once, + * as in: + * + * <pre> {@code + * public Set<K> keySet() { + * Set<K> ks = keySet; // single racy read + * if (ks == null) { + * ks = new KeySet(); + * keySet = ks; + * } + * return ks; + * } + *}</pre> */ - transient volatile Set<K> keySet; - transient volatile Collection<V> values; + transient Set<K> keySet; + transient Collection<V> values; /** * {@inheritDoc} @@ -325,8 +344,9 @@ * method will not all return the same set. */ public Set<K> keySet() { - if (keySet == null) { - keySet = new AbstractSet<K>() { + Set<K> ks = keySet; + if (ks == null) { + ks = new AbstractSet<K>() { public Iterator<K> iterator() { return new Iterator<K>() { private Iterator<Entry<K,V>> i = entrySet().iterator(); @@ -361,8 +381,9 @@ return AbstractMap.this.containsKey(k); } }; + keySet = ks; } - return keySet; + return ks; } /** @@ -382,8 +403,9 @@ * method will not all return the same collection. */ public Collection<V> values() { - if (values == null) { - values = new AbstractCollection<V>() { + Collection<V> vals = values; + if (vals == null) { + vals = new AbstractCollection<V>() { public Iterator<V> iterator() { return new Iterator<V>() { private Iterator<Entry<K,V>> i = entrySet().iterator(); @@ -418,8 +440,9 @@ return AbstractMap.this.containsValue(v); } }; + values = vals; } - return values; + return vals; } public abstract Set<Entry<K,V>> entrySet();
--- a/src/java.base/share/classes/java/util/Collections.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/Collections.java Tue Dec 22 13:41:12 2015 -0800 @@ -5530,7 +5530,7 @@ * @since 1.6 */ public static <T> Queue<T> asLifoQueue(Deque<T> deque) { - return new AsLIFOQueue<>(deque); + return new AsLIFOQueue<>(Objects.requireNonNull(deque)); } /**
--- a/src/java.base/share/classes/java/util/EnumMap.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/EnumMap.java Tue Dec 22 13:41:12 2015 -0800 @@ -380,10 +380,11 @@ */ public Set<K> keySet() { Set<K> ks = keySet; - if (ks != null) - return ks; - else - return keySet = new KeySet(); + if (ks == null) { + ks = new KeySet(); + keySet = ks; + } + return ks; } private class KeySet extends AbstractSet<K> { @@ -418,10 +419,11 @@ */ public Collection<V> values() { Collection<V> vs = values; - if (vs != null) - return vs; - else - return values = new Values(); + if (vs == null) { + vs = new Values(); + values = vs; + } + return vs; } private class Values extends AbstractCollection<V> {
--- a/src/java.base/share/classes/java/util/HashMap.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/HashMap.java Tue Dec 22 13:41:12 2015 -0800 @@ -902,8 +902,12 @@ * @return a set view of the keys contained in this map */ public Set<K> keySet() { - Set<K> ks; - return (ks = keySet) == null ? (keySet = new KeySet()) : ks; + Set<K> ks = keySet; + if (ks == null) { + ks = new KeySet(); + keySet = ks; + } + return ks; } final class KeySet extends AbstractSet<K> { @@ -949,8 +953,12 @@ * @return a view of the values contained in this map */ public Collection<V> values() { - Collection<V> vs; - return (vs = values) == null ? (values = new Values()) : vs; + Collection<V> vs = values; + if (vs == null) { + vs = new Values(); + values = vs; + } + return vs; } final class Values extends AbstractCollection<V> {
--- a/src/java.base/share/classes/java/util/IdentityHashMap.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/IdentityHashMap.java Tue Dec 22 13:41:12 2015 -0800 @@ -964,10 +964,11 @@ */ public Set<K> keySet() { Set<K> ks = keySet; - if (ks != null) - return ks; - else - return keySet = new KeySet(); + if (ks == null) { + ks = new KeySet(); + keySet = ks; + } + return ks; } private class KeySet extends AbstractSet<K> { @@ -1069,10 +1070,11 @@ */ public Collection<V> values() { Collection<V> vs = values; - if (vs != null) - return vs; - else - return values = new Values(); + if (vs == null) { + vs = new Values(); + values = vs; + } + return vs; } private class Values extends AbstractCollection<V> {
--- a/src/java.base/share/classes/java/util/LinkedHashMap.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/LinkedHashMap.java Tue Dec 22 13:41:12 2015 -0800 @@ -528,8 +528,12 @@ * @return a set view of the keys contained in this map */ public Set<K> keySet() { - Set<K> ks; - return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks; + Set<K> ks = keySet; + if (ks == null) { + ks = new LinkedKeySet(); + keySet = ks; + } + return ks; } final class LinkedKeySet extends AbstractSet<K> { @@ -577,8 +581,12 @@ * @return a view of the values contained in this map */ public Collection<V> values() { - Collection<V> vs; - return (vs = values) == null ? (values = new LinkedValues()) : vs; + Collection<V> vs = values; + if (vs == null) { + vs = new LinkedValues(); + values = vs; + } + return vs; } final class LinkedValues extends AbstractCollection<V> {
--- a/src/java.base/share/classes/java/util/TreeMap.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/TreeMap.java Tue Dec 22 13:41:12 2015 -0800 @@ -852,7 +852,11 @@ */ public Collection<V> values() { Collection<V> vs = values; - return (vs != null) ? vs : (values = new Values()); + if (vs == null) { + vs = new Values(); + values = vs; + } + return vs; } /**
--- a/src/java.base/share/classes/java/util/WeakHashMap.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/WeakHashMap.java Tue Dec 22 13:41:12 2015 -0800 @@ -866,7 +866,11 @@ */ public Set<K> keySet() { Set<K> ks = keySet; - return (ks != null ? ks : (keySet = new KeySet())); + if (ks == null) { + ks = new KeySet(); + keySet = ks; + } + return ks; } private class KeySet extends AbstractSet<K> { @@ -915,7 +919,11 @@ */ public Collection<V> values() { Collection<V> vs = values; - return (vs != null) ? vs : (values = new Values()); + if (vs == null) { + vs = new Values(); + values = vs; + } + return vs; } private class Values extends AbstractCollection<V> {
--- a/src/java.base/share/classes/java/util/jar/JarFile.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/jar/JarFile.java Tue Dec 22 13:41:12 2015 -0800 @@ -203,7 +203,10 @@ return man; } - private native String[] getMetaInfEntryNames(); + private String[] getMetaInfEntryNames() { + return jdk.internal.misc.SharedSecrets.getJavaUtilZipFileAccess() + .getMetaInfEntryNames((ZipFile)this); + } /** * Returns the {@code JarEntry} for the given entry name or
--- a/src/java.base/share/classes/java/util/regex/Pattern.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/regex/Pattern.java Tue Dec 22 13:41:12 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -5814,7 +5814,7 @@ */ public Stream<String> splitAsStream(final CharSequence input) { class MatcherIterator implements Iterator<String> { - private final Matcher matcher; + private Matcher matcher; // The start position of the next sub-sequence of input // when current == input.length there are no more elements private int current; @@ -5823,14 +5823,6 @@ // > 0 if there are N next empty elements private int emptyElementCount; - MatcherIterator() { - this.matcher = matcher(input); - // If the input is an empty string then the result can only be a - // stream of the input. Induce that by setting the empty - // element count to 1 - this.emptyElementCount = input.length() == 0 ? 1 : 0; - } - public String next() { if (!hasNext()) throw new NoSuchElementException(); @@ -5846,6 +5838,13 @@ } public boolean hasNext() { + if (matcher == null) { + matcher = matcher(input); + // If the input is an empty string then the result can only be a + // stream of the input. Induce that by setting the empty + // element count to 1 + emptyElementCount = input.length() == 0 ? 1 : 0; + } if (nextElement != null || emptyElementCount > 0) return true;
--- a/src/java.base/share/classes/java/util/stream/Collectors.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/stream/Collectors.java Tue Dec 22 13:41:12 2015 -0800 @@ -434,7 +434,7 @@ * stream returned by mapper * @return a collector which applies the mapping function to the input * elements and provides the flat mapped results to the downstream collector - * @since 1.9 + * @since 9 */ public static <T, U, A, R> Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, @@ -452,6 +452,53 @@ } /** + * Adapts a {@code Collector} to one accepting elements of the same type + * {@code T} by applying the predicate to each input element and only + * accumulating if the predicate returns {@code true}. + * + * @apiNote + * The {@code filtering()} collectors are most useful when used in a + * multi-level reduction, such as downstream of a {@code groupingBy} or + * {@code partitioningBy}. For example, given a stream of + * {@code Employee}, to accumulate the employees in each department that have a + * salary above a certain threshold: + * <pre>{@code + * Map<Department, Set<Employee>> wellPaidEmployeesByDepartment + * = employees.stream().collect(groupingBy(Employee::getDepartment, + * filtering(e -> e.getSalary() > 2000, toSet()))); + * }</pre> + * A filtering collector differs from a stream's {@code filter()} operation. + * In this example, suppose there are no employees whose salary is above the + * threshold in some department. Using a filtering collector as shown above + * would result in a mapping from that department to an empty {@code Set}. + * If a stream {@code filter()} operation were done instead, there would be + * no mapping for that department at all. + * + * @param <T> the type of the input elements + * @param <A> intermediate accumulation type of the downstream collector + * @param <R> result type of collector + * @param predicate a predicate to be applied to the input elements + * @param downstream a collector which will accept values that match the + * predicate + * @return a collector which applies the predicate to the input elements + * and provides matching elements to the downstream collector + * @since 9 + */ + public static <T, A, R> + Collector<T, ?, R> filtering(Predicate<? super T> predicate, + Collector<? super T, A, R> downstream) { + BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); + return new CollectorImpl<>(downstream.supplier(), + (r, t) -> { + if (predicate.test(t)) { + downstreamAccumulator.accept(r, t); + } + }, + downstream.combiner(), downstream.finisher(), + downstream.characteristics()); + } + + /** * Adapts a {@code Collector} to perform an additional finishing * transformation. For example, one could adapt the {@link #toList()} * collector to always produce an immutable list with:
--- a/src/java.base/share/classes/java/util/zip/ZipCoder.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java Tue Dec 22 13:41:12 2015 -0800 @@ -43,7 +43,7 @@ final class ZipCoder { - String toString(byte[] ba, int length) { + String toString(byte[] ba, int off, int length) { CharsetDecoder cd = decoder().reset(); int len = (int)(length * cd.maxCharsPerByte()); char[] ca = new char[len]; @@ -53,12 +53,12 @@ // CodingErrorAction.REPLACE mode. ZipCoder uses // REPORT mode. if (isUTF8 && cd instanceof ArrayDecoder) { - int clen = ((ArrayDecoder)cd).decode(ba, 0, length, ca); + int clen = ((ArrayDecoder)cd).decode(ba, off, length, ca); if (clen == -1) // malformed throw new IllegalArgumentException("MALFORMED"); return new String(ca, 0, clen); } - ByteBuffer bb = ByteBuffer.wrap(ba, 0, length); + ByteBuffer bb = ByteBuffer.wrap(ba, off, length); CharBuffer cb = CharBuffer.wrap(ca); CoderResult cr = cd.decode(bb, cb, true); if (!cr.isUnderflow()) @@ -69,8 +69,12 @@ return new String(ca, 0, cb.position()); } + String toString(byte[] ba, int length) { + return toString(ba, 0, length); + } + String toString(byte[] ba) { - return toString(ba, ba.length); + return toString(ba, 0, ba.length); } byte[] getBytes(String s) { @@ -111,13 +115,16 @@ return utf8.getBytes(s); } + String toStringUTF8(byte[] ba, int len) { + return toStringUTF8(ba, 0, len); + } - String toStringUTF8(byte[] ba, int len) { + String toStringUTF8(byte[] ba, int off, int len) { if (isUTF8) - return toString(ba, len); + return toString(ba, off, len); if (utf8 == null) utf8 = new ZipCoder(StandardCharsets.UTF_8); - return utf8.toString(ba, len); + return utf8.toString(ba, off, len); } boolean isUTF8() {
--- a/src/java.base/share/classes/java/util/zip/ZipFile.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java Tue Dec 22 13:41:12 2015 -0800 @@ -30,14 +30,22 @@ import java.io.IOException; import java.io.EOFException; import java.io.File; +import java.io.RandomAccessFile; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.Path; +import java.nio.file.Files; + import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Deque; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Objects; import java.util.NoSuchElementException; import java.util.Spliterator; import java.util.Spliterators; @@ -47,7 +55,9 @@ import jdk.internal.misc.JavaUtilZipFileAccess; import jdk.internal.misc.SharedSecrets; +import static java.util.zip.ZipConstants.*; import static java.util.zip.ZipConstants64.*; +import static java.util.zip.ZipUtils.*; /** * This class is used to read entries from a zip file. @@ -60,11 +70,11 @@ */ public class ZipFile implements ZipConstants, Closeable { - private long jzfile; // address of jzfile data + private final String name; // zip file name - private final int total; // total number of entries - private final boolean locsig; // if zip file starts with LOCSIG (usually true) private volatile boolean closeRequested = false; + private Source zsrc; + private ZipCoder zc; private static final int STORED = ZipEntry.STORED; private static final int DEFLATED = ZipEntry.DEFLATED; @@ -83,23 +93,6 @@ */ public static final int OPEN_DELETE = 0x4; - static { - /* Zip library is loaded from System.initializeSystemClass */ - initIDs(); - } - - private static native void initIDs(); - - private static final boolean usemmap; - - static { - // A system prpperty to disable mmap use to avoid vm crash when - // in-use zip file is accidently overwritten by others. - String prop = sun.misc.VM.getSavedProperty("sun.zip.disableMemoryMapping"); - usemmap = (prop == null || - !(prop.length() == 0 || prop.equalsIgnoreCase("true"))); - } - /** * Opens a zip file for reading. * @@ -165,8 +158,6 @@ this(file, OPEN_READ); } - private ZipCoder zc; - /** * Opens a new {@code ZipFile} to read from the specified * {@code File} object in the specified mode. The mode argument @@ -214,16 +205,13 @@ sm.checkDelete(name); } } - if (charset == null) - throw new NullPointerException("charset is null"); + Objects.requireNonNull(charset, "charset"); this.zc = ZipCoder.get(charset); + this.name = name; long t0 = System.nanoTime(); - jzfile = open(name, mode, file.lastModified(), usemmap); + this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0); sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0); sun.misc.PerfCounter.getZipFileCount().increment(); - this.name = name; - this.total = getTotal(jzfile); - this.locsig = startsWithLOC(jzfile); } /** @@ -257,6 +245,7 @@ /** * Opens a ZIP file for reading given the specified File object. + * * @param file the ZIP file to be opened for reading * @param charset * The {@linkplain java.nio.charset.Charset charset} to be @@ -287,10 +276,10 @@ public String getComment() { synchronized (this) { ensureOpen(); - byte[] bcomm = getCommentBytes(jzfile); - if (bcomm == null) + if (zsrc.comment == null) { return null; - return zc.toString(bcomm, bcomm.length); + } + return zc.toString(zsrc.comment); } } @@ -303,38 +292,28 @@ * @throws IllegalStateException if the zip file has been closed */ public ZipEntry getEntry(String name) { - if (name == null) { - throw new NullPointerException("name"); - } - long jzentry = 0; + + Objects.requireNonNull(name, "name"); synchronized (this) { ensureOpen(); - jzentry = getEntry(jzfile, zc.getBytes(name), true); - if (jzentry != 0) { - ZipEntry ze = getZipEntry(name, jzentry); - freeEntry(jzfile, jzentry); - return ze; + int pos = zsrc.getEntryPos(zc.getBytes(name), true); + if (pos != -1) { + return getZipEntry(name, pos); } } return null; } - private static native long getEntry(long jzfile, byte[] name, - boolean addSlash); - - // freeEntry releases the C jzentry struct. - private static native void freeEntry(long jzfile, long jzentry); - - // the outstanding inputstreams that need to be closed, + // The outstanding inputstreams that need to be closed, // mapped to the inflater objects they use. private final Map<InputStream, Inflater> streams = new WeakHashMap<>(); /** * Returns an input stream for reading the contents of the specified * zip file entry. - * - * <p> Closing this ZIP file will, in turn, close all input - * streams that have been returned by invocations of this method. + * <p> + * Closing this ZIP file will, in turn, close all input streams that + * have been returned by invocations of this method. * * @param entry the zip file entry * @return the input stream for reading the contents of the specified @@ -344,37 +323,38 @@ * @throws IllegalStateException if the zip file has been closed */ public InputStream getInputStream(ZipEntry entry) throws IOException { - if (entry == null) { - throw new NullPointerException("entry"); - } - long jzentry = 0; + Objects.requireNonNull(entry, "entry"); + int pos = -1; ZipFileInputStream in = null; synchronized (this) { ensureOpen(); if (!zc.isUTF8() && (entry.flag & EFS) != 0) { - jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false); + pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false); } else { - jzentry = getEntry(jzfile, zc.getBytes(entry.name), false); + pos = zsrc.getEntryPos(zc.getBytes(entry.name), false); } - if (jzentry == 0) { + if (pos == -1) { return null; } - in = new ZipFileInputStream(jzentry); - - switch (getEntryMethod(jzentry)) { + in = new ZipFileInputStream(zsrc.cen, pos); + switch (CENHOW(zsrc.cen, pos)) { case STORED: synchronized (streams) { streams.put(in, null); } return in; case DEFLATED: + // Inflater likes a bit of slack // MORE: Compute good size for inflater stream: - long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack - if (size > 65536) size = 8192; - if (size <= 0) size = 4096; + long size = CENLEN(zsrc.cen, pos) + 2; + if (size > 65536) { + size = 8192; + } + if (size <= 0) { + size = 4096; + } Inflater inf = getInflater(); - InputStream is = - new ZipFileInflaterInputStream(in, inf, (int)size); + InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size); synchronized (streams) { streams.put(is, inf); } @@ -447,8 +427,8 @@ private Inflater getInflater() { Inflater inf; synchronized (inflaterCache) { - while (null != (inf = inflaterCache.poll())) { - if (false == inf.ended()) { + while ((inf = inflaterCache.poll()) != null) { + if (!inf.ended()) { return inf; } } @@ -460,7 +440,7 @@ * Releases the specified inflater to the list of available inflaters. */ private void releaseInflater(Inflater inf) { - if (false == inf.ended()) { + if (!inf.ended()) { inf.reset(); synchronized (inflaterCache) { inflaterCache.add(inf); @@ -469,7 +449,7 @@ } // List of available Inflater objects for decompression - private Deque<Inflater> inflaterCache = new ArrayDeque<>(); + private final Deque<Inflater> inflaterCache = new ArrayDeque<>(); /** * Returns the path name of the ZIP file. @@ -493,7 +473,7 @@ public boolean hasNext() { synchronized (ZipFile.this) { ensureOpen(); - return i < total; + return i < zsrc.total; } } @@ -504,28 +484,11 @@ public ZipEntry next() { synchronized (ZipFile.this) { ensureOpen(); - if (i >= total) { + if (i >= zsrc.total) { throw new NoSuchElementException(); } - long jzentry = getNextEntry(jzfile, i++); - if (jzentry == 0) { - String message; - if (closeRequested) { - message = "ZipFile concurrently closed"; - } else { - message = getZipMessage(ZipFile.this.jzfile); - } - throw new ZipError("jzentry == 0" + - ",\n jzfile = " + ZipFile.this.jzfile + - ",\n total = " + ZipFile.this.total + - ",\n name = " + ZipFile.this.name + - ",\n i = " + i + - ",\n message = " + message - ); - } - ZipEntry ze = getZipEntry(null, jzentry); - freeEntry(jzfile, jzentry); - return ze; + // each "entry" has 3 ints in table entries + return getZipEntry(null, zsrc.getEntryPos(i++ * 3)); } } @@ -559,48 +522,53 @@ Spliterator.IMMUTABLE | Spliterator.NONNULL), false); } - private ZipEntry getZipEntry(String name, long jzentry) { + /* Checks ensureOpen() before invoke this method */ + private ZipEntry getZipEntry(String name, int pos) { + byte[] cen = zsrc.cen; ZipEntry e = new ZipEntry(); - e.flag = getEntryFlag(jzentry); // get the flag first + int nlen = CENNAM(cen, pos); + int elen = CENEXT(cen, pos); + int clen = CENCOM(cen, pos); + e.flag = CENFLG(cen, pos); // get the flag first if (name != null) { e.name = name; } else { - byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME); if (!zc.isUTF8() && (e.flag & EFS) != 0) { - e.name = zc.toStringUTF8(bname, bname.length); + e.name = zc.toStringUTF8(cen, pos + CENHDR, nlen); } else { - e.name = zc.toString(bname, bname.length); + e.name = zc.toString(cen, pos + CENHDR, nlen); } } - e.xdostime = getEntryTime(jzentry); - e.crc = getEntryCrc(jzentry); - e.size = getEntrySize(jzentry); - e.csize = getEntryCSize(jzentry); - e.method = getEntryMethod(jzentry); - e.setExtra0(getEntryBytes(jzentry, JZENTRY_EXTRA), false); - byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT); - if (bcomm == null) { - e.comment = null; - } else { + e.xdostime = CENTIM(cen, pos); + e.crc = CENCRC(cen, pos); + e.size = CENLEN(cen, pos); + e.csize = CENSIZ(cen, pos); + e.method = CENHOW(cen, pos); + if (elen != 0) { + e.setExtra0(Arrays.copyOfRange(cen, pos + CENHDR + nlen, + pos + CENHDR + nlen + elen), true); + } + if (clen != 0) { if (!zc.isUTF8() && (e.flag & EFS) != 0) { - e.comment = zc.toStringUTF8(bcomm, bcomm.length); + e.comment = zc.toStringUTF8(cen, pos + CENHDR + nlen + elen, clen); } else { - e.comment = zc.toString(bcomm, bcomm.length); + e.comment = zc.toString(cen, pos + CENHDR + nlen + elen, clen); } } return e; } - private static native long getNextEntry(long jzfile, int i); - /** * Returns the number of entries in the ZIP file. + * * @return the number of entries in the ZIP file * @throws IllegalStateException if the zip file has been closed */ public int size() { - ensureOpen(); - return total; + synchronized (this) { + ensureOpen(); + return zsrc.total; + } } /** @@ -612,14 +580,15 @@ * @throws IOException if an I/O error has occurred */ public void close() throws IOException { - if (closeRequested) + if (closeRequested) { return; + } closeRequested = true; synchronized (this) { // Close streams, release their inflaters synchronized (streams) { - if (false == streams.isEmpty()) { + if (!streams.isEmpty()) { Map<InputStream, Inflater> copy = new HashMap<>(streams); streams.clear(); for (Map.Entry<InputStream, Inflater> e : copy.entrySet()) { @@ -631,21 +600,17 @@ } } } - // Release cached inflaters - Inflater inf; synchronized (inflaterCache) { - while (null != (inf = inflaterCache.poll())) { + Inflater inf; + while ((inf = inflaterCache.poll()) != null) { inf.end(); } } - - if (jzfile != 0) { - // Close the zip file - long zf = this.jzfile; - jzfile = 0; - - close(zf); + // Release zip src + if (zsrc != null) { + Source.close(zsrc); + zsrc = null; } } } @@ -668,14 +633,11 @@ close(); } - private static native void close(long jzfile); - private void ensureOpen() { if (closeRequested) { throw new IllegalStateException("zip file closed"); } - - if (jzfile == 0) { + if (zsrc == null) { throw new IllegalStateException("The object is not initialized."); } } @@ -691,40 +653,99 @@ * (possibly compressed) zip file entry. */ private class ZipFileInputStream extends InputStream { - private volatile boolean zfisCloseRequested = false; - protected long jzentry; // address of jzentry data + private volatile boolean closeRequested = false; private long pos; // current position within entry data protected long rem; // number of remaining bytes within entry protected long size; // uncompressed size of this entry - ZipFileInputStream(long jzentry) { - pos = 0; - rem = getEntryCSize(jzentry); - size = getEntrySize(jzentry); - this.jzentry = jzentry; + ZipFileInputStream(byte[] cen, int cenpos) throws IOException { + rem = CENSIZ(cen, cenpos); + size = CENLEN(cen, cenpos); + pos = CENOFF(cen, cenpos); + // zip64 + if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL || + pos == ZIP64_MAGICVAL) { + checkZIP64(cen, cenpos); + } + // negative for lazy initialization, see getDataOffset(); + pos = - (pos + ZipFile.this.zsrc.locpos); + } + + private void checkZIP64(byte[] cen, int cenpos) throws IOException { + int off = cenpos + CENHDR + CENNAM(cen, cenpos); + int end = off + CENEXT(cen, cenpos); + while (off + 4 < end) { + int tag = get16(cen, off); + int sz = get16(cen, off + 2); + off += 4; + if (off + sz > end) // invalid data + break; + if (tag == EXTID_ZIP64) { + if (size == ZIP64_MAGICVAL) { + if (sz < 8 || (off + 8) > end) + break; + size = get64(cen, off); + sz -= 8; + off += 8; + } + if (rem == ZIP64_MAGICVAL) { + if (sz < 8 || (off + 8) > end) + break; + rem = get64(cen, off); + sz -= 8; + off += 8; + } + if (pos == ZIP64_MAGICVAL) { + if (sz < 8 || (off + 8) > end) + break; + pos = get64(cen, off); + sz -= 8; + off += 8; + } + break; + } + off += sz; + } + } + + /* The Zip file spec explicitly allows the LOC extra data size to + * be different from the CEN extra data size. Since we cannot trust + * the CEN extra data size, we need to read the LOC to determine + * the entry data offset. + */ + private long initDataOffset() throws IOException { + if (pos <= 0) { + byte[] loc = new byte[LOCHDR]; + pos = -pos; + int len = ZipFile.this.zsrc.readFullyAt(loc, 0, loc.length, pos); + if (len != LOCHDR) { + throw new ZipException("ZipFile error reading zip file"); + } + if (LOCSIG(loc) != LOCSIG) { + throw new ZipException("ZipFile invalid LOC header (bad signature)"); + } + pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc); + } + return pos; } public int read(byte b[], int off, int len) throws IOException { synchronized (ZipFile.this) { - long rem = this.rem; - long pos = this.pos; + ensureOpenOrZipException(); + initDataOffset(); if (rem == 0) { return -1; } + if (len > rem) { + len = (int) rem; + } if (len <= 0) { return 0; } - if (len > rem) { - len = (int) rem; - } - - // Check if ZipFile open - ensureOpenOrZipException(); - len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b, - off, len); + len = ZipFile.this.zsrc.readAt(b, off, len, pos); if (len > 0) { - this.pos = (pos + len); - this.rem = (rem - len); + pos += len; + rem -= len; } } if (rem == 0) { @@ -742,11 +763,16 @@ } } - public long skip(long n) { - if (n > rem) - n = rem; - pos += n; - rem -= n; + public long skip(long n) throws IOException { + synchronized (ZipFile.this) { + ensureOpenOrZipException(); + initDataOffset(); + if (n > rem) { + n = rem; + } + pos += n; + rem -= n; + } if (rem == 0) { close(); } @@ -762,17 +788,11 @@ } public void close() { - if (zfisCloseRequested) + if (closeRequested) { return; - zfisCloseRequested = true; - + } + closeRequested = true; rem = 0; - synchronized (ZipFile.this) { - if (jzentry != 0 && ZipFile.this.jzfile != 0) { - freeEntry(ZipFile.this.jzfile, jzentry); - jzentry = 0; - } - } synchronized (streams) { streams.remove(this); } @@ -787,40 +807,502 @@ SharedSecrets.setJavaUtilZipFileAccess( new JavaUtilZipFileAccess() { public boolean startsWithLocHeader(ZipFile zip) { - return zip.startsWithLocHeader(); + return zip.zsrc.startsWithLoc; } - } + public String[] getMetaInfEntryNames(ZipFile zip) { + return zip.getMetaInfEntryNames(); + } + } ); } - /** - * Returns {@code true} if, and only if, the zip file begins with {@code - * LOCSIG}. + /* + * Returns an array of strings representing the names of all entries + * that begin with "META-INF/" (case ignored). This method is used + * in JarFile, via SharedSecrets, as an optimization when looking up + * manifest and signature file entries. Returns null if no entries + * were found. */ - private boolean startsWithLocHeader() { - return locsig; + private String[] getMetaInfEntryNames() { + synchronized (this) { + ensureOpen(); + if (zsrc.metanames.size() == 0) { + return null; + } + String[] names = new String[zsrc.metanames.size()]; + byte[] cen = zsrc.cen; + for (int i = 0; i < names.length; i++) { + int pos = zsrc.metanames.get(i); + names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos), + StandardCharsets.UTF_8); + } + return names; + } } - private static native long open(String name, int mode, long lastModified, - boolean usemmap) throws IOException; - private static native int getTotal(long jzfile); - private static native boolean startsWithLOC(long jzfile); - private static native int read(long jzfile, long jzentry, - long pos, byte[] b, int off, int len); + private static class Source { + private final Key key; // the key in files + private int refs = 1; + + private RandomAccessFile zfile; // zfile of the underlying zip file + private byte[] cen; // CEN & ENDHDR + private long locpos; // position of first LOC header (usually 0) + private byte[] comment; // zip file comment + // list of meta entries in META-INF dir + private ArrayList<Integer> metanames = new ArrayList<>(); + private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true) + + // A Hashmap for all entries. + // + // A cen entry of Zip/JAR file. As we have one for every entry in every active Zip/JAR, + // We might have a lot of these in a typical system. In order to save space we don't + // keep the name in memory, but merely remember a 32 bit {@code hash} value of the + // entry name and its offset {@code pos} in the central directory hdeader. + // + // private static class Entry { + // int hash; // 32 bit hashcode on name + // int next; // hash chain: index into entries + // int pos; // Offset of central directory file header + // } + // private Entry[] entries; // array of hashed cen entry + // + // To reduce the total size of entries further, we use a int[] here to store 3 "int" + // {@code hash}, {@code next and {@code "pos for each entry. The entry can then be + // referred by their index of their positions in the {@code entries}. + // + private int[] entries; // array of hashed cen entry + private int addEntry(int index, int hash, int next, int pos) { + entries[index++] = hash; + entries[index++] = next; + entries[index++] = pos; + return index; + } + private int getEntryHash(int index) { return entries[index]; } + private int getEntryNext(int index) { return entries[index + 1]; } + private int getEntryPos(int index) { return entries[index + 2]; } + private static final int ZIP_ENDCHAIN = -1; + private int total; // total number of entries + private int[] table; // Hash chain heads: indexes into entries + private int tablelen; // number of hash heads + + private static class Key { + BasicFileAttributes attrs; + File file; + + public Key(File file, BasicFileAttributes attrs) { + this.attrs = attrs; + this.file = file; + } + + public int hashCode() { + long t = attrs.lastModifiedTime().toMillis(); + return ((int)(t ^ (t >>> 32))) + file.hashCode(); + } + + public boolean equals(Object obj) { + if (obj instanceof Key) { + Key key = (Key)obj; + if (!attrs.lastModifiedTime().equals(key.attrs.lastModifiedTime())) { + return false; + } + Object fk = attrs.fileKey(); + if (fk != null) { + return fk.equals(key.attrs.fileKey()); + } else { + return file.equals(key.file); + } + } + return false; + } + } + private static final HashMap<Key, Source> files = new HashMap<>(); + + + public static Source get(File file, boolean toDelete) throws IOException { + Key key = new Key(file, + Files.readAttributes(file.toPath(), BasicFileAttributes.class)); + Source src = null; + synchronized (files) { + src = files.get(key); + if (src != null) { + src.refs++; + return src; + } + } + src = new Source(key, toDelete); + + synchronized (files) { + if (files.containsKey(key)) { // someone else put in first + src.close(); // close the newly created one + src = files.get(key); + src.refs++; + return src; + } + files.put(key, src); + return src; + } + } + + private static void close(Source src) throws IOException { + synchronized (files) { + if (--src.refs == 0) { + files.remove(src.key); + src.close(); + } + } + } + + private Source(Key key, boolean toDelete) throws IOException { + this.key = key; + this.zfile = new RandomAccessFile(key.file, "r"); + if (toDelete) { + key.file.delete(); + } + try { + initCEN(-1); + byte[] buf = new byte[4]; + readFullyAt(buf, 0, 4, 0); + this.startsWithLoc = (LOCSIG(buf) == LOCSIG); + } catch (IOException x) { + try { + this.zfile.close(); + } catch (IOException xx) {} + throw x; + } + } + + private void close() throws IOException { + zfile.close(); + zfile = null; + cen = null; + entries = null; + table = null; + metanames = null; + } + + private static final int BUF_SIZE = 8192; + private final int readFullyAt(byte[] buf, int off, int len, long pos) + throws IOException + { + synchronized(zfile) { + zfile.seek(pos); + int N = len; + while (N > 0) { + int n = Math.min(BUF_SIZE, N); + zfile.readFully(buf, off, n); + off += n; + N -= n; + } + return len; + } + } + + private final int readAt(byte[] buf, int off, int len, long pos) + throws IOException + { + synchronized(zfile) { + zfile.seek(pos); + return zfile.read(buf, off, len); + } + } + + private static final int hashN(byte[] a, int off, int len) { + int h = 1; + while (len-- > 0) { + h = 31 * h + a[off++]; + } + return h; + } + + private static final int hash_append(int hash, byte b) { + return hash * 31 + b; + } + + private static class End { + int centot; // 4 bytes + long cenlen; // 4 bytes + long cenoff; // 4 bytes + long endpos; // 4 bytes + } - // access to the native zentry object - private static native long getEntryTime(long jzentry); - private static native long getEntryCrc(long jzentry); - private static native long getEntryCSize(long jzentry); - private static native long getEntrySize(long jzentry); - private static native int getEntryMethod(long jzentry); - private static native int getEntryFlag(long jzentry); - private static native byte[] getCommentBytes(long jzfile); + /* + * Searches for end of central directory (END) header. The contents of + * the END header will be read and placed in endbuf. Returns the file + * position of the END header, otherwise returns -1 if the END header + * was not found or an error occurred. + */ + private End findEND() throws IOException { + long ziplen = zfile.length(); + if (ziplen <= 0) + zerror("zip file is empty"); + End end = new End(); + byte[] buf = new byte[READBLOCKSZ]; + long minHDR = (ziplen - END_MAXLEN) > 0 ? ziplen - END_MAXLEN : 0; + long minPos = minHDR - (buf.length - ENDHDR); + for (long pos = ziplen - buf.length; pos >= minPos; pos -= (buf.length - ENDHDR)) { + int off = 0; + if (pos < 0) { + // Pretend there are some NUL bytes before start of file + off = (int)-pos; + Arrays.fill(buf, 0, off, (byte)0); + } + int len = buf.length - off; + if (readFullyAt(buf, off, len, pos + off) != len ) { + zerror("zip END header not found"); + } + // Now scan the block backwards for END header signature + for (int i = buf.length - ENDHDR; i >= 0; i--) { + if (buf[i+0] == (byte)'P' && + buf[i+1] == (byte)'K' && + buf[i+2] == (byte)'\005' && + buf[i+3] == (byte)'\006') { + // Found ENDSIG header + byte[] endbuf = Arrays.copyOfRange(buf, i, i + ENDHDR); + end.centot = ENDTOT(endbuf); + end.cenlen = ENDSIZ(endbuf); + end.cenoff = ENDOFF(endbuf); + end.endpos = pos + i; + int comlen = ENDCOM(endbuf); + if (end.endpos + ENDHDR + comlen != ziplen) { + // ENDSIG matched, however the size of file comment in it does + // not match the real size. One "common" cause for this problem + // is some "extra" bytes are padded at the end of the zipfile. + // Let's do some extra verification, we don't care about the + // performance in this situation. + byte[] sbuf = new byte[4]; + long cenpos = end.endpos - end.cenlen; + long locpos = cenpos - end.cenoff; + if (cenpos < 0 || + locpos < 0 || + readFullyAt(sbuf, 0, sbuf.length, cenpos) != 4 || + GETSIG(sbuf) != CENSIG || + readFullyAt(sbuf, 0, sbuf.length, locpos) != 4 || + GETSIG(sbuf) != LOCSIG) { + continue; + } + } + if (comlen > 0) { // this zip file has comlen + comment = new byte[comlen]; + if (readFullyAt(comment, 0, comlen, end.endpos + ENDHDR) != comlen) { + zerror("zip comment read failed"); + } + } + if (end.cenlen == ZIP64_MAGICVAL || + end.cenoff == ZIP64_MAGICVAL || + end.centot == ZIP64_MAGICCOUNT) + { + // need to find the zip64 end; + try { + byte[] loc64 = new byte[ZIP64_LOCHDR]; + if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR) + != loc64.length || GETSIG(loc64) != ZIP64_LOCSIG) { + return end; + } + long end64pos = ZIP64_LOCOFF(loc64); + byte[] end64buf = new byte[ZIP64_ENDHDR]; + if (readFullyAt(end64buf, 0, end64buf.length, end64pos) + != end64buf.length || GETSIG(end64buf) != ZIP64_ENDSIG) { + return end; + } + // end64 found, re-calcualte everything. + end.cenlen = ZIP64_ENDSIZ(end64buf); + end.cenoff = ZIP64_ENDOFF(end64buf); + end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g + end.endpos = end64pos; + } catch (IOException x) {} // no zip64 loc/end + } + return end; + } + } + } + zerror("zip END header not found"); + return null; //make compiler happy + } + + // Reads zip file central directory. + private void initCEN(int knownTotal) throws IOException { + if (knownTotal == -1) { + End end = findEND(); + if (end.endpos == 0) { + locpos = 0; + total = 0; + entries = new int[0]; + cen = null; + return; // only END header present + } + if (end.cenlen > end.endpos) + zerror("invalid END header (bad central directory size)"); + long cenpos = end.endpos - end.cenlen; // position of CEN table + // Get position of first local file (LOC) header, taking into + // account that there may be a stub prefixed to the zip file. + locpos = cenpos - end.cenoff; + if (locpos < 0) { + zerror("invalid END header (bad central directory offset)"); + } + // read in the CEN and END + cen = new byte[(int)(end.cenlen + ENDHDR)]; + if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { + zerror("read CEN tables failed"); + } + total = end.centot; + } else { + total = knownTotal; + } + // hash table for entries + entries = new int[total * 3]; + tablelen = ((total/2) | 1); // Odd -> fewer collisions + table = new int[tablelen]; + Arrays.fill(table, ZIP_ENDCHAIN); + int idx = 0; + int hash = 0; + int next = -1; + + // list for all meta entries + metanames = new ArrayList<>(); - private static final int JZENTRY_NAME = 0; - private static final int JZENTRY_EXTRA = 1; - private static final int JZENTRY_COMMENT = 2; - private static native byte[] getEntryBytes(long jzentry, int type); + // Iterate through the entries in the central directory + int i = 0; + int hsh = 0; + int pos = 0; + int limit = cen.length - ENDHDR; + while (pos + CENHDR <= limit) { + if (i >= total) { + // This will only happen if the zip file has an incorrect + // ENDTOT field, which usually means it contains more than + // 65535 entries. + initCEN(countCENHeaders(cen, limit)); + return; + } + if (CENSIG(cen, pos) != CENSIG) + zerror("invalid CEN header (bad signature)"); + int method = CENHOW(cen, pos); + int nlen = CENNAM(cen, pos); + int elen = CENEXT(cen, pos); + int clen = CENCOM(cen, pos); + if ((CENFLG(cen, pos) & 1) != 0) + zerror("invalid CEN header (encrypted entry)"); + if (method != STORED && method != DEFLATED) + zerror("invalid CEN header (bad compression method: " + method + ")"); + if (pos + CENHDR + nlen > limit) + zerror("invalid CEN header (bad header size)"); + // Record the CEN offset and the name hash in our hash cell. + hash = hashN(cen, pos + CENHDR, nlen); + hsh = (hash & 0x7fffffff) % tablelen; + next = table[hsh]; + table[hsh] = idx; + idx = addEntry(idx, hash, next, pos); + // Adds name to metanames. + if (isMetaName(cen, pos + CENHDR, nlen)) { + metanames.add(pos); + } + // skip ext and comment + pos += (CENHDR + nlen + elen + clen); + i++; + } + total = i; + if (pos + ENDHDR != cen.length) { + zerror("invalid CEN header (bad header size)"); + } + } + + private static void zerror(String msg) throws ZipException { + throw new ZipException(msg); + } - private static native String getZipMessage(long jzfile); + /* + * Returns the {@code pos} of the zip cen entry corresponding to the + * specified entry name, or -1 if not found. + */ + private int getEntryPos(byte[] name, boolean addSlash) { + if (total == 0) { + return -1; + } + int hsh = hashN(name, 0, name.length); + int idx = table[(hsh & 0x7fffffff) % tablelen]; + /* + * This while loop is an optimization where a double lookup + * for name and name+/ is being performed. The name char + * array has enough room at the end to try again with a + * slash appended if the first table lookup does not succeed. + */ + while(true) { + /* + * Search down the target hash chain for a entry whose + * 32 bit hash matches the hashed name. + */ + while (idx != ZIP_ENDCHAIN) { + if (getEntryHash(idx) == hsh) { + // The CEN name must match the specfied one + int pos = getEntryPos(idx); + if (name.length == CENNAM(cen, pos)) { + boolean matched = true; + int nameoff = pos + CENHDR; + for (int i = 0; i < name.length; i++) { + if (name[i] != cen[nameoff++]) { + matched = false; + break; + } + } + if (matched) { + return pos; + } + } + } + idx = getEntryNext(idx); + } + /* If not addSlash, or slash is already there, we are done */ + if (!addSlash || name[name.length - 1] == '/') { + return -1; + } + /* Add slash and try once more */ + name = Arrays.copyOf(name, name.length + 1); + name[name.length - 1] = '/'; + hsh = hash_append(hsh, (byte)'/'); + //idx = table[hsh % tablelen]; + idx = table[(hsh & 0x7fffffff) % tablelen]; + addSlash = false; + } + } + + private static byte[] metainf = new byte[] { + 'M', 'E', 'T', 'A', '-', 'I' , 'N', 'F', '/', + }; + + /* + * Returns true if the specified entry's name begins with the string + * "META-INF/" irrespective of case. + */ + private static boolean isMetaName(byte[] name, int off, int len) { + if (len < 9 || (name[off] != 'M' && name[off] != 'm')) { // sizeof("META-INF/") - 1 + return false; + } + off++; + for (int i = 1; i < metainf.length; i++) { + byte c = name[off++]; + // Avoid toupper; it's locale-dependent + if (c >= 'a' && c <= 'z') { + c += 'A' - 'a'; + } + if (metainf[i] != c) { + return false; + } + } + return true; + } + + /* + * Counts the number of CEN headers in a central directory extending + * from BEG to END. Might return a bogus answer if the zip file is + * corrupt, but will not crash. + */ + static int countCENHeaders(byte[] cen, int end) { + int count = 0; + int pos = 0; + while (pos + CENHDR <= end) { + count++; + pos += (CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos)); + } + return count; + } + } }
--- a/src/java.base/share/classes/java/util/zip/ZipUtils.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/java/util/zip/ZipUtils.java Tue Dec 22 13:41:12 2015 -0800 @@ -31,6 +31,8 @@ import java.time.ZoneId; import java.util.concurrent.TimeUnit; +import static java.util.zip.ZipConstants.ENDHDR; + class ZipUtils { // used to adjust values between Windows and java epoch @@ -133,7 +135,7 @@ * The bytes are assumed to be in Intel (little-endian) byte order. */ public static final int get16(byte b[], int off) { - return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8); + return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8); } /** @@ -160,4 +162,79 @@ public static final int get32S(byte b[], int off) { return (get16(b, off) | (get16(b, off+2) << 16)); } + + // fields access methods + static final int CH(byte[] b, int n) { + return b[n] & 0xff ; + } + + static final int SH(byte[] b, int n) { + return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8); + } + + static final long LG(byte[] b, int n) { + return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL; + } + + static final long LL(byte[] b, int n) { + return (LG(b, n)) | (LG(b, n + 4) << 32); + } + + static final long GETSIG(byte[] b) { + return LG(b, 0); + } + + // local file (LOC) header fields + static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature + static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract + static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags + static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method + static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time + static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data + static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size + static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size + static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length + static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length + + // extra local (EXT) header fields + static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data + static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size + static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size + + // end of central directory header (END) fields + static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk + static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries + static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size + static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset + static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment + static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);} + + // zip64 end of central directory recoder fields + static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk + static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries + static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size + static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset + static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset + + // central directory header (CEN) fields + static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); } + static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); } + static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); } + static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); } + static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);} + static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);} + static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);} + static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);} + static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);} + static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);} + static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);} + static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);} + static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);} + static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);} + static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);} + static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);} + + // The END header is followed by a variable length comment of size < 64k. + static final long END_MAXLEN = 0xFFFF + ENDHDR; + static final int READBLOCKSZ = 128; }
--- a/src/java.base/share/classes/jdk/internal/misc/JavaUtilZipFileAccess.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/jdk/internal/misc/JavaUtilZipFileAccess.java Tue Dec 22 13:41:12 2015 -0800 @@ -29,5 +29,6 @@ public interface JavaUtilZipFileAccess { public boolean startsWithLocHeader(ZipFile zip); + public String[] getMetaInfEntryNames(ZipFile zip); }
--- a/src/java.base/share/classes/sun/misc/BASE64Decoder.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* - * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.misc; - -import java.io.OutputStream; -import java.io.PushbackInputStream; -import java.io.PrintStream; - -/** - * This class implements a BASE64 Character decoder as specified in RFC1521. - * - * This RFC is part of the MIME specification which is published by the - * Internet Engineering Task Force (IETF). Unlike some other encoding - * schemes there is nothing in this encoding that tells the decoder - * where a buffer starts or stops, so to use it you will need to isolate - * your encoded data into a single chunk and then feed them this decoder. - * The simplest way to do that is to read all of the encoded data into a - * string and then use: - * <pre> - * byte mydata[]; - * BASE64Decoder base64 = new BASE64Decoder(); - * - * mydata = base64.decodeBuffer(bufferString); - * </pre> - * This will decode the String in <i>bufferString</i> and give you an array - * of bytes in the array <i>myData</i>. - * - * On errors, this class throws a CEFormatException with the following detail - * strings: - * <pre> - * "BASE64Decoder: Not enough bytes for an atom." - * </pre> - * - * @author Chuck McManis - * @see CharacterEncoder - * @see BASE64Decoder - */ - -public class BASE64Decoder extends CharacterDecoder { - - /** This class has 4 bytes per atom */ - protected int bytesPerAtom() { - return (4); - } - - /** Any multiple of 4 will do, 72 might be common */ - protected int bytesPerLine() { - return (72); - } - - /** - * This character array provides the character to value map - * based on RFC1521. - */ - private static final char pem_array[] = { - // 0 1 2 3 4 5 6 7 - 'A','B','C','D','E','F','G','H', // 0 - 'I','J','K','L','M','N','O','P', // 1 - 'Q','R','S','T','U','V','W','X', // 2 - 'Y','Z','a','b','c','d','e','f', // 3 - 'g','h','i','j','k','l','m','n', // 4 - 'o','p','q','r','s','t','u','v', // 5 - 'w','x','y','z','0','1','2','3', // 6 - '4','5','6','7','8','9','+','/' // 7 - }; - - private static final byte pem_convert_array[] = new byte[256]; - - static { - for (int i = 0; i < 255; i++) { - pem_convert_array[i] = -1; - } - for (int i = 0; i < pem_array.length; i++) { - pem_convert_array[pem_array[i]] = (byte) i; - } - } - - byte decode_buffer[] = new byte[4]; - - /** - * Decode one BASE64 atom into 1, 2, or 3 bytes of data. - */ - @SuppressWarnings("fallthrough") - protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int rem) - throws java.io.IOException - { - int i; - byte a = -1, b = -1, c = -1, d = -1; - - if (rem < 2) { - throw new CEFormatException("BASE64Decoder: Not enough bytes for an atom."); - } - do { - i = inStream.read(); - if (i == -1) { - throw new CEStreamExhausted(); - } - } while (i == '\n' || i == '\r'); - decode_buffer[0] = (byte) i; - - i = readFully(inStream, decode_buffer, 1, rem-1); - if (i == -1) { - throw new CEStreamExhausted(); - } - - if (rem > 3 && decode_buffer[3] == '=') { - rem = 3; - } - if (rem > 2 && decode_buffer[2] == '=') { - rem = 2; - } - switch (rem) { - case 4: - d = pem_convert_array[decode_buffer[3] & 0xff]; - // NOBREAK - case 3: - c = pem_convert_array[decode_buffer[2] & 0xff]; - // NOBREAK - case 2: - b = pem_convert_array[decode_buffer[1] & 0xff]; - a = pem_convert_array[decode_buffer[0] & 0xff]; - break; - } - - switch (rem) { - case 2: - outStream.write( (byte)(((a << 2) & 0xfc) | ((b >>> 4) & 3)) ); - break; - case 3: - outStream.write( (byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)) ); - outStream.write( (byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)) ); - break; - case 4: - outStream.write( (byte) (((a << 2) & 0xfc) | ((b >>> 4) & 3)) ); - outStream.write( (byte) (((b << 4) & 0xf0) | ((c >>> 2) & 0xf)) ); - outStream.write( (byte) (((c << 6) & 0xc0) | (d & 0x3f)) ); - break; - } - return; - } -}
--- a/src/java.base/share/classes/sun/misc/BASE64Encoder.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (c) 1995, 1997, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.misc; - -import java.io.OutputStream; -import java.io.InputStream; -import java.io.PrintStream; -import java.io.IOException; - -/** - * This class implements a BASE64 Character encoder as specified in RFC1521. - * This RFC is part of the MIME specification as published by the Internet - * Engineering Task Force (IETF). Unlike some other encoding schemes there - * is nothing in this encoding that indicates - * where a buffer starts or ends. - * - * This means that the encoded text will simply start with the first line - * of encoded text and end with the last line of encoded text. - * - * @author Chuck McManis - * @see CharacterEncoder - * @see BASE64Decoder - */ - -public class BASE64Encoder extends CharacterEncoder { - - /** this class encodes three bytes per atom. */ - protected int bytesPerAtom() { - return (3); - } - - /** - * this class encodes 57 bytes per line. This results in a maximum - * of 57/3 * 4 or 76 characters per output line. Not counting the - * line termination. - */ - protected int bytesPerLine() { - return (57); - } - - /** This array maps the characters to their 6 bit values */ - private static final char pem_array[] = { - // 0 1 2 3 4 5 6 7 - 'A','B','C','D','E','F','G','H', // 0 - 'I','J','K','L','M','N','O','P', // 1 - 'Q','R','S','T','U','V','W','X', // 2 - 'Y','Z','a','b','c','d','e','f', // 3 - 'g','h','i','j','k','l','m','n', // 4 - 'o','p','q','r','s','t','u','v', // 5 - 'w','x','y','z','0','1','2','3', // 6 - '4','5','6','7','8','9','+','/' // 7 - }; - - /** - * encodeAtom - Take three bytes of input and encode it as 4 - * printable characters. Note that if the length in len is less - * than three is encodes either one or two '=' signs to indicate - * padding characters. - */ - protected void encodeAtom(OutputStream outStream, byte data[], int offset, int len) - throws IOException { - byte a, b, c; - - if (len == 1) { - a = data[offset]; - b = 0; - c = 0; - outStream.write(pem_array[(a >>> 2) & 0x3F]); - outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); - outStream.write('='); - outStream.write('='); - } else if (len == 2) { - a = data[offset]; - b = data[offset+1]; - c = 0; - outStream.write(pem_array[(a >>> 2) & 0x3F]); - outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); - outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]); - outStream.write('='); - } else { - a = data[offset]; - b = data[offset+1]; - c = data[offset+2]; - outStream.write(pem_array[(a >>> 2) & 0x3F]); - outStream.write(pem_array[((a << 4) & 0x30) + ((b >>> 4) & 0xf)]); - outStream.write(pem_array[((b << 2) & 0x3c) + ((c >>> 6) & 0x3)]); - outStream.write(pem_array[c & 0x3F]); - } - } -}
--- a/src/java.base/share/classes/sun/misc/CharacterDecoder.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.io.OutputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.PushbackInputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * This class defines the decoding half of character encoders. - * A character decoder is an algorithim for transforming 8 bit - * binary data that has been encoded into text by a character - * encoder, back into original binary form. - * - * The character encoders, in general, have been structured - * around a central theme that binary data can be encoded into - * text that has the form: - * - * <pre> - * [Buffer Prefix] - * [Line Prefix][encoded data atoms][Line Suffix] - * [Buffer Suffix] - * </pre> - * - * Of course in the simplest encoding schemes, the buffer has no - * distinct prefix of suffix, however all have some fixed relationship - * between the text in an 'atom' and the binary data itself. - * - * In the CharacterEncoder and CharacterDecoder classes, one complete - * chunk of data is referred to as a <i>buffer</i>. Encoded buffers - * are all text, and decoded buffers (sometimes just referred to as - * buffers) are binary octets. - * - * To create a custom decoder, you must, at a minimum, overide three - * abstract methods in this class. - * <DL> - * <DD>bytesPerAtom which tells the decoder how many bytes to - * expect from decodeAtom - * <DD>decodeAtom which decodes the bytes sent to it as text. - * <DD>bytesPerLine which tells the encoder the maximum number of - * bytes per line. - * </DL> - * - * In general, the character decoders return error in the form of a - * CEFormatException. The syntax of the detail string is - * <pre> - * DecoderClassName: Error message. - * </pre> - * - * Several useful decoders have already been written and are - * referenced in the See Also list below. - * - * @author Chuck McManis - * @see CEFormatException - * @see CharacterEncoder - * @see UCDecoder - * @see UUDecoder - * @see BASE64Decoder - */ - -public abstract class CharacterDecoder { - - /** Return the number of bytes per atom of decoding */ - protected abstract int bytesPerAtom(); - - /** Return the maximum number of bytes that can be encoded per line */ - protected abstract int bytesPerLine(); - - /** decode the beginning of the buffer, by default this is a NOP. */ - protected void decodeBufferPrefix(PushbackInputStream aStream, OutputStream bStream) throws IOException { } - - /** decode the buffer suffix, again by default it is a NOP. */ - protected void decodeBufferSuffix(PushbackInputStream aStream, OutputStream bStream) throws IOException { } - - /** - * This method should return, if it knows, the number of bytes - * that will be decoded. Many formats such as uuencoding provide - * this information. By default we return the maximum bytes that - * could have been encoded on the line. - */ - protected int decodeLinePrefix(PushbackInputStream aStream, OutputStream bStream) throws IOException { - return (bytesPerLine()); - } - - /** - * This method post processes the line, if there are error detection - * or correction codes in a line, they are generally processed by - * this method. The simplest version of this method looks for the - * (newline) character. - */ - protected void decodeLineSuffix(PushbackInputStream aStream, OutputStream bStream) throws IOException { } - - /** - * This method does an actual decode. It takes the decoded bytes and - * writes them to the OutputStream. The integer <i>l</i> tells the - * method how many bytes are required. This is always {@literal <=} bytesPerAtom(). - */ - protected void decodeAtom(PushbackInputStream aStream, OutputStream bStream, int l) throws IOException { - throw new CEStreamExhausted(); - } - - /** - * This method works around the bizarre semantics of BufferedInputStream's - * read method. - */ - protected int readFully(InputStream in, byte buffer[], int offset, int len) - throws java.io.IOException { - for (int i = 0; i < len; i++) { - int q = in.read(); - if (q == -1) - return ((i == 0) ? -1 : i); - buffer[i+offset] = (byte)q; - } - return len; - } - - /** - * Decode the text from the InputStream and write the decoded - * octets to the OutputStream. This method runs until the stream - * is exhausted. - * @exception CEFormatException An error has occurred while decoding - * @exception CEStreamExhausted The input stream is unexpectedly out of data - */ - public void decodeBuffer(InputStream aStream, OutputStream bStream) throws IOException { - int i; - int totalBytes = 0; - - PushbackInputStream ps = new PushbackInputStream (aStream); - decodeBufferPrefix(ps, bStream); - while (true) { - int length; - - try { - length = decodeLinePrefix(ps, bStream); - for (i = 0; (i+bytesPerAtom()) < length; i += bytesPerAtom()) { - decodeAtom(ps, bStream, bytesPerAtom()); - totalBytes += bytesPerAtom(); - } - if ((i + bytesPerAtom()) == length) { - decodeAtom(ps, bStream, bytesPerAtom()); - totalBytes += bytesPerAtom(); - } else { - decodeAtom(ps, bStream, length - i); - totalBytes += (length - i); - } - decodeLineSuffix(ps, bStream); - } catch (CEStreamExhausted e) { - break; - } - } - decodeBufferSuffix(ps, bStream); - } - - /** - * Alternate decode interface that takes a String containing the encoded - * buffer and returns a byte array containing the data. - * @exception CEFormatException An error has occurred while decoding - */ - public byte[] decodeBuffer(String inputString) throws IOException { - byte inputBuffer[] = inputString.getBytes("ISO-8859-1"); - ByteArrayInputStream inStream = new ByteArrayInputStream(inputBuffer); - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - decodeBuffer(inStream, outStream); - return outStream.toByteArray(); - } - - /** - * Decode the contents of the inputstream into a buffer. - */ - public byte[] decodeBuffer(InputStream in) throws IOException { - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - decodeBuffer(in, outStream); - return outStream.toByteArray(); - } - - /** - * Decode the contents of the String into a ByteBuffer. - */ - public ByteBuffer decodeBufferToByteBuffer(String inputString) - throws IOException { - return ByteBuffer.wrap(decodeBuffer(inputString)); - } - - /** - * Decode the contents of the inputStream into a ByteBuffer. - */ - public ByteBuffer decodeBufferToByteBuffer(InputStream in) - throws IOException { - return ByteBuffer.wrap(decodeBuffer(in)); - } -}
--- a/src/java.base/share/classes/sun/misc/CharacterEncoder.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,354 +0,0 @@ -/* - * Copyright (c) 1995, 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.io.InputStream; -import java.io.ByteArrayInputStream; -import java.io.OutputStream; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.io.IOException; -import java.nio.ByteBuffer; - - -/** - * This class defines the encoding half of character encoders. - * A character encoder is an algorithim for transforming 8 bit binary - * data into text (generally 7 bit ASCII or 8 bit ISO-Latin-1 text) - * for transmition over text channels such as e-mail and network news. - * - * The character encoders have been structured around a central theme - * that, in general, the encoded text has the form: - * - * <pre> - * [Buffer Prefix] - * [Line Prefix][encoded data atoms][Line Suffix] - * [Buffer Suffix] - * </pre> - * - * In the CharacterEncoder and CharacterDecoder classes, one complete - * chunk of data is referred to as a <i>buffer</i>. Encoded buffers - * are all text, and decoded buffers (sometimes just referred to as - * buffers) are binary octets. - * - * To create a custom encoder, you must, at a minimum, overide three - * abstract methods in this class. - * <DL> - * <DD>bytesPerAtom which tells the encoder how many bytes to - * send to encodeAtom - * <DD>encodeAtom which encodes the bytes sent to it as text. - * <DD>bytesPerLine which tells the encoder the maximum number of - * bytes per line. - * </DL> - * - * Several useful encoders have already been written and are - * referenced in the See Also list below. - * - * @author Chuck McManis - * @see CharacterDecoder - * @see UCEncoder - * @see UUEncoder - * @see BASE64Encoder - */ -public abstract class CharacterEncoder { - - /** Stream that understands "printing" */ - protected PrintStream pStream; - - /** Return the number of bytes per atom of encoding */ - protected abstract int bytesPerAtom(); - - /** Return the number of bytes that can be encoded per line */ - protected abstract int bytesPerLine(); - - /** - * Encode the prefix for the entire buffer. By default is simply - * opens the PrintStream for use by the other functions. - */ - protected void encodeBufferPrefix(OutputStream aStream) throws IOException { - pStream = new PrintStream(aStream); - } - - /** - * Encode the suffix for the entire buffer. - */ - protected void encodeBufferSuffix(OutputStream aStream) throws IOException { - } - - /** - * Encode the prefix that starts every output line. - */ - protected void encodeLinePrefix(OutputStream aStream, int aLength) - throws IOException { - } - - /** - * Encode the suffix that ends every output line. By default - * this method just prints a newline into the output stream. - */ - protected void encodeLineSuffix(OutputStream aStream) throws IOException { - pStream.println(); - } - - /** Encode one "atom" of information into characters. */ - protected abstract void encodeAtom(OutputStream aStream, byte someBytes[], - int anOffset, int aLength) throws IOException; - - /** - * This method works around the bizarre semantics of BufferedInputStream's - * read method. - */ - protected int readFully(InputStream in, byte buffer[]) - throws java.io.IOException { - for (int i = 0; i < buffer.length; i++) { - int q = in.read(); - if (q == -1) - return i; - buffer[i] = (byte)q; - } - return buffer.length; - } - - /** - * Encode bytes from the input stream, and write them as text characters - * to the output stream. This method will run until it exhausts the - * input stream, but does not print the line suffix for a final - * line that is shorter than bytesPerLine(). - */ - public void encode(InputStream inStream, OutputStream outStream) - throws IOException { - int j; - int numBytes; - byte tmpbuffer[] = new byte[bytesPerLine()]; - - encodeBufferPrefix(outStream); - - while (true) { - numBytes = readFully(inStream, tmpbuffer); - if (numBytes == 0) { - break; - } - encodeLinePrefix(outStream, numBytes); - for (j = 0; j < numBytes; j += bytesPerAtom()) { - - if ((j + bytesPerAtom()) <= numBytes) { - encodeAtom(outStream, tmpbuffer, j, bytesPerAtom()); - } else { - encodeAtom(outStream, tmpbuffer, j, (numBytes)- j); - } - } - if (numBytes < bytesPerLine()) { - break; - } else { - encodeLineSuffix(outStream); - } - } - encodeBufferSuffix(outStream); - } - - /** - * Encode the buffer in <i>aBuffer</i> and write the encoded - * result to the OutputStream <i>aStream</i>. - */ - public void encode(byte aBuffer[], OutputStream aStream) - throws IOException { - ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer); - encode(inStream, aStream); - } - - /** - * A 'streamless' version of encode that simply takes a buffer of - * bytes and returns a string containing the encoded buffer. - */ - public String encode(byte aBuffer[]) { - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer); - String retVal = null; - try { - encode(inStream, outStream); - // explicit ascii->unicode conversion - retVal = outStream.toString("ISO-8859-1"); - } catch (Exception IOException) { - // This should never happen. - throw new Error("CharacterEncoder.encode internal error"); - } - return (retVal); - } - - /** - * Return a byte array from the remaining bytes in this ByteBuffer. - * <P> - * The ByteBuffer's position will be advanced to ByteBuffer's limit. - * <P> - * To avoid an extra copy, the implementation will attempt to return the - * byte array backing the ByteBuffer. If this is not possible, a - * new byte array will be created. - */ - private byte [] getBytes(ByteBuffer bb) { - /* - * This should never return a BufferOverflowException, as we're - * careful to allocate just the right amount. - */ - byte [] buf = null; - - /* - * If it has a usable backing byte buffer, use it. Use only - * if the array exactly represents the current ByteBuffer. - */ - if (bb.hasArray()) { - byte [] tmp = bb.array(); - if ((tmp.length == bb.capacity()) && - (tmp.length == bb.remaining())) { - buf = tmp; - bb.position(bb.limit()); - } - } - - if (buf == null) { - /* - * This class doesn't have a concept of encode(buf, len, off), - * so if we have a partial buffer, we must reallocate - * space. - */ - buf = new byte[bb.remaining()]; - - /* - * position() automatically updated - */ - bb.get(buf); - } - - return buf; - } - - /** - * Encode the <i>aBuffer</i> ByteBuffer and write the encoded - * result to the OutputStream <i>aStream</i>. - * <P> - * The ByteBuffer's position will be advanced to ByteBuffer's limit. - */ - public void encode(ByteBuffer aBuffer, OutputStream aStream) - throws IOException { - byte [] buf = getBytes(aBuffer); - encode(buf, aStream); - } - - /** - * A 'streamless' version of encode that simply takes a ByteBuffer - * and returns a string containing the encoded buffer. - * <P> - * The ByteBuffer's position will be advanced to ByteBuffer's limit. - */ - public String encode(ByteBuffer aBuffer) { - byte [] buf = getBytes(aBuffer); - return encode(buf); - } - - /** - * Encode bytes from the input stream, and write them as text characters - * to the output stream. This method will run until it exhausts the - * input stream. It differs from encode in that it will add the - * line at the end of a final line that is shorter than bytesPerLine(). - */ - public void encodeBuffer(InputStream inStream, OutputStream outStream) - throws IOException { - int j; - int numBytes; - byte tmpbuffer[] = new byte[bytesPerLine()]; - - encodeBufferPrefix(outStream); - - while (true) { - numBytes = readFully(inStream, tmpbuffer); - if (numBytes == 0) { - break; - } - encodeLinePrefix(outStream, numBytes); - for (j = 0; j < numBytes; j += bytesPerAtom()) { - if ((j + bytesPerAtom()) <= numBytes) { - encodeAtom(outStream, tmpbuffer, j, bytesPerAtom()); - } else { - encodeAtom(outStream, tmpbuffer, j, (numBytes)- j); - } - } - encodeLineSuffix(outStream); - if (numBytes < bytesPerLine()) { - break; - } - } - encodeBufferSuffix(outStream); - } - - /** - * Encode the buffer in <i>aBuffer</i> and write the encoded - * result to the OutputStream <i>aStream</i>. - */ - public void encodeBuffer(byte aBuffer[], OutputStream aStream) - throws IOException { - ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer); - encodeBuffer(inStream, aStream); - } - - /** - * A 'streamless' version of encode that simply takes a buffer of - * bytes and returns a string containing the encoded buffer. - */ - public String encodeBuffer(byte aBuffer[]) { - ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - ByteArrayInputStream inStream = new ByteArrayInputStream(aBuffer); - try { - encodeBuffer(inStream, outStream); - } catch (Exception IOException) { - // This should never happen. - throw new Error("CharacterEncoder.encodeBuffer internal error"); - } - return (outStream.toString()); - } - - /** - * Encode the <i>aBuffer</i> ByteBuffer and write the encoded - * result to the OutputStream <i>aStream</i>. - * <P> - * The ByteBuffer's position will be advanced to ByteBuffer's limit. - */ - public void encodeBuffer(ByteBuffer aBuffer, OutputStream aStream) - throws IOException { - byte [] buf = getBytes(aBuffer); - encodeBuffer(buf, aStream); - } - - /** - * A 'streamless' version of encode that simply takes a ByteBuffer - * and returns a string containing the encoded buffer. - * <P> - * The ByteBuffer's position will be advanced to ByteBuffer's limit. - */ - public String encodeBuffer(ByteBuffer aBuffer) { - byte [] buf = getBytes(aBuffer); - return encodeBuffer(buf); - } - -}
--- a/src/java.base/share/classes/sun/misc/GC.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/misc/GC.java Tue Dec 22 13:41:12 2015 -0800 @@ -82,7 +82,7 @@ */ public static native long maxObjectInspectionAge(); - private static class Daemon extends ManagedLocalsThread { + private static class Daemon extends Thread { public void run() { for (;;) { @@ -122,7 +122,7 @@ } private Daemon(ThreadGroup tg) { - super(tg, "GC Daemon"); + super(tg, null, "GC Daemon", 0L, false); } /* Create a new daemon thread in the root thread group */
--- a/src/java.base/share/classes/sun/misc/HexDumpEncoder.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,120 +0,0 @@ -/* - * Copyright (c) 1995, 1997, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package sun.misc; -import java.io.PrintStream; -import java.io.OutputStream; -import java.io.IOException; - -/** - * This class encodes a buffer into the classic: "Hexadecimal Dump" format of - * the past. It is useful for analyzing the contents of binary buffers. - * The format produced is as follows: - * <pre> - * xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff ................ - * </pre> - * Where xxxx is the offset into the buffer in 16 byte chunks, followed - * by ascii coded hexadecimal bytes followed by the ASCII representation of - * the bytes or '.' if they are not valid bytes. - * - * @author Chuck McManis - */ - -public class HexDumpEncoder extends CharacterEncoder { - - private int offset; - private int thisLineLength; - private int currentByte; - private byte thisLine[] = new byte[16]; - - static void hexDigit(PrintStream p, byte x) { - char c; - - c = (char) ((x >> 4) & 0xf); - if (c > 9) - c = (char) ((c-10) + 'A'); - else - c = (char)(c + '0'); - p.write(c); - c = (char) (x & 0xf); - if (c > 9) - c = (char)((c-10) + 'A'); - else - c = (char)(c + '0'); - p.write(c); - } - - protected int bytesPerAtom() { - return (1); - } - - protected int bytesPerLine() { - return (16); - } - - protected void encodeBufferPrefix(OutputStream o) throws IOException { - offset = 0; - super.encodeBufferPrefix(o); - } - - protected void encodeLinePrefix(OutputStream o, int len) throws IOException { - hexDigit(pStream, (byte)((offset >>> 8) & 0xff)); - hexDigit(pStream, (byte)(offset & 0xff)); - pStream.print(": "); - currentByte = 0; - thisLineLength = len; - } - - protected void encodeAtom(OutputStream o, byte buf[], int off, int len) throws IOException { - thisLine[currentByte] = buf[off]; - hexDigit(pStream, buf[off]); - pStream.print(" "); - currentByte++; - if (currentByte == 8) - pStream.print(" "); - } - - protected void encodeLineSuffix(OutputStream o) throws IOException { - if (thisLineLength < 16) { - for (int i = thisLineLength; i < 16; i++) { - pStream.print(" "); - if (i == 7) - pStream.print(" "); - } - } - pStream.print(" "); - for (int i = 0; i < thisLineLength; i++) { - if ((thisLine[i] < ' ') || (thisLine[i] > 'z')) { - pStream.print("."); - } else { - pStream.write(thisLine[i]); - } - } - pStream.println(); - offset += thisLineLength; - } - -}
--- a/src/java.base/share/classes/sun/misc/InnocuousThread.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/misc/InnocuousThread.java Tue Dec 22 13:41:12 2015 -0800 @@ -35,8 +35,10 @@ * A thread that has no permissions, is not a member of any user-defined * ThreadGroup and supports the ability to erase ThreadLocals. */ -public final class InnocuousThread extends ManagedLocalsThread { +public final class InnocuousThread extends Thread { private static final jdk.internal.misc.Unsafe UNSAFE; + private static final long THREAD_LOCALS; + private static final long INHERITABLE_THREAD_LOCALS; private static final ThreadGroup INNOCUOUSTHREADGROUP; private static final AccessControlContext ACC; private static final long INHERITEDACCESSCONTROLCONTEXT; @@ -54,7 +56,7 @@ } public InnocuousThread(ThreadGroup group, Runnable target, String name) { - super(group, target, name); + super(group, target, name, 0L, false); UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC); UNSAFE.putOrderedObject(this, CONTEXTCLASSLOADER, ClassLoader.getSystemClassLoader()); } @@ -73,6 +75,14 @@ throw new SecurityException("setContextClassLoader"); } + /** + * Drops all thread locals (and inherited thread locals). + */ + public final void eraseThreadLocals() { + UNSAFE.putObject(this, THREAD_LOCALS, null); + UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null); + } + // ensure run method is run only once private volatile boolean hasRun; @@ -96,6 +106,10 @@ Class<?> tk = Thread.class; Class<?> gk = ThreadGroup.class; + THREAD_LOCALS = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocals")); + INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset + (tk.getDeclaredField("inheritableThreadLocals")); INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset (tk.getDeclaredField("inheritedAccessControlContext")); CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset
--- a/src/java.base/share/classes/sun/misc/ProxyGenerator.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2031 +0,0 @@ -/* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import sun.security.action.GetBooleanAction; - -/** - * ProxyGenerator contains the code to generate a dynamic proxy class - * for the java.lang.reflect.Proxy API. - * - * The external interfaces to ProxyGenerator is the static - * "generateProxyClass" method. - * - * @author Peter Jones - * @since 1.3 - */ -public class ProxyGenerator { - /* - * In the comments below, "JVMS" refers to The Java Virtual Machine - * Specification Second Edition and "JLS" refers to the original - * version of The Java Language Specification, unless otherwise - * specified. - */ - - /* generate 1.5-era class file version */ - private static final int CLASSFILE_MAJOR_VERSION = 49; - private static final int CLASSFILE_MINOR_VERSION = 0; - - /* - * beginning of constants copied from - * sun.tools.java.RuntimeConstants (which no longer exists): - */ - - /* constant pool tags */ - private static final int CONSTANT_UTF8 = 1; - private static final int CONSTANT_UNICODE = 2; - private static final int CONSTANT_INTEGER = 3; - private static final int CONSTANT_FLOAT = 4; - private static final int CONSTANT_LONG = 5; - private static final int CONSTANT_DOUBLE = 6; - private static final int CONSTANT_CLASS = 7; - private static final int CONSTANT_STRING = 8; - private static final int CONSTANT_FIELD = 9; - private static final int CONSTANT_METHOD = 10; - private static final int CONSTANT_INTERFACEMETHOD = 11; - private static final int CONSTANT_NAMEANDTYPE = 12; - - /* access and modifier flags */ - private static final int ACC_PUBLIC = 0x00000001; - private static final int ACC_PRIVATE = 0x00000002; -// private static final int ACC_PROTECTED = 0x00000004; - private static final int ACC_STATIC = 0x00000008; - private static final int ACC_FINAL = 0x00000010; -// private static final int ACC_SYNCHRONIZED = 0x00000020; -// private static final int ACC_VOLATILE = 0x00000040; -// private static final int ACC_TRANSIENT = 0x00000080; -// private static final int ACC_NATIVE = 0x00000100; -// private static final int ACC_INTERFACE = 0x00000200; -// private static final int ACC_ABSTRACT = 0x00000400; - private static final int ACC_SUPER = 0x00000020; -// private static final int ACC_STRICT = 0x00000800; - - /* opcodes */ -// private static final int opc_nop = 0; - private static final int opc_aconst_null = 1; -// private static final int opc_iconst_m1 = 2; - private static final int opc_iconst_0 = 3; -// private static final int opc_iconst_1 = 4; -// private static final int opc_iconst_2 = 5; -// private static final int opc_iconst_3 = 6; -// private static final int opc_iconst_4 = 7; -// private static final int opc_iconst_5 = 8; -// private static final int opc_lconst_0 = 9; -// private static final int opc_lconst_1 = 10; -// private static final int opc_fconst_0 = 11; -// private static final int opc_fconst_1 = 12; -// private static final int opc_fconst_2 = 13; -// private static final int opc_dconst_0 = 14; -// private static final int opc_dconst_1 = 15; - private static final int opc_bipush = 16; - private static final int opc_sipush = 17; - private static final int opc_ldc = 18; - private static final int opc_ldc_w = 19; -// private static final int opc_ldc2_w = 20; - private static final int opc_iload = 21; - private static final int opc_lload = 22; - private static final int opc_fload = 23; - private static final int opc_dload = 24; - private static final int opc_aload = 25; - private static final int opc_iload_0 = 26; -// private static final int opc_iload_1 = 27; -// private static final int opc_iload_2 = 28; -// private static final int opc_iload_3 = 29; - private static final int opc_lload_0 = 30; -// private static final int opc_lload_1 = 31; -// private static final int opc_lload_2 = 32; -// private static final int opc_lload_3 = 33; - private static final int opc_fload_0 = 34; -// private static final int opc_fload_1 = 35; -// private static final int opc_fload_2 = 36; -// private static final int opc_fload_3 = 37; - private static final int opc_dload_0 = 38; -// private static final int opc_dload_1 = 39; -// private static final int opc_dload_2 = 40; -// private static final int opc_dload_3 = 41; - private static final int opc_aload_0 = 42; -// private static final int opc_aload_1 = 43; -// private static final int opc_aload_2 = 44; -// private static final int opc_aload_3 = 45; -// private static final int opc_iaload = 46; -// private static final int opc_laload = 47; -// private static final int opc_faload = 48; -// private static final int opc_daload = 49; -// private static final int opc_aaload = 50; -// private static final int opc_baload = 51; -// private static final int opc_caload = 52; -// private static final int opc_saload = 53; -// private static final int opc_istore = 54; -// private static final int opc_lstore = 55; -// private static final int opc_fstore = 56; -// private static final int opc_dstore = 57; - private static final int opc_astore = 58; -// private static final int opc_istore_0 = 59; -// private static final int opc_istore_1 = 60; -// private static final int opc_istore_2 = 61; -// private static final int opc_istore_3 = 62; -// private static final int opc_lstore_0 = 63; -// private static final int opc_lstore_1 = 64; -// private static final int opc_lstore_2 = 65; -// private static final int opc_lstore_3 = 66; -// private static final int opc_fstore_0 = 67; -// private static final int opc_fstore_1 = 68; -// private static final int opc_fstore_2 = 69; -// private static final int opc_fstore_3 = 70; -// private static final int opc_dstore_0 = 71; -// private static final int opc_dstore_1 = 72; -// private static final int opc_dstore_2 = 73; -// private static final int opc_dstore_3 = 74; - private static final int opc_astore_0 = 75; -// private static final int opc_astore_1 = 76; -// private static final int opc_astore_2 = 77; -// private static final int opc_astore_3 = 78; -// private static final int opc_iastore = 79; -// private static final int opc_lastore = 80; -// private static final int opc_fastore = 81; -// private static final int opc_dastore = 82; - private static final int opc_aastore = 83; -// private static final int opc_bastore = 84; -// private static final int opc_castore = 85; -// private static final int opc_sastore = 86; - private static final int opc_pop = 87; -// private static final int opc_pop2 = 88; - private static final int opc_dup = 89; -// private static final int opc_dup_x1 = 90; -// private static final int opc_dup_x2 = 91; -// private static final int opc_dup2 = 92; -// private static final int opc_dup2_x1 = 93; -// private static final int opc_dup2_x2 = 94; -// private static final int opc_swap = 95; -// private static final int opc_iadd = 96; -// private static final int opc_ladd = 97; -// private static final int opc_fadd = 98; -// private static final int opc_dadd = 99; -// private static final int opc_isub = 100; -// private static final int opc_lsub = 101; -// private static final int opc_fsub = 102; -// private static final int opc_dsub = 103; -// private static final int opc_imul = 104; -// private static final int opc_lmul = 105; -// private static final int opc_fmul = 106; -// private static final int opc_dmul = 107; -// private static final int opc_idiv = 108; -// private static final int opc_ldiv = 109; -// private static final int opc_fdiv = 110; -// private static final int opc_ddiv = 111; -// private static final int opc_irem = 112; -// private static final int opc_lrem = 113; -// private static final int opc_frem = 114; -// private static final int opc_drem = 115; -// private static final int opc_ineg = 116; -// private static final int opc_lneg = 117; -// private static final int opc_fneg = 118; -// private static final int opc_dneg = 119; -// private static final int opc_ishl = 120; -// private static final int opc_lshl = 121; -// private static final int opc_ishr = 122; -// private static final int opc_lshr = 123; -// private static final int opc_iushr = 124; -// private static final int opc_lushr = 125; -// private static final int opc_iand = 126; -// private static final int opc_land = 127; -// private static final int opc_ior = 128; -// private static final int opc_lor = 129; -// private static final int opc_ixor = 130; -// private static final int opc_lxor = 131; -// private static final int opc_iinc = 132; -// private static final int opc_i2l = 133; -// private static final int opc_i2f = 134; -// private static final int opc_i2d = 135; -// private static final int opc_l2i = 136; -// private static final int opc_l2f = 137; -// private static final int opc_l2d = 138; -// private static final int opc_f2i = 139; -// private static final int opc_f2l = 140; -// private static final int opc_f2d = 141; -// private static final int opc_d2i = 142; -// private static final int opc_d2l = 143; -// private static final int opc_d2f = 144; -// private static final int opc_i2b = 145; -// private static final int opc_i2c = 146; -// private static final int opc_i2s = 147; -// private static final int opc_lcmp = 148; -// private static final int opc_fcmpl = 149; -// private static final int opc_fcmpg = 150; -// private static final int opc_dcmpl = 151; -// private static final int opc_dcmpg = 152; -// private static final int opc_ifeq = 153; -// private static final int opc_ifne = 154; -// private static final int opc_iflt = 155; -// private static final int opc_ifge = 156; -// private static final int opc_ifgt = 157; -// private static final int opc_ifle = 158; -// private static final int opc_if_icmpeq = 159; -// private static final int opc_if_icmpne = 160; -// private static final int opc_if_icmplt = 161; -// private static final int opc_if_icmpge = 162; -// private static final int opc_if_icmpgt = 163; -// private static final int opc_if_icmple = 164; -// private static final int opc_if_acmpeq = 165; -// private static final int opc_if_acmpne = 166; -// private static final int opc_goto = 167; -// private static final int opc_jsr = 168; -// private static final int opc_ret = 169; -// private static final int opc_tableswitch = 170; -// private static final int opc_lookupswitch = 171; - private static final int opc_ireturn = 172; - private static final int opc_lreturn = 173; - private static final int opc_freturn = 174; - private static final int opc_dreturn = 175; - private static final int opc_areturn = 176; - private static final int opc_return = 177; - private static final int opc_getstatic = 178; - private static final int opc_putstatic = 179; - private static final int opc_getfield = 180; -// private static final int opc_putfield = 181; - private static final int opc_invokevirtual = 182; - private static final int opc_invokespecial = 183; - private static final int opc_invokestatic = 184; - private static final int opc_invokeinterface = 185; - private static final int opc_new = 187; -// private static final int opc_newarray = 188; - private static final int opc_anewarray = 189; -// private static final int opc_arraylength = 190; - private static final int opc_athrow = 191; - private static final int opc_checkcast = 192; -// private static final int opc_instanceof = 193; -// private static final int opc_monitorenter = 194; -// private static final int opc_monitorexit = 195; - private static final int opc_wide = 196; -// private static final int opc_multianewarray = 197; -// private static final int opc_ifnull = 198; -// private static final int opc_ifnonnull = 199; -// private static final int opc_goto_w = 200; -// private static final int opc_jsr_w = 201; - - // end of constants copied from sun.tools.java.RuntimeConstants - - /** name of the superclass of proxy classes */ - private static final String superclassName = "java/lang/reflect/Proxy"; - - /** name of field for storing a proxy instance's invocation handler */ - private static final String handlerFieldName = "h"; - - /** debugging flag for saving generated class files */ - private static final boolean saveGeneratedFiles = - java.security.AccessController.doPrivileged( - new GetBooleanAction( - "sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue(); - - /** - * Generate a public proxy class given a name and a list of proxy interfaces. - */ - public static byte[] generateProxyClass(final String name, - Class<?>[] interfaces) { - return generateProxyClass(name, interfaces, (ACC_PUBLIC | ACC_FINAL | ACC_SUPER)); - } - - /** - * Generate a proxy class given a name and a list of proxy interfaces. - * - * @param name the class name of the proxy class - * @param interfaces proxy interfaces - * @param accessFlags access flags of the proxy class - */ - public static byte[] generateProxyClass(final String name, - Class<?>[] interfaces, - int accessFlags) - { - ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags); - final byte[] classFile = gen.generateClassFile(); - - if (saveGeneratedFiles) { - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction<Void>() { - public Void run() { - try { - int i = name.lastIndexOf('.'); - Path path; - if (i > 0) { - Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar)); - Files.createDirectories(dir); - path = dir.resolve(name.substring(i+1, name.length()) + ".class"); - } else { - path = Paths.get(name + ".class"); - } - Files.write(path, classFile); - return null; - } catch (IOException e) { - throw new InternalError( - "I/O exception saving generated file: " + e); - } - } - }); - } - - return classFile; - } - - /* preloaded Method objects for methods in java.lang.Object */ - private static Method hashCodeMethod; - private static Method equalsMethod; - private static Method toStringMethod; - static { - try { - hashCodeMethod = Object.class.getMethod("hashCode"); - equalsMethod = - Object.class.getMethod("equals", new Class<?>[] { Object.class }); - toStringMethod = Object.class.getMethod("toString"); - } catch (NoSuchMethodException e) { - throw new NoSuchMethodError(e.getMessage()); - } - } - - /** name of proxy class */ - private String className; - - /** proxy interfaces */ - private Class<?>[] interfaces; - - /** proxy class access flags */ - private int accessFlags; - - /** constant pool of class being generated */ - private ConstantPool cp = new ConstantPool(); - - /** FieldInfo struct for each field of generated class */ - private List<FieldInfo> fields = new ArrayList<>(); - - /** MethodInfo struct for each method of generated class */ - private List<MethodInfo> methods = new ArrayList<>(); - - /** - * maps method signature string to list of ProxyMethod objects for - * proxy methods with that signature - */ - private Map<String, List<ProxyMethod>> proxyMethods = new HashMap<>(); - - /** count of ProxyMethod objects added to proxyMethods */ - private int proxyMethodCount = 0; - - /** - * Construct a ProxyGenerator to generate a proxy class with the - * specified name and for the given interfaces. - * - * A ProxyGenerator object contains the state for the ongoing - * generation of a particular proxy class. - */ - private ProxyGenerator(String className, Class<?>[] interfaces, int accessFlags) { - this.className = className; - this.interfaces = interfaces; - this.accessFlags = accessFlags; - } - - /** - * Generate a class file for the proxy class. This method drives the - * class file generation process. - */ - private byte[] generateClassFile() { - - /* ============================================================ - * Step 1: Assemble ProxyMethod objects for all methods to - * generate proxy dispatching code for. - */ - - /* - * Record that proxy methods are needed for the hashCode, equals, - * and toString methods of java.lang.Object. This is done before - * the methods from the proxy interfaces so that the methods from - * java.lang.Object take precedence over duplicate methods in the - * proxy interfaces. - */ - addProxyMethod(hashCodeMethod, Object.class); - addProxyMethod(equalsMethod, Object.class); - addProxyMethod(toStringMethod, Object.class); - - /* - * Now record all of the methods from the proxy interfaces, giving - * earlier interfaces precedence over later ones with duplicate - * methods. - */ - for (Class<?> intf : interfaces) { - for (Method m : intf.getMethods()) { - addProxyMethod(m, intf); - } - } - - /* - * For each set of proxy methods with the same signature, - * verify that the methods' return types are compatible. - */ - for (List<ProxyMethod> sigmethods : proxyMethods.values()) { - checkReturnTypes(sigmethods); - } - - /* ============================================================ - * Step 2: Assemble FieldInfo and MethodInfo structs for all of - * fields and methods in the class we are generating. - */ - try { - methods.add(generateConstructor()); - - for (List<ProxyMethod> sigmethods : proxyMethods.values()) { - for (ProxyMethod pm : sigmethods) { - - // add static field for method's Method object - fields.add(new FieldInfo(pm.methodFieldName, - "Ljava/lang/reflect/Method;", - ACC_PRIVATE | ACC_STATIC)); - - // generate code for proxy method and add it - methods.add(pm.generateMethod()); - } - } - - methods.add(generateStaticInitializer()); - - } catch (IOException e) { - throw new InternalError("unexpected I/O Exception", e); - } - - if (methods.size() > 65535) { - throw new IllegalArgumentException("method limit exceeded"); - } - if (fields.size() > 65535) { - throw new IllegalArgumentException("field limit exceeded"); - } - - /* ============================================================ - * Step 3: Write the final class file. - */ - - /* - * Make sure that constant pool indexes are reserved for the - * following items before starting to write the final class file. - */ - cp.getClass(dotToSlash(className)); - cp.getClass(superclassName); - for (Class<?> intf: interfaces) { - cp.getClass(dotToSlash(intf.getName())); - } - - /* - * Disallow new constant pool additions beyond this point, since - * we are about to write the final constant pool table. - */ - cp.setReadOnly(); - - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - DataOutputStream dout = new DataOutputStream(bout); - - try { - /* - * Write all the items of the "ClassFile" structure. - * See JVMS section 4.1. - */ - // u4 magic; - dout.writeInt(0xCAFEBABE); - // u2 minor_version; - dout.writeShort(CLASSFILE_MINOR_VERSION); - // u2 major_version; - dout.writeShort(CLASSFILE_MAJOR_VERSION); - - cp.write(dout); // (write constant pool) - - // u2 access_flags; - dout.writeShort(accessFlags); - // u2 this_class; - dout.writeShort(cp.getClass(dotToSlash(className))); - // u2 super_class; - dout.writeShort(cp.getClass(superclassName)); - - // u2 interfaces_count; - dout.writeShort(interfaces.length); - // u2 interfaces[interfaces_count]; - for (Class<?> intf : interfaces) { - dout.writeShort(cp.getClass( - dotToSlash(intf.getName()))); - } - - // u2 fields_count; - dout.writeShort(fields.size()); - // field_info fields[fields_count]; - for (FieldInfo f : fields) { - f.write(dout); - } - - // u2 methods_count; - dout.writeShort(methods.size()); - // method_info methods[methods_count]; - for (MethodInfo m : methods) { - m.write(dout); - } - - // u2 attributes_count; - dout.writeShort(0); // (no ClassFile attributes for proxy classes) - - } catch (IOException e) { - throw new InternalError("unexpected I/O Exception", e); - } - - return bout.toByteArray(); - } - - /** - * Add another method to be proxied, either by creating a new - * ProxyMethod object or augmenting an old one for a duplicate - * method. - * - * "fromClass" indicates the proxy interface that the method was - * found through, which may be different from (a subinterface of) - * the method's "declaring class". Note that the first Method - * object passed for a given name and descriptor identifies the - * Method object (and thus the declaring class) that will be - * passed to the invocation handler's "invoke" method for a given - * set of duplicate methods. - */ - private void addProxyMethod(Method m, Class<?> fromClass) { - String name = m.getName(); - Class<?>[] parameterTypes = m.getParameterTypes(); - Class<?> returnType = m.getReturnType(); - Class<?>[] exceptionTypes = m.getExceptionTypes(); - - String sig = name + getParameterDescriptors(parameterTypes); - List<ProxyMethod> sigmethods = proxyMethods.get(sig); - if (sigmethods != null) { - for (ProxyMethod pm : sigmethods) { - if (returnType == pm.returnType) { - /* - * Found a match: reduce exception types to the - * greatest set of exceptions that can thrown - * compatibly with the throws clauses of both - * overridden methods. - */ - List<Class<?>> legalExceptions = new ArrayList<>(); - collectCompatibleTypes( - exceptionTypes, pm.exceptionTypes, legalExceptions); - collectCompatibleTypes( - pm.exceptionTypes, exceptionTypes, legalExceptions); - pm.exceptionTypes = new Class<?>[legalExceptions.size()]; - pm.exceptionTypes = - legalExceptions.toArray(pm.exceptionTypes); - return; - } - } - } else { - sigmethods = new ArrayList<>(3); - proxyMethods.put(sig, sigmethods); - } - sigmethods.add(new ProxyMethod(name, parameterTypes, returnType, - exceptionTypes, fromClass)); - } - - /** - * For a given set of proxy methods with the same signature, check - * that their return types are compatible according to the Proxy - * specification. - * - * Specifically, if there is more than one such method, then all - * of the return types must be reference types, and there must be - * one return type that is assignable to each of the rest of them. - */ - private static void checkReturnTypes(List<ProxyMethod> methods) { - /* - * If there is only one method with a given signature, there - * cannot be a conflict. This is the only case in which a - * primitive (or void) return type is allowed. - */ - if (methods.size() < 2) { - return; - } - - /* - * List of return types that are not yet known to be - * assignable from ("covered" by) any of the others. - */ - LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<>(); - - nextNewReturnType: - for (ProxyMethod pm : methods) { - Class<?> newReturnType = pm.returnType; - if (newReturnType.isPrimitive()) { - throw new IllegalArgumentException( - "methods with same signature " + - getFriendlyMethodSignature(pm.methodName, - pm.parameterTypes) + - " but incompatible return types: " + - newReturnType.getName() + " and others"); - } - boolean added = false; - - /* - * Compare the new return type to the existing uncovered - * return types. - */ - ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator(); - while (liter.hasNext()) { - Class<?> uncoveredReturnType = liter.next(); - - /* - * If an existing uncovered return type is assignable - * to this new one, then we can forget the new one. - */ - if (newReturnType.isAssignableFrom(uncoveredReturnType)) { - assert !added; - continue nextNewReturnType; - } - - /* - * If the new return type is assignable to an existing - * uncovered one, then should replace the existing one - * with the new one (or just forget the existing one, - * if the new one has already be put in the list). - */ - if (uncoveredReturnType.isAssignableFrom(newReturnType)) { - // (we can assume that each return type is unique) - if (!added) { - liter.set(newReturnType); - added = true; - } else { - liter.remove(); - } - } - } - - /* - * If we got through the list of existing uncovered return - * types without an assignability relationship, then add - * the new return type to the list of uncovered ones. - */ - if (!added) { - uncoveredReturnTypes.add(newReturnType); - } - } - - /* - * We shouldn't end up with more than one return type that is - * not assignable from any of the others. - */ - if (uncoveredReturnTypes.size() > 1) { - ProxyMethod pm = methods.get(0); - throw new IllegalArgumentException( - "methods with same signature " + - getFriendlyMethodSignature(pm.methodName, pm.parameterTypes) + - " but incompatible return types: " + uncoveredReturnTypes); - } - } - - /** - * A FieldInfo object contains information about a particular field - * in the class being generated. The class mirrors the data items of - * the "field_info" structure of the class file format (see JVMS 4.5). - */ - private class FieldInfo { - public int accessFlags; - public String name; - public String descriptor; - - public FieldInfo(String name, String descriptor, int accessFlags) { - this.name = name; - this.descriptor = descriptor; - this.accessFlags = accessFlags; - - /* - * Make sure that constant pool indexes are reserved for the - * following items before starting to write the final class file. - */ - cp.getUtf8(name); - cp.getUtf8(descriptor); - } - - public void write(DataOutputStream out) throws IOException { - /* - * Write all the items of the "field_info" structure. - * See JVMS section 4.5. - */ - // u2 access_flags; - out.writeShort(accessFlags); - // u2 name_index; - out.writeShort(cp.getUtf8(name)); - // u2 descriptor_index; - out.writeShort(cp.getUtf8(descriptor)); - // u2 attributes_count; - out.writeShort(0); // (no field_info attributes for proxy classes) - } - } - - /** - * An ExceptionTableEntry object holds values for the data items of - * an entry in the "exception_table" item of the "Code" attribute of - * "method_info" structures (see JVMS 4.7.3). - */ - private static class ExceptionTableEntry { - public short startPc; - public short endPc; - public short handlerPc; - public short catchType; - - public ExceptionTableEntry(short startPc, short endPc, - short handlerPc, short catchType) - { - this.startPc = startPc; - this.endPc = endPc; - this.handlerPc = handlerPc; - this.catchType = catchType; - } - }; - - /** - * A MethodInfo object contains information about a particular method - * in the class being generated. This class mirrors the data items of - * the "method_info" structure of the class file format (see JVMS 4.6). - */ - private class MethodInfo { - public int accessFlags; - public String name; - public String descriptor; - public short maxStack; - public short maxLocals; - public ByteArrayOutputStream code = new ByteArrayOutputStream(); - public List<ExceptionTableEntry> exceptionTable = - new ArrayList<ExceptionTableEntry>(); - public short[] declaredExceptions; - - public MethodInfo(String name, String descriptor, int accessFlags) { - this.name = name; - this.descriptor = descriptor; - this.accessFlags = accessFlags; - - /* - * Make sure that constant pool indexes are reserved for the - * following items before starting to write the final class file. - */ - cp.getUtf8(name); - cp.getUtf8(descriptor); - cp.getUtf8("Code"); - cp.getUtf8("Exceptions"); - } - - public void write(DataOutputStream out) throws IOException { - /* - * Write all the items of the "method_info" structure. - * See JVMS section 4.6. - */ - // u2 access_flags; - out.writeShort(accessFlags); - // u2 name_index; - out.writeShort(cp.getUtf8(name)); - // u2 descriptor_index; - out.writeShort(cp.getUtf8(descriptor)); - // u2 attributes_count; - out.writeShort(2); // (two method_info attributes:) - - // Write "Code" attribute. See JVMS section 4.7.3. - - // u2 attribute_name_index; - out.writeShort(cp.getUtf8("Code")); - // u4 attribute_length; - out.writeInt(12 + code.size() + 8 * exceptionTable.size()); - // u2 max_stack; - out.writeShort(maxStack); - // u2 max_locals; - out.writeShort(maxLocals); - // u2 code_length; - out.writeInt(code.size()); - // u1 code[code_length]; - code.writeTo(out); - // u2 exception_table_length; - out.writeShort(exceptionTable.size()); - for (ExceptionTableEntry e : exceptionTable) { - // u2 start_pc; - out.writeShort(e.startPc); - // u2 end_pc; - out.writeShort(e.endPc); - // u2 handler_pc; - out.writeShort(e.handlerPc); - // u2 catch_type; - out.writeShort(e.catchType); - } - // u2 attributes_count; - out.writeShort(0); - - // write "Exceptions" attribute. See JVMS section 4.7.4. - - // u2 attribute_name_index; - out.writeShort(cp.getUtf8("Exceptions")); - // u4 attributes_length; - out.writeInt(2 + 2 * declaredExceptions.length); - // u2 number_of_exceptions; - out.writeShort(declaredExceptions.length); - // u2 exception_index_table[number_of_exceptions]; - for (short value : declaredExceptions) { - out.writeShort(value); - } - } - - } - - /** - * A ProxyMethod object represents a proxy method in the proxy class - * being generated: a method whose implementation will encode and - * dispatch invocations to the proxy instance's invocation handler. - */ - private class ProxyMethod { - - public String methodName; - public Class<?>[] parameterTypes; - public Class<?> returnType; - public Class<?>[] exceptionTypes; - public Class<?> fromClass; - public String methodFieldName; - - private ProxyMethod(String methodName, Class<?>[] parameterTypes, - Class<?> returnType, Class<?>[] exceptionTypes, - Class<?> fromClass) - { - this.methodName = methodName; - this.parameterTypes = parameterTypes; - this.returnType = returnType; - this.exceptionTypes = exceptionTypes; - this.fromClass = fromClass; - this.methodFieldName = "m" + proxyMethodCount++; - } - - /** - * Return a MethodInfo object for this method, including generating - * the code and exception table entry. - */ - private MethodInfo generateMethod() throws IOException { - String desc = getMethodDescriptor(parameterTypes, returnType); - MethodInfo minfo = new MethodInfo(methodName, desc, - ACC_PUBLIC | ACC_FINAL); - - int[] parameterSlot = new int[parameterTypes.length]; - int nextSlot = 1; - for (int i = 0; i < parameterSlot.length; i++) { - parameterSlot[i] = nextSlot; - nextSlot += getWordsPerType(parameterTypes[i]); - } - int localSlot0 = nextSlot; - short pc, tryBegin = 0, tryEnd; - - DataOutputStream out = new DataOutputStream(minfo.code); - - code_aload(0, out); - - out.writeByte(opc_getfield); - out.writeShort(cp.getFieldRef( - superclassName, - handlerFieldName, "Ljava/lang/reflect/InvocationHandler;")); - - code_aload(0, out); - - out.writeByte(opc_getstatic); - out.writeShort(cp.getFieldRef( - dotToSlash(className), - methodFieldName, "Ljava/lang/reflect/Method;")); - - if (parameterTypes.length > 0) { - - code_ipush(parameterTypes.length, out); - - out.writeByte(opc_anewarray); - out.writeShort(cp.getClass("java/lang/Object")); - - for (int i = 0; i < parameterTypes.length; i++) { - - out.writeByte(opc_dup); - - code_ipush(i, out); - - codeWrapArgument(parameterTypes[i], parameterSlot[i], out); - - out.writeByte(opc_aastore); - } - } else { - - out.writeByte(opc_aconst_null); - } - - out.writeByte(opc_invokeinterface); - out.writeShort(cp.getInterfaceMethodRef( - "java/lang/reflect/InvocationHandler", - "invoke", - "(Ljava/lang/Object;Ljava/lang/reflect/Method;" + - "[Ljava/lang/Object;)Ljava/lang/Object;")); - out.writeByte(4); - out.writeByte(0); - - if (returnType == void.class) { - - out.writeByte(opc_pop); - - out.writeByte(opc_return); - - } else { - - codeUnwrapReturnValue(returnType, out); - } - - tryEnd = pc = (short) minfo.code.size(); - - List<Class<?>> catchList = computeUniqueCatchList(exceptionTypes); - if (catchList.size() > 0) { - - for (Class<?> ex : catchList) { - minfo.exceptionTable.add(new ExceptionTableEntry( - tryBegin, tryEnd, pc, - cp.getClass(dotToSlash(ex.getName())))); - } - - out.writeByte(opc_athrow); - - pc = (short) minfo.code.size(); - - minfo.exceptionTable.add(new ExceptionTableEntry( - tryBegin, tryEnd, pc, cp.getClass("java/lang/Throwable"))); - - code_astore(localSlot0, out); - - out.writeByte(opc_new); - out.writeShort(cp.getClass( - "java/lang/reflect/UndeclaredThrowableException")); - - out.writeByte(opc_dup); - - code_aload(localSlot0, out); - - out.writeByte(opc_invokespecial); - - out.writeShort(cp.getMethodRef( - "java/lang/reflect/UndeclaredThrowableException", - "<init>", "(Ljava/lang/Throwable;)V")); - - out.writeByte(opc_athrow); - } - - if (minfo.code.size() > 65535) { - throw new IllegalArgumentException("code size limit exceeded"); - } - - minfo.maxStack = 10; - minfo.maxLocals = (short) (localSlot0 + 1); - minfo.declaredExceptions = new short[exceptionTypes.length]; - for (int i = 0; i < exceptionTypes.length; i++) { - minfo.declaredExceptions[i] = cp.getClass( - dotToSlash(exceptionTypes[i].getName())); - } - - return minfo; - } - - /** - * Generate code for wrapping an argument of the given type - * whose value can be found at the specified local variable - * index, in order for it to be passed (as an Object) to the - * invocation handler's "invoke" method. The code is written - * to the supplied stream. - */ - private void codeWrapArgument(Class<?> type, int slot, - DataOutputStream out) - throws IOException - { - if (type.isPrimitive()) { - PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type); - - if (type == int.class || - type == boolean.class || - type == byte.class || - type == char.class || - type == short.class) - { - code_iload(slot, out); - } else if (type == long.class) { - code_lload(slot, out); - } else if (type == float.class) { - code_fload(slot, out); - } else if (type == double.class) { - code_dload(slot, out); - } else { - throw new AssertionError(); - } - - out.writeByte(opc_invokestatic); - out.writeShort(cp.getMethodRef( - prim.wrapperClassName, - "valueOf", prim.wrapperValueOfDesc)); - - } else { - - code_aload(slot, out); - } - } - - /** - * Generate code for unwrapping a return value of the given - * type from the invocation handler's "invoke" method (as type - * Object) to its correct type. The code is written to the - * supplied stream. - */ - private void codeUnwrapReturnValue(Class<?> type, DataOutputStream out) - throws IOException - { - if (type.isPrimitive()) { - PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type); - - out.writeByte(opc_checkcast); - out.writeShort(cp.getClass(prim.wrapperClassName)); - - out.writeByte(opc_invokevirtual); - out.writeShort(cp.getMethodRef( - prim.wrapperClassName, - prim.unwrapMethodName, prim.unwrapMethodDesc)); - - if (type == int.class || - type == boolean.class || - type == byte.class || - type == char.class || - type == short.class) - { - out.writeByte(opc_ireturn); - } else if (type == long.class) { - out.writeByte(opc_lreturn); - } else if (type == float.class) { - out.writeByte(opc_freturn); - } else if (type == double.class) { - out.writeByte(opc_dreturn); - } else { - throw new AssertionError(); - } - - } else { - - out.writeByte(opc_checkcast); - out.writeShort(cp.getClass(dotToSlash(type.getName()))); - - out.writeByte(opc_areturn); - } - } - - /** - * Generate code for initializing the static field that stores - * the Method object for this proxy method. The code is written - * to the supplied stream. - */ - private void codeFieldInitialization(DataOutputStream out) - throws IOException - { - codeClassForName(fromClass, out); - - code_ldc(cp.getString(methodName), out); - - code_ipush(parameterTypes.length, out); - - out.writeByte(opc_anewarray); - out.writeShort(cp.getClass("java/lang/Class")); - - for (int i = 0; i < parameterTypes.length; i++) { - - out.writeByte(opc_dup); - - code_ipush(i, out); - - if (parameterTypes[i].isPrimitive()) { - PrimitiveTypeInfo prim = - PrimitiveTypeInfo.get(parameterTypes[i]); - - out.writeByte(opc_getstatic); - out.writeShort(cp.getFieldRef( - prim.wrapperClassName, "TYPE", "Ljava/lang/Class;")); - - } else { - codeClassForName(parameterTypes[i], out); - } - - out.writeByte(opc_aastore); - } - - out.writeByte(opc_invokevirtual); - out.writeShort(cp.getMethodRef( - "java/lang/Class", - "getMethod", - "(Ljava/lang/String;[Ljava/lang/Class;)" + - "Ljava/lang/reflect/Method;")); - - out.writeByte(opc_putstatic); - out.writeShort(cp.getFieldRef( - dotToSlash(className), - methodFieldName, "Ljava/lang/reflect/Method;")); - } - } - - /** - * Generate the constructor method for the proxy class. - */ - private MethodInfo generateConstructor() throws IOException { - MethodInfo minfo = new MethodInfo( - "<init>", "(Ljava/lang/reflect/InvocationHandler;)V", - ACC_PUBLIC); - - DataOutputStream out = new DataOutputStream(minfo.code); - - code_aload(0, out); - - code_aload(1, out); - - out.writeByte(opc_invokespecial); - out.writeShort(cp.getMethodRef( - superclassName, - "<init>", "(Ljava/lang/reflect/InvocationHandler;)V")); - - out.writeByte(opc_return); - - minfo.maxStack = 10; - minfo.maxLocals = 2; - minfo.declaredExceptions = new short[0]; - - return minfo; - } - - /** - * Generate the static initializer method for the proxy class. - */ - private MethodInfo generateStaticInitializer() throws IOException { - MethodInfo minfo = new MethodInfo( - "<clinit>", "()V", ACC_STATIC); - - int localSlot0 = 1; - short pc, tryBegin = 0, tryEnd; - - DataOutputStream out = new DataOutputStream(minfo.code); - - for (List<ProxyMethod> sigmethods : proxyMethods.values()) { - for (ProxyMethod pm : sigmethods) { - pm.codeFieldInitialization(out); - } - } - - out.writeByte(opc_return); - - tryEnd = pc = (short) minfo.code.size(); - - minfo.exceptionTable.add(new ExceptionTableEntry( - tryBegin, tryEnd, pc, - cp.getClass("java/lang/NoSuchMethodException"))); - - code_astore(localSlot0, out); - - out.writeByte(opc_new); - out.writeShort(cp.getClass("java/lang/NoSuchMethodError")); - - out.writeByte(opc_dup); - - code_aload(localSlot0, out); - - out.writeByte(opc_invokevirtual); - out.writeShort(cp.getMethodRef( - "java/lang/Throwable", "getMessage", "()Ljava/lang/String;")); - - out.writeByte(opc_invokespecial); - out.writeShort(cp.getMethodRef( - "java/lang/NoSuchMethodError", "<init>", "(Ljava/lang/String;)V")); - - out.writeByte(opc_athrow); - - pc = (short) minfo.code.size(); - - minfo.exceptionTable.add(new ExceptionTableEntry( - tryBegin, tryEnd, pc, - cp.getClass("java/lang/ClassNotFoundException"))); - - code_astore(localSlot0, out); - - out.writeByte(opc_new); - out.writeShort(cp.getClass("java/lang/NoClassDefFoundError")); - - out.writeByte(opc_dup); - - code_aload(localSlot0, out); - - out.writeByte(opc_invokevirtual); - out.writeShort(cp.getMethodRef( - "java/lang/Throwable", "getMessage", "()Ljava/lang/String;")); - - out.writeByte(opc_invokespecial); - out.writeShort(cp.getMethodRef( - "java/lang/NoClassDefFoundError", - "<init>", "(Ljava/lang/String;)V")); - - out.writeByte(opc_athrow); - - if (minfo.code.size() > 65535) { - throw new IllegalArgumentException("code size limit exceeded"); - } - - minfo.maxStack = 10; - minfo.maxLocals = (short) (localSlot0 + 1); - minfo.declaredExceptions = new short[0]; - - return minfo; - } - - - /* - * =============== Code Generation Utility Methods =============== - */ - - /* - * The following methods generate code for the load or store operation - * indicated by their name for the given local variable. The code is - * written to the supplied stream. - */ - - private void code_iload(int lvar, DataOutputStream out) - throws IOException - { - codeLocalLoadStore(lvar, opc_iload, opc_iload_0, out); - } - - private void code_lload(int lvar, DataOutputStream out) - throws IOException - { - codeLocalLoadStore(lvar, opc_lload, opc_lload_0, out); - } - - private void code_fload(int lvar, DataOutputStream out) - throws IOException - { - codeLocalLoadStore(lvar, opc_fload, opc_fload_0, out); - } - - private void code_dload(int lvar, DataOutputStream out) - throws IOException - { - codeLocalLoadStore(lvar, opc_dload, opc_dload_0, out); - } - - private void code_aload(int lvar, DataOutputStream out) - throws IOException - { - codeLocalLoadStore(lvar, opc_aload, opc_aload_0, out); - } - -// private void code_istore(int lvar, DataOutputStream out) -// throws IOException -// { -// codeLocalLoadStore(lvar, opc_istore, opc_istore_0, out); -// } - -// private void code_lstore(int lvar, DataOutputStream out) -// throws IOException -// { -// codeLocalLoadStore(lvar, opc_lstore, opc_lstore_0, out); -// } - -// private void code_fstore(int lvar, DataOutputStream out) -// throws IOException -// { -// codeLocalLoadStore(lvar, opc_fstore, opc_fstore_0, out); -// } - -// private void code_dstore(int lvar, DataOutputStream out) -// throws IOException -// { -// codeLocalLoadStore(lvar, opc_dstore, opc_dstore_0, out); -// } - - private void code_astore(int lvar, DataOutputStream out) - throws IOException - { - codeLocalLoadStore(lvar, opc_astore, opc_astore_0, out); - } - - /** - * Generate code for a load or store instruction for the given local - * variable. The code is written to the supplied stream. - * - * "opcode" indicates the opcode form of the desired load or store - * instruction that takes an explicit local variable index, and - * "opcode_0" indicates the corresponding form of the instruction - * with the implicit index 0. - */ - private void codeLocalLoadStore(int lvar, int opcode, int opcode_0, - DataOutputStream out) - throws IOException - { - assert lvar >= 0 && lvar <= 0xFFFF; - if (lvar <= 3) { - out.writeByte(opcode_0 + lvar); - } else if (lvar <= 0xFF) { - out.writeByte(opcode); - out.writeByte(lvar & 0xFF); - } else { - /* - * Use the "wide" instruction modifier for local variable - * indexes that do not fit into an unsigned byte. - */ - out.writeByte(opc_wide); - out.writeByte(opcode); - out.writeShort(lvar & 0xFFFF); - } - } - - /** - * Generate code for an "ldc" instruction for the given constant pool - * index (the "ldc_w" instruction is used if the index does not fit - * into an unsigned byte). The code is written to the supplied stream. - */ - private void code_ldc(int index, DataOutputStream out) - throws IOException - { - assert index >= 0 && index <= 0xFFFF; - if (index <= 0xFF) { - out.writeByte(opc_ldc); - out.writeByte(index & 0xFF); - } else { - out.writeByte(opc_ldc_w); - out.writeShort(index & 0xFFFF); - } - } - - /** - * Generate code to push a constant integer value on to the operand - * stack, using the "iconst_<i>", "bipush", or "sipush" instructions - * depending on the size of the value. The code is written to the - * supplied stream. - */ - private void code_ipush(int value, DataOutputStream out) - throws IOException - { - if (value >= -1 && value <= 5) { - out.writeByte(opc_iconst_0 + value); - } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { - out.writeByte(opc_bipush); - out.writeByte(value & 0xFF); - } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { - out.writeByte(opc_sipush); - out.writeShort(value & 0xFFFF); - } else { - throw new AssertionError(); - } - } - - /** - * Generate code to invoke the Class.forName with the name of the given - * class to get its Class object at runtime. The code is written to - * the supplied stream. Note that the code generated by this method - * may caused the checked ClassNotFoundException to be thrown. - */ - private void codeClassForName(Class<?> cl, DataOutputStream out) - throws IOException - { - code_ldc(cp.getString(cl.getName()), out); - - out.writeByte(opc_invokestatic); - out.writeShort(cp.getMethodRef( - "java/lang/Class", - "forName", "(Ljava/lang/String;)Ljava/lang/Class;")); - } - - - /* - * ==================== General Utility Methods ==================== - */ - - /** - * Convert a fully qualified class name that uses '.' as the package - * separator, the external representation used by the Java language - * and APIs, to a fully qualified class name that uses '/' as the - * package separator, the representation used in the class file - * format (see JVMS section 4.2). - */ - private static String dotToSlash(String name) { - return name.replace('.', '/'); - } - - /** - * Return the "method descriptor" string for a method with the given - * parameter types and return type. See JVMS section 4.3.3. - */ - private static String getMethodDescriptor(Class<?>[] parameterTypes, - Class<?> returnType) - { - return getParameterDescriptors(parameterTypes) + - ((returnType == void.class) ? "V" : getFieldType(returnType)); - } - - /** - * Return the list of "parameter descriptor" strings enclosed in - * parentheses corresponding to the given parameter types (in other - * words, a method descriptor without a return descriptor). This - * string is useful for constructing string keys for methods without - * regard to their return type. - */ - private static String getParameterDescriptors(Class<?>[] parameterTypes) { - StringBuilder desc = new StringBuilder("("); - for (int i = 0; i < parameterTypes.length; i++) { - desc.append(getFieldType(parameterTypes[i])); - } - desc.append(')'); - return desc.toString(); - } - - /** - * Return the "field type" string for the given type, appropriate for - * a field descriptor, a parameter descriptor, or a return descriptor - * other than "void". See JVMS section 4.3.2. - */ - private static String getFieldType(Class<?> type) { - if (type.isPrimitive()) { - return PrimitiveTypeInfo.get(type).baseTypeString; - } else if (type.isArray()) { - /* - * According to JLS 20.3.2, the getName() method on Class does - * return the VM type descriptor format for array classes (only); - * using that should be quicker than the otherwise obvious code: - * - * return "[" + getTypeDescriptor(type.getComponentType()); - */ - return type.getName().replace('.', '/'); - } else { - return "L" + dotToSlash(type.getName()) + ";"; - } - } - - /** - * Returns a human-readable string representing the signature of a - * method with the given name and parameter types. - */ - private static String getFriendlyMethodSignature(String name, - Class<?>[] parameterTypes) - { - StringBuilder sig = new StringBuilder(name); - sig.append('('); - for (int i = 0; i < parameterTypes.length; i++) { - if (i > 0) { - sig.append(','); - } - Class<?> parameterType = parameterTypes[i]; - int dimensions = 0; - while (parameterType.isArray()) { - parameterType = parameterType.getComponentType(); - dimensions++; - } - sig.append(parameterType.getName()); - while (dimensions-- > 0) { - sig.append("[]"); - } - } - sig.append(')'); - return sig.toString(); - } - - /** - * Return the number of abstract "words", or consecutive local variable - * indexes, required to contain a value of the given type. See JVMS - * section 3.6.1. - * - * Note that the original version of the JVMS contained a definition of - * this abstract notion of a "word" in section 3.4, but that definition - * was removed for the second edition. - */ - private static int getWordsPerType(Class<?> type) { - if (type == long.class || type == double.class) { - return 2; - } else { - return 1; - } - } - - /** - * Add to the given list all of the types in the "from" array that - * are not already contained in the list and are assignable to at - * least one of the types in the "with" array. - * - * This method is useful for computing the greatest common set of - * declared exceptions from duplicate methods inherited from - * different interfaces. - */ - private static void collectCompatibleTypes(Class<?>[] from, - Class<?>[] with, - List<Class<?>> list) - { - for (Class<?> fc: from) { - if (!list.contains(fc)) { - for (Class<?> wc: with) { - if (wc.isAssignableFrom(fc)) { - list.add(fc); - break; - } - } - } - } - } - - /** - * Given the exceptions declared in the throws clause of a proxy method, - * compute the exceptions that need to be caught from the invocation - * handler's invoke method and rethrown intact in the method's - * implementation before catching other Throwables and wrapping them - * in UndeclaredThrowableExceptions. - * - * The exceptions to be caught are returned in a List object. Each - * exception in the returned list is guaranteed to not be a subclass of - * any of the other exceptions in the list, so the catch blocks for - * these exceptions may be generated in any order relative to each other. - * - * Error and RuntimeException are each always contained by the returned - * list (if none of their superclasses are contained), since those - * unchecked exceptions should always be rethrown intact, and thus their - * subclasses will never appear in the returned list. - * - * The returned List will be empty if java.lang.Throwable is in the - * given list of declared exceptions, indicating that no exceptions - * need to be caught. - */ - private static List<Class<?>> computeUniqueCatchList(Class<?>[] exceptions) { - List<Class<?>> uniqueList = new ArrayList<>(); - // unique exceptions to catch - - uniqueList.add(Error.class); // always catch/rethrow these - uniqueList.add(RuntimeException.class); - - nextException: - for (Class<?> ex: exceptions) { - if (ex.isAssignableFrom(Throwable.class)) { - /* - * If Throwable is declared to be thrown by the proxy method, - * then no catch blocks are necessary, because the invoke - * can, at most, throw Throwable anyway. - */ - uniqueList.clear(); - break; - } else if (!Throwable.class.isAssignableFrom(ex)) { - /* - * Ignore types that cannot be thrown by the invoke method. - */ - continue; - } - /* - * Compare this exception against the current list of - * exceptions that need to be caught: - */ - for (int j = 0; j < uniqueList.size();) { - Class<?> ex2 = uniqueList.get(j); - if (ex2.isAssignableFrom(ex)) { - /* - * if a superclass of this exception is already on - * the list to catch, then ignore this one and continue; - */ - continue nextException; - } else if (ex.isAssignableFrom(ex2)) { - /* - * if a subclass of this exception is on the list - * to catch, then remove it; - */ - uniqueList.remove(j); - } else { - j++; // else continue comparing. - } - } - // This exception is unique (so far): add it to the list to catch. - uniqueList.add(ex); - } - return uniqueList; - } - - /** - * A PrimitiveTypeInfo object contains assorted information about - * a primitive type in its public fields. The struct for a particular - * primitive type can be obtained using the static "get" method. - */ - private static class PrimitiveTypeInfo { - - /** "base type" used in various descriptors (see JVMS section 4.3.2) */ - public String baseTypeString; - - /** name of corresponding wrapper class */ - public String wrapperClassName; - - /** method descriptor for wrapper class "valueOf" factory method */ - public String wrapperValueOfDesc; - - /** name of wrapper class method for retrieving primitive value */ - public String unwrapMethodName; - - /** descriptor of same method */ - public String unwrapMethodDesc; - - private static Map<Class<?>,PrimitiveTypeInfo> table = new HashMap<>(); - static { - add(byte.class, Byte.class); - add(char.class, Character.class); - add(double.class, Double.class); - add(float.class, Float.class); - add(int.class, Integer.class); - add(long.class, Long.class); - add(short.class, Short.class); - add(boolean.class, Boolean.class); - } - - private static void add(Class<?> primitiveClass, Class<?> wrapperClass) { - table.put(primitiveClass, - new PrimitiveTypeInfo(primitiveClass, wrapperClass)); - } - - private PrimitiveTypeInfo(Class<?> primitiveClass, Class<?> wrapperClass) { - assert primitiveClass.isPrimitive(); - - baseTypeString = - Array.newInstance(primitiveClass, 0) - .getClass().getName().substring(1); - wrapperClassName = dotToSlash(wrapperClass.getName()); - wrapperValueOfDesc = - "(" + baseTypeString + ")L" + wrapperClassName + ";"; - unwrapMethodName = primitiveClass.getName() + "Value"; - unwrapMethodDesc = "()" + baseTypeString; - } - - public static PrimitiveTypeInfo get(Class<?> cl) { - return table.get(cl); - } - } - - - /** - * A ConstantPool object represents the constant pool of a class file - * being generated. This representation of a constant pool is designed - * specifically for use by ProxyGenerator; in particular, it assumes - * that constant pool entries will not need to be resorted (for example, - * by their type, as the Java compiler does), so that the final index - * value can be assigned and used when an entry is first created. - * - * Note that new entries cannot be created after the constant pool has - * been written to a class file. To prevent such logic errors, a - * ConstantPool instance can be marked "read only", so that further - * attempts to add new entries will fail with a runtime exception. - * - * See JVMS section 4.4 for more information about the constant pool - * of a class file. - */ - private static class ConstantPool { - - /** - * list of constant pool entries, in constant pool index order. - * - * This list is used when writing the constant pool to a stream - * and for assigning the next index value. Note that element 0 - * of this list corresponds to constant pool index 1. - */ - private List<Entry> pool = new ArrayList<>(32); - - /** - * maps constant pool data of all types to constant pool indexes. - * - * This map is used to look up the index of an existing entry for - * values of all types. - */ - private Map<Object,Short> map = new HashMap<>(16); - - /** true if no new constant pool entries may be added */ - private boolean readOnly = false; - - /** - * Get or assign the index for a CONSTANT_Utf8 entry. - */ - public short getUtf8(String s) { - if (s == null) { - throw new NullPointerException(); - } - return getValue(s); - } - - /** - * Get or assign the index for a CONSTANT_Integer entry. - */ - public short getInteger(int i) { - return getValue(i); - } - - /** - * Get or assign the index for a CONSTANT_Float entry. - */ - public short getFloat(float f) { - return getValue(new Float(f)); - } - - /** - * Get or assign the index for a CONSTANT_Class entry. - */ - public short getClass(String name) { - short utf8Index = getUtf8(name); - return getIndirect(new IndirectEntry( - CONSTANT_CLASS, utf8Index)); - } - - /** - * Get or assign the index for a CONSTANT_String entry. - */ - public short getString(String s) { - short utf8Index = getUtf8(s); - return getIndirect(new IndirectEntry( - CONSTANT_STRING, utf8Index)); - } - - /** - * Get or assign the index for a CONSTANT_FieldRef entry. - */ - public short getFieldRef(String className, - String name, String descriptor) - { - short classIndex = getClass(className); - short nameAndTypeIndex = getNameAndType(name, descriptor); - return getIndirect(new IndirectEntry( - CONSTANT_FIELD, classIndex, nameAndTypeIndex)); - } - - /** - * Get or assign the index for a CONSTANT_MethodRef entry. - */ - public short getMethodRef(String className, - String name, String descriptor) - { - short classIndex = getClass(className); - short nameAndTypeIndex = getNameAndType(name, descriptor); - return getIndirect(new IndirectEntry( - CONSTANT_METHOD, classIndex, nameAndTypeIndex)); - } - - /** - * Get or assign the index for a CONSTANT_InterfaceMethodRef entry. - */ - public short getInterfaceMethodRef(String className, String name, - String descriptor) - { - short classIndex = getClass(className); - short nameAndTypeIndex = getNameAndType(name, descriptor); - return getIndirect(new IndirectEntry( - CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex)); - } - - /** - * Get or assign the index for a CONSTANT_NameAndType entry. - */ - public short getNameAndType(String name, String descriptor) { - short nameIndex = getUtf8(name); - short descriptorIndex = getUtf8(descriptor); - return getIndirect(new IndirectEntry( - CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex)); - } - - /** - * Set this ConstantPool instance to be "read only". - * - * After this method has been called, further requests to get - * an index for a non-existent entry will cause an InternalError - * to be thrown instead of creating of the entry. - */ - public void setReadOnly() { - readOnly = true; - } - - /** - * Write this constant pool to a stream as part of - * the class file format. - * - * This consists of writing the "constant_pool_count" and - * "constant_pool[]" items of the "ClassFile" structure, as - * described in JVMS section 4.1. - */ - public void write(OutputStream out) throws IOException { - DataOutputStream dataOut = new DataOutputStream(out); - - // constant_pool_count: number of entries plus one - dataOut.writeShort(pool.size() + 1); - - for (Entry e : pool) { - e.write(dataOut); - } - } - - /** - * Add a new constant pool entry and return its index. - */ - private short addEntry(Entry entry) { - pool.add(entry); - /* - * Note that this way of determining the index of the - * added entry is wrong if this pool supports - * CONSTANT_Long or CONSTANT_Double entries. - */ - if (pool.size() >= 65535) { - throw new IllegalArgumentException( - "constant pool size limit exceeded"); - } - return (short) pool.size(); - } - - /** - * Get or assign the index for an entry of a type that contains - * a direct value. The type of the given object determines the - * type of the desired entry as follows: - * - * java.lang.String CONSTANT_Utf8 - * java.lang.Integer CONSTANT_Integer - * java.lang.Float CONSTANT_Float - * java.lang.Long CONSTANT_Long - * java.lang.Double CONSTANT_DOUBLE - */ - private short getValue(Object key) { - Short index = map.get(key); - if (index != null) { - return index.shortValue(); - } else { - if (readOnly) { - throw new InternalError( - "late constant pool addition: " + key); - } - short i = addEntry(new ValueEntry(key)); - map.put(key, i); - return i; - } - } - - /** - * Get or assign the index for an entry of a type that contains - * references to other constant pool entries. - */ - private short getIndirect(IndirectEntry e) { - Short index = map.get(e); - if (index != null) { - return index.shortValue(); - } else { - if (readOnly) { - throw new InternalError("late constant pool addition"); - } - short i = addEntry(e); - map.put(e, i); - return i; - } - } - - /** - * Entry is the abstact superclass of all constant pool entry types - * that can be stored in the "pool" list; its purpose is to define a - * common method for writing constant pool entries to a class file. - */ - private abstract static class Entry { - public abstract void write(DataOutputStream out) - throws IOException; - } - - /** - * ValueEntry represents a constant pool entry of a type that - * contains a direct value (see the comments for the "getValue" - * method for a list of such types). - * - * ValueEntry objects are not used as keys for their entries in the - * Map "map", so no useful hashCode or equals methods are defined. - */ - private static class ValueEntry extends Entry { - private Object value; - - public ValueEntry(Object value) { - this.value = value; - } - - public void write(DataOutputStream out) throws IOException { - if (value instanceof String) { - out.writeByte(CONSTANT_UTF8); - out.writeUTF((String) value); - } else if (value instanceof Integer) { - out.writeByte(CONSTANT_INTEGER); - out.writeInt(((Integer) value).intValue()); - } else if (value instanceof Float) { - out.writeByte(CONSTANT_FLOAT); - out.writeFloat(((Float) value).floatValue()); - } else if (value instanceof Long) { - out.writeByte(CONSTANT_LONG); - out.writeLong(((Long) value).longValue()); - } else if (value instanceof Double) { - out.writeDouble(CONSTANT_DOUBLE); - out.writeDouble(((Double) value).doubleValue()); - } else { - throw new InternalError("bogus value entry: " + value); - } - } - } - - /** - * IndirectEntry represents a constant pool entry of a type that - * references other constant pool entries, i.e., the following types: - * - * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref, - * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and - * CONSTANT_NameAndType. - * - * Each of these entry types contains either one or two indexes of - * other constant pool entries. - * - * IndirectEntry objects are used as the keys for their entries in - * the Map "map", so the hashCode and equals methods are overridden - * to allow matching. - */ - private static class IndirectEntry extends Entry { - private int tag; - private short index0; - private short index1; - - /** - * Construct an IndirectEntry for a constant pool entry type - * that contains one index of another entry. - */ - public IndirectEntry(int tag, short index) { - this.tag = tag; - this.index0 = index; - this.index1 = 0; - } - - /** - * Construct an IndirectEntry for a constant pool entry type - * that contains two indexes for other entries. - */ - public IndirectEntry(int tag, short index0, short index1) { - this.tag = tag; - this.index0 = index0; - this.index1 = index1; - } - - public void write(DataOutputStream out) throws IOException { - out.writeByte(tag); - out.writeShort(index0); - /* - * If this entry type contains two indexes, write - * out the second, too. - */ - if (tag == CONSTANT_FIELD || - tag == CONSTANT_METHOD || - tag == CONSTANT_INTERFACEMETHOD || - tag == CONSTANT_NAMEANDTYPE) - { - out.writeShort(index1); - } - } - - public int hashCode() { - return tag + index0 + index1; - } - - public boolean equals(Object obj) { - if (obj instanceof IndirectEntry) { - IndirectEntry other = (IndirectEntry) obj; - if (tag == other.tag && - index0 == other.index0 && index1 == other.index1) - { - return true; - } - } - return false; - } - } - } -}
--- a/src/java.base/share/classes/sun/misc/Queue.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,214 +0,0 @@ -/* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.util.Enumeration; -import java.util.NoSuchElementException; - -/** - * Queue: implements a simple queue mechanism. Allows for enumeration of the - * elements. - * - * @author Herb Jellinek - */ - -public class Queue<T> { - - int length = 0; - - QueueElement<T> head = null; - QueueElement<T> tail = null; - - public Queue() { - } - - /** - * Enqueue an object. - */ - public synchronized void enqueue(T obj) { - - QueueElement<T> newElt = new QueueElement<>(obj); - - if (head == null) { - head = newElt; - tail = newElt; - length = 1; - } else { - newElt.next = head; - head.prev = newElt; - head = newElt; - length++; - } - notify(); - } - - /** - * Dequeue the oldest object on the queue. Will wait indefinitely. - * - * @return the oldest object on the queue. - * @exception java.lang.InterruptedException if any thread has - * interrupted this thread. - */ - public T dequeue() throws InterruptedException { - return dequeue(0L); - } - - /** - * Dequeue the oldest object on the queue. - * @param timeOut the number of milliseconds to wait for something - * to arrive. - * - * @return the oldest object on the queue. - * @exception java.lang.InterruptedException if any thread has - * interrupted this thread. - */ - public synchronized T dequeue(long timeOut) - throws InterruptedException { - - while (tail == null) { - wait(timeOut); - } - QueueElement<T> elt = tail; - tail = elt.prev; - if (tail == null) { - head = null; - } else { - tail.next = null; - } - length--; - return elt.obj; - } - - /** - * Is the queue empty? - * @return true if the queue is empty. - */ - public synchronized boolean isEmpty() { - return (tail == null); - } - - /** - * Returns an enumeration of the elements in Last-In, First-Out - * order. Use the Enumeration methods on the returned object to - * fetch the elements sequentially. - */ - public final synchronized Enumeration<T> elements() { - return new LIFOQueueEnumerator<>(this); - } - - /** - * Returns an enumeration of the elements in First-In, First-Out - * order. Use the Enumeration methods on the returned object to - * fetch the elements sequentially. - */ - public final synchronized Enumeration<T> reverseElements() { - return new FIFOQueueEnumerator<>(this); - } - - public synchronized void dump(String msg) { - System.err.println(">> "+msg); - System.err.println("["+length+" elt(s); head = "+ - (head == null ? "null" : (head.obj)+"")+ - " tail = "+(tail == null ? "null" : (tail.obj)+"")); - QueueElement<T> cursor = head; - QueueElement<T> last = null; - while (cursor != null) { - System.err.println(" "+cursor); - last = cursor; - cursor = cursor.next; - } - if (last != tail) { - System.err.println(" tail != last: "+tail+", "+last); - } - System.err.println("]"); - } -} - -final class FIFOQueueEnumerator<T> implements Enumeration<T> { - Queue<T> queue; - QueueElement<T> cursor; - - FIFOQueueEnumerator(Queue<T> q) { - queue = q; - cursor = q.tail; - } - - public boolean hasMoreElements() { - return (cursor != null); - } - - public T nextElement() { - synchronized (queue) { - if (cursor != null) { - QueueElement<T> result = cursor; - cursor = cursor.prev; - return result.obj; - } - } - throw new NoSuchElementException("FIFOQueueEnumerator"); - } -} - -final class LIFOQueueEnumerator<T> implements Enumeration<T> { - Queue<T> queue; - QueueElement<T> cursor; - - LIFOQueueEnumerator(Queue<T> q) { - queue = q; - cursor = q.head; - } - - public boolean hasMoreElements() { - return (cursor != null); - } - - public T nextElement() { - synchronized (queue) { - if (cursor != null) { - QueueElement<T> result = cursor; - cursor = cursor.next; - return result.obj; - } - } - throw new NoSuchElementException("LIFOQueueEnumerator"); - } -} - -class QueueElement<T> { - QueueElement<T> next = null; - QueueElement<T> prev = null; - - T obj = null; - - QueueElement(T obj) { - this.obj = obj; - } - - public String toString() { - return "QueueElement[obj="+obj+(prev == null ? " null" : " prev")+ - (next == null ? " null" : " next")+"]"; - } -}
--- a/src/java.base/share/classes/sun/misc/Request.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/* - * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -/** - * Requests are functor objects; that is, they provide part of the mechanism - * for deferred function application. - * - * @author Steven B. Byrne - */ - -public abstract class Request { - /** - * The main task of the Request object is to be exectuted from a request - * queue. - */ - public abstract void execute(); -}
--- a/src/java.base/share/classes/sun/misc/RequestProcessor.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -/** - * The request processor allows functors (Request instances) to be created - * in arbitrary threads, and to be posted for execution in a non-restricted - * thread. - * - * @author Steven B. Byrne - */ - - -public class RequestProcessor implements Runnable { - - private static Queue<Request> requestQueue; - private static Thread dispatcher; - - /** - * Queues a Request instance for execution by the request procesor - * thread. - */ - public static void postRequest(Request req) { - lazyInitialize(); - requestQueue.enqueue(req); - } - - /** - * Process requests as they are queued. - */ - public void run() { - lazyInitialize(); - while (true) { - try { - Request req = requestQueue.dequeue(); - try { - req.execute(); - } catch (Throwable t) { - // do nothing at the moment...maybe report an error - // in the future - } - } catch (InterruptedException e) { - // do nothing at the present time. - } - } - } - - - /** - * This method initiates the request processor thread. It is safe - * to call it after the thread has been started. It provides a way for - * clients to deliberately control the context in which the request - * processor thread is created - */ - public static synchronized void startProcessing() { - if (dispatcher == null) { - dispatcher = new ManagedLocalsThread(new RequestProcessor(), "Request Processor"); - dispatcher.setPriority(Thread.NORM_PRIORITY + 2); - dispatcher.start(); - } - } - - - /** - * This method performs lazy initialization. - */ - private static synchronized void lazyInitialize() { - if (requestQueue == null) { - requestQueue = new Queue<Request>(); - } - } - -}
--- a/src/java.base/share/classes/sun/misc/Signal.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/misc/Signal.java Tue Dec 22 13:41:12 2015 -0800 @@ -213,7 +213,7 @@ } }; if (handler != null) { - new ManagedLocalsThread(runnable, sig + " handler").start(); + new Thread(null, runnable, sig + " handler", 0, false).start(); } }
--- a/src/java.base/share/classes/sun/misc/UCDecoder.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,233 +0,0 @@ -/* - * Copyright (c) 1995, 2000, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.misc; - -import java.io.OutputStream; -import java.io.ByteArrayOutputStream; -import java.io.PushbackInputStream; -import java.io.PrintStream; -import java.io.IOException; - -/** - * This class implements a robust character decoder. The decoder will - * converted encoded text into binary data. - * - * The basic encoding unit is a 3 character atom. It encodes two bytes - * of data. Bytes are encoded into a 64 character set, the characters - * were chosen specifically because they appear in all codesets. - * We don't care what their numerical equivalent is because - * we use a character array to map them. This is like UUencoding - * with the dependency on ASCII removed. - * - * The three chars that make up an atom are encoded as follows: - * <pre> - * 00xxxyyy 00axxxxx 00byyyyy - * 00 = leading zeros, all values are 0 - 63 - * xxxyyy - Top 3 bits of X, Top 3 bits of Y - * axxxxx - a = X parity bit, xxxxx lower 5 bits of X - * byyyyy - b = Y parity bit, yyyyy lower 5 bits of Y - * </pre> - * - * The atoms are arranged into lines suitable for inclusion into an - * email message or text file. The number of bytes that are encoded - * per line is 48 which keeps the total line length under 80 chars) - * - * Each line has the form( - * <pre> - * *(LLSS)(DDDD)(DDDD)(DDDD)...(CRC) - * Where each (xxx) represents a three character atom. - * (LLSS) - 8 bit length (high byte), and sequence number - * modulo 256; - * (DDDD) - Data byte atoms, if length is odd, last data - * atom has (DD00) (high byte data, low byte 0) - * (CRC) - 16 bit CRC for the line, includes length, - * sequence, and all data bytes. If there is a - * zero pad byte (odd length) it is _NOT_ - * included in the CRC. - * </pre> - * - * If an error is encountered during decoding this class throws a - * CEFormatException. The specific detail messages are: - * - * <pre> - * "UCDecoder: High byte parity error." - * "UCDecoder: Low byte parity error." - * "UCDecoder: Out of sequence line." - * "UCDecoder: CRC check failed." - * </pre> - * - * @author Chuck McManis - * @see CharacterEncoder - * @see UCEncoder - */ -public class UCDecoder extends CharacterDecoder { - - /** This class encodes two bytes per atom. */ - protected int bytesPerAtom() { - return (2); - } - - /** this class encodes 48 bytes per line */ - protected int bytesPerLine() { - return (48); - } - - /* this is the UCE mapping of 0-63 to characters .. */ - private static final byte map_array[] = { - // 0 1 2 3 4 5 6 7 - (byte)'0',(byte)'1',(byte)'2',(byte)'3',(byte)'4',(byte)'5',(byte)'6',(byte)'7', // 0 - (byte)'8',(byte)'9',(byte)'A',(byte)'B',(byte)'C',(byte)'D',(byte)'E',(byte)'F', // 1 - (byte)'G',(byte)'H',(byte)'I',(byte)'J',(byte)'K',(byte)'L',(byte)'M',(byte)'N', // 2 - (byte)'O',(byte)'P',(byte)'Q',(byte)'R',(byte)'S',(byte)'T',(byte)'U',(byte)'V', // 3 - (byte)'W',(byte)'X',(byte)'Y',(byte)'Z',(byte)'a',(byte)'b',(byte)'c',(byte)'d', // 4 - (byte)'e',(byte)'f',(byte)'g',(byte)'h',(byte)'i',(byte)'j',(byte)'k',(byte)'l', // 5 - (byte)'m',(byte)'n',(byte)'o',(byte)'p',(byte)'q',(byte)'r',(byte)'s',(byte)'t', // 6 - (byte)'u',(byte)'v',(byte)'w',(byte)'x',(byte)'y',(byte)'z',(byte)'(',(byte)')' // 7 - }; - - private int sequence; - private byte tmp[] = new byte[2]; - private CRC16 crc = new CRC16(); - - /** - * Decode one atom - reads the characters from the input stream, decodes - * them, and checks for valid parity. - */ - protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int l) throws IOException { - int i, p1, p2, np1, np2; - byte a = -1, b = -1, c = -1; - byte high_byte, low_byte; - byte tmp[] = new byte[3]; - - i = inStream.read(tmp); - if (i != 3) { - throw new CEStreamExhausted(); - } - for (i = 0; (i < 64) && ((a == -1) || (b == -1) || (c == -1)); i++) { - if (tmp[0] == map_array[i]) { - a = (byte) i; - } - if (tmp[1] == map_array[i]) { - b = (byte) i; - } - if (tmp[2] == map_array[i]) { - c = (byte) i; - } - } - high_byte = (byte) (((a & 0x38) << 2) + (b & 0x1f)); - low_byte = (byte) (((a & 0x7) << 5) + (c & 0x1f)); - p1 = 0; - p2 = 0; - for (i = 1; i < 256; i = i * 2) { - if ((high_byte & i) != 0) - p1++; - if ((low_byte & i) != 0) - p2++; - } - np1 = (b & 32) / 32; - np2 = (c & 32) / 32; - if ((p1 & 1) != np1) { - throw new CEFormatException("UCDecoder: High byte parity error."); - } - if ((p2 & 1) != np2) { - throw new CEFormatException("UCDecoder: Low byte parity error."); - } - outStream.write(high_byte); - crc.update(high_byte); - if (l == 2) { - outStream.write(low_byte); - crc.update(low_byte); - } - } - - private ByteArrayOutputStream lineAndSeq = new ByteArrayOutputStream(2); - - /** - * decodeBufferPrefix initializes the sequence number to zero. - */ - protected void decodeBufferPrefix(PushbackInputStream inStream, OutputStream outStream) { - sequence = 0; - } - - /** - * decodeLinePrefix reads the sequence number and the number of - * encoded bytes from the line. If the sequence number is not the - * previous sequence number + 1 then an exception is thrown. - * UCE lines are line terminator immune, they all start with * - * so the other thing this method does is scan for the next line - * by looking for the * character. - * - * @exception CEFormatException out of sequence lines detected. - */ - protected int decodeLinePrefix(PushbackInputStream inStream, OutputStream outStream) throws IOException { - int i; - int nLen, nSeq; - byte xtmp[]; - int c; - - crc.value = 0; - while (true) { - c = inStream.read(tmp, 0, 1); - if (c == -1) { - throw new CEStreamExhausted(); - } - if (tmp[0] == '*') { - break; - } - } - lineAndSeq.reset(); - decodeAtom(inStream, lineAndSeq, 2); - xtmp = lineAndSeq.toByteArray(); - nLen = xtmp[0] & 0xff; - nSeq = xtmp[1] & 0xff; - if (nSeq != sequence) { - throw new CEFormatException("UCDecoder: Out of sequence line."); - } - sequence = (sequence + 1) & 0xff; - return (nLen); - } - - - /** - * this method reads the CRC that is at the end of every line and - * verifies that it matches the computed CRC. - * - * @exception CEFormatException if CRC check fails. - */ - protected void decodeLineSuffix(PushbackInputStream inStream, OutputStream outStream) throws IOException { - int i; - int lineCRC = crc.value; - int readCRC; - byte tmp[]; - - lineAndSeq.reset(); - decodeAtom(inStream, lineAndSeq, 2); - tmp = lineAndSeq.toByteArray(); - readCRC = ((tmp[0] << 8) & 0xFF00) + (tmp[1] & 0xff); - if (readCRC != lineCRC) { - throw new CEFormatException("UCDecoder: CRC check failed."); - } - } -}
--- a/src/java.base/share/classes/sun/misc/UCEncoder.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,178 +0,0 @@ -/* - * Copyright (c) 1995, 1997, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.misc; - -import java.io.OutputStream; -import java.io.InputStream; -import java.io.PrintStream; -import java.io.IOException; - -/** - * This class implements a robust character encoder. The encoder is designed - * to convert binary data into printable characters. The characters are - * assumed to exist but they are not assumed to be ASCII, the complete set - * is 0-9, A-Z, a-z, "(", and ")". - * - * The basic encoding unit is a 3 character atom. It encodes two bytes - * of data. Bytes are encoded into a 64 character set, the characters - * were chosen specifically because they appear in all codesets. - * We don't care what their numerical equivalent is because - * we use a character array to map them. This is like UUencoding - * with the dependency on ASCII removed. - * - * The three chars that make up an atom are encoded as follows: - * <pre> - * 00xxxyyy 00axxxxx 00byyyyy - * 00 = leading zeros, all values are 0 - 63 - * xxxyyy - Top 3 bits of X, Top 3 bits of Y - * axxxxx - a = X parity bit, xxxxx lower 5 bits of X - * byyyyy - b = Y parity bit, yyyyy lower 5 bits of Y - * </pre> - * - * The atoms are arranged into lines suitable for inclusion into an - * email message or text file. The number of bytes that are encoded - * per line is 48 which keeps the total line length under 80 chars) - * - * Each line has the form( - * <pre> - * *(LLSS)(DDDD)(DDDD)(DDDD)...(CRC) - * Where each (xxx) represents a three character atom. - * (LLSS) - 8 bit length (high byte), and sequence number - * modulo 256; - * (DDDD) - Data byte atoms, if length is odd, last data - * atom has (DD00) (high byte data, low byte 0) - * (CRC) - 16 bit CRC for the line, includes length, - * sequence, and all data bytes. If there is a - * zero pad byte (odd length) it is _NOT_ - * included in the CRC. - * </pre> - * - * @author Chuck McManis - * @see CharacterEncoder - * @see UCDecoder - */ -public class UCEncoder extends CharacterEncoder { - - /** this clase encodes two bytes per atom */ - protected int bytesPerAtom() { - return (2); - } - - /** this class encodes 48 bytes per line */ - protected int bytesPerLine() { - return (48); - } - - /* this is the UCE mapping of 0-63 to characters .. */ - private static final byte map_array[] = { - // 0 1 2 3 4 5 6 7 - (byte)'0',(byte)'1',(byte)'2',(byte)'3',(byte)'4',(byte)'5',(byte)'6',(byte)'7', // 0 - (byte)'8',(byte)'9',(byte)'A',(byte)'B',(byte)'C',(byte)'D',(byte)'E',(byte)'F', // 1 - (byte)'G',(byte)'H',(byte)'I',(byte)'J',(byte)'K',(byte)'L',(byte)'M',(byte)'N', // 2 - (byte)'O',(byte)'P',(byte)'Q',(byte)'R',(byte)'S',(byte)'T',(byte)'U',(byte)'V', // 3 - (byte)'W',(byte)'X',(byte)'Y',(byte)'Z',(byte)'a',(byte)'b',(byte)'c',(byte)'d', // 4 - (byte)'e',(byte)'f',(byte)'g',(byte)'h',(byte)'i',(byte)'j',(byte)'k',(byte)'l', // 5 - (byte)'m',(byte)'n',(byte)'o',(byte)'p',(byte)'q',(byte)'r',(byte)'s',(byte)'t', // 6 - (byte)'u',(byte)'v',(byte)'w',(byte)'x',(byte)'y',(byte)'z',(byte)'(',(byte)')' // 7 - }; - - private int sequence; - private byte tmp[] = new byte[2]; - private CRC16 crc = new CRC16(); - - /** - * encodeAtom - take two bytes and encode them into the correct - * three characters. If only one byte is to be encoded, the other - * must be zero. The padding byte is not included in the CRC computation. - */ - protected void encodeAtom(OutputStream outStream, byte data[], int offset, int len) throws IOException - { - int i; - int p1, p2; // parity bits - byte a, b; - - a = data[offset]; - if (len == 2) { - b = data[offset+1]; - } else { - b = 0; - } - crc.update(a); - if (len == 2) { - crc.update(b); - } - outStream.write(map_array[((a >>> 2) & 0x38) + ((b >>> 5) & 0x7)]); - p1 = 0; p2 = 0; - for (i = 1; i < 256; i = i * 2) { - if ((a & i) != 0) { - p1++; - } - if ((b & i) != 0) { - p2++; - } - } - p1 = (p1 & 1) * 32; - p2 = (p2 & 1) * 32; - outStream.write(map_array[(a & 31) + p1]); - outStream.write(map_array[(b & 31) + p2]); - return; - } - - /** - * Each UCE encoded line starts with a prefix of '*[XXX]', where - * the sequence number and the length are encoded in the first - * atom. - */ - protected void encodeLinePrefix(OutputStream outStream, int length) throws IOException { - outStream.write('*'); - crc.value = 0; - tmp[0] = (byte) length; - tmp[1] = (byte) sequence; - sequence = (sequence + 1) & 0xff; - encodeAtom(outStream, tmp, 0, 2); - } - - - /** - * each UCE encoded line ends with YYY and encoded version of the - * 16 bit checksum. The most significant byte of the check sum - * is always encoded FIRST. - */ - protected void encodeLineSuffix(OutputStream outStream) throws IOException { - tmp[0] = (byte) ((crc.value >>> 8) & 0xff); - tmp[1] = (byte) (crc.value & 0xff); - encodeAtom(outStream, tmp, 0, 2); - super.pStream.println(); - } - - /** - * The buffer prefix code is used to initialize the sequence number - * to zero. - */ - protected void encodeBufferPrefix(OutputStream a) throws IOException { - sequence = 0; - super.encodeBufferPrefix(a); - } -}
--- a/src/java.base/share/classes/sun/misc/UUDecoder.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,274 +0,0 @@ -/* - * Copyright (c) 1995, 2001, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.misc; - -import java.io.PushbackInputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.IOException; - -/** - * This class implements a Berkeley uu character decoder. This decoder - * was made famous by the uudecode program. - * - * The basic character coding is algorithmic, taking 6 bits of binary - * data and adding it to an ASCII ' ' (space) character. This converts - * these six bits into a printable representation. Note that it depends - * on the ASCII character encoding standard for english. Groups of three - * bytes are converted into 4 characters by treating the three bytes - * a four 6 bit groups, group 1 is byte 1's most significant six bits, - * group 2 is byte 1's least significant two bits plus byte 2's four - * most significant bits. etc. - * - * In this encoding, the buffer prefix is: - * <pre> - * begin [mode] [filename] - * </pre> - * - * This is followed by one or more lines of the form: - * <pre> - * (len)(data)(data)(data) ... - * </pre> - * where (len) is the number of bytes on this line. Note that groupings - * are always four characters, even if length is not a multiple of three - * bytes. When less than three characters are encoded, the values of the - * last remaining bytes is undefined and should be ignored. - * - * The last line of data in a uuencoded buffer is represented by a single - * space character. This is translated by the decoding engine to a line - * length of zero. This is immediately followed by a line which contains - * the word 'end[newline]' - * - * If an error is encountered during decoding this class throws a - * CEFormatException. The specific detail messages are: - * - * <pre> - * "UUDecoder: No begin line." - * "UUDecoder: Malformed begin line." - * "UUDecoder: Short Buffer." - * "UUDecoder: Bad Line Length." - * "UUDecoder: Missing 'end' line." - * </pre> - * - * @author Chuck McManis - * @see CharacterDecoder - * @see UUEncoder - */ -public class UUDecoder extends CharacterDecoder { - - /** - * This string contains the name that was in the buffer being decoded. - */ - public String bufferName; - - /** - * Represents UNIX(tm) mode bits. Generally three octal digits - * representing read, write, and execute permission of the owner, - * group owner, and others. They should be interpreted as the bit groups: - * <pre> - * (owner) (group) (others) - * rwx rwx rwx (r = read, w = write, x = execute) - *</pre> - * - */ - public int mode; - - - /** - * UU encoding specifies 3 bytes per atom. - */ - protected int bytesPerAtom() { - return (3); - } - - /** - * All UU lines have 45 bytes on them, for line length of 15*4+1 or 61 - * characters per line. - */ - protected int bytesPerLine() { - return (45); - } - - /** This is used to decode the atoms */ - private byte decoderBuffer[] = new byte[4]; - - /** - * Decode a UU atom. Note that if l is less than 3 we don't write - * the extra bits, however the encoder always encodes 4 character - * groups even when they are not needed. - */ - protected void decodeAtom(PushbackInputStream inStream, OutputStream outStream, int l) - throws IOException { - int i, c1, c2, c3, c4; - int a, b, c; - StringBuilder x = new StringBuilder(); - - for (i = 0; i < 4; i++) { - c1 = inStream.read(); - if (c1 == -1) { - throw new CEStreamExhausted(); - } - x.append((char)c1); - decoderBuffer[i] = (byte) ((c1 - ' ') & 0x3f); - } - a = ((decoderBuffer[0] << 2) & 0xfc) | ((decoderBuffer[1] >>> 4) & 3); - b = ((decoderBuffer[1] << 4) & 0xf0) | ((decoderBuffer[2] >>> 2) & 0xf); - c = ((decoderBuffer[2] << 6) & 0xc0) | (decoderBuffer[3] & 0x3f); - outStream.write((byte)(a & 0xff)); - if (l > 1) { - outStream.write((byte)( b & 0xff)); - } - if (l > 2) { - outStream.write((byte)(c&0xff)); - } - } - - /** - * For uuencoded buffers, the data begins with a line of the form: - * begin MODE FILENAME - * This line always starts in column 1. - */ - protected void decodeBufferPrefix(PushbackInputStream inStream, OutputStream outStream) throws IOException { - int c; - StringBuilder q = new StringBuilder(32); - String r; - boolean sawNewLine; - - /* - * This works by ripping through the buffer until it finds a 'begin' - * line or the end of the buffer. - */ - sawNewLine = true; - while (true) { - c = inStream.read(); - if (c == -1) { - throw new CEFormatException("UUDecoder: No begin line."); - } - if ((c == 'b') && sawNewLine){ - c = inStream.read(); - if (c == 'e') { - break; - } - } - sawNewLine = (c == '\n') || (c == '\r'); - } - - /* - * Now we think its begin, (we've seen ^be) so verify it here. - */ - while ((c != '\n') && (c != '\r')) { - c = inStream.read(); - if (c == -1) { - throw new CEFormatException("UUDecoder: No begin line."); - } - if ((c != '\n') && (c != '\r')) { - q.append((char)c); - } - } - r = q.toString(); - if (r.indexOf(' ') != 3) { - throw new CEFormatException("UUDecoder: Malformed begin line."); - } - mode = Integer.parseInt(r.substring(4,7)); - bufferName = r.substring(r.indexOf(' ',6)+1); - /* - * Check for \n after \r - */ - if (c == '\r') { - c = inStream.read (); - if ((c != '\n') && (c != -1)) - inStream.unread (c); - } - } - - /** - * In uuencoded buffers, encoded lines start with a character that - * represents the number of bytes encoded in this line. The last - * line of input is always a line that starts with a single space - * character, which would be a zero length line. - */ - protected int decodeLinePrefix(PushbackInputStream inStream, OutputStream outStream) throws IOException { - int c; - - c = inStream.read(); - if (c == ' ') { - c = inStream.read(); /* discard the (first)trailing CR or LF */ - c = inStream.read(); /* check for a second one */ - if ((c != '\n') && (c != -1)) - inStream.unread (c); - throw new CEStreamExhausted(); - } else if (c == -1) { - throw new CEFormatException("UUDecoder: Short Buffer."); - } - - c = (c - ' ') & 0x3f; - if (c > bytesPerLine()) { - throw new CEFormatException("UUDecoder: Bad Line Length."); - } - return (c); - } - - - /** - * Find the end of the line for the next operation. - * The following sequences are recognized as end-of-line - * CR, CR LF, or LF - */ - protected void decodeLineSuffix(PushbackInputStream inStream, OutputStream outStream) throws IOException { - int c; - while (true) { - c = inStream.read(); - if (c == -1) { - throw new CEStreamExhausted(); - } - if (c == '\n') { - break; - } - if (c == '\r') { - c = inStream.read(); - if ((c != '\n') && (c != -1)) { - inStream.unread (c); - } - break; - } - } - } - - /** - * UUencoded files have a buffer suffix which consists of the word - * end. This line should immediately follow the line with a single - * space in it. - */ - protected void decodeBufferSuffix(PushbackInputStream inStream, OutputStream outStream) throws IOException { - int c; - - c = inStream.read(decoderBuffer); - if ((decoderBuffer[0] != 'e') || (decoderBuffer[1] != 'n') || - (decoderBuffer[2] != 'd')) { - throw new CEFormatException("UUDecoder: Missing 'end' line."); - } - } - -}
--- a/src/java.base/share/classes/sun/misc/UUEncoder.java Fri Dec 18 10:00:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -/* - * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.misc; - -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.IOException; - -/** - * This class implements a Berkeley uu character encoder. This encoder - * was made famous by uuencode program. - * - * The basic character coding is algorithmic, taking 6 bits of binary - * data and adding it to an ASCII ' ' (space) character. This converts - * these six bits into a printable representation. Note that it depends - * on the ASCII character encoding standard for english. Groups of three - * bytes are converted into 4 characters by treating the three bytes - * a four 6 bit groups, group 1 is byte 1's most significant six bits, - * group 2 is byte 1's least significant two bits plus byte 2's four - * most significant bits. etc. - * - * In this encoding, the buffer prefix is: - * <pre> - * begin [mode] [filename] - * </pre> - * - * This is followed by one or more lines of the form: - * <pre> - * (len)(data)(data)(data) ... - * </pre> - * where (len) is the number of bytes on this line. Note that groupings - * are always four characters, even if length is not a multiple of three - * bytes. When less than three characters are encoded, the values of the - * last remaining bytes is undefined and should be ignored. - * - * The last line of data in a uuencoded file is represented by a single - * space character. This is translated by the decoding engine to a line - * length of zero. This is immediately followed by a line which contains - * the word 'end[newline]' - * - * @author Chuck McManis - * @see CharacterEncoder - * @see UUDecoder - */ -public class UUEncoder extends CharacterEncoder { - - /** - * This name is stored in the begin line. - */ - private String bufferName; - - /** - * Represents UNIX(tm) mode bits. Generally three octal digits representing - * read, write, and execute permission of the owner, group owner, and - * others. They should be interpreted as the bit groups: - * (owner) (group) (others) - * rwx rwx rwx (r = read, w = write, x = execute) - * - * By default these are set to 644 (UNIX rw-r--r-- permissions). - */ - private int mode; - - - /** - * Default - buffer begin line will be: - * <pre> - * begin 644 encoder.buf - * </pre> - */ - public UUEncoder() { - bufferName = "encoder.buf"; - mode = 644; - } - - /** - * Specifies a name for the encoded buffer, begin line will be: - * <pre> - * begin 644 [FNAME] - * </pre> - */ - public UUEncoder(String fname) { - bufferName = fname; - mode = 644; - } - - /** - * Specifies a name and mode for the encoded buffer, begin line will be: - * <pre> - * begin [MODE] [FNAME] - * </pre> - */ - public UUEncoder(String fname, int newMode) { - bufferName = fname; - mode = newMode; - } - - /** number of bytes per atom in uuencoding is 3 */ - protected int bytesPerAtom() { - return (3); - } - - /** number of bytes per line in uuencoding is 45 */ - protected int bytesPerLine() { - return (45); - } - - /** - * encodeAtom - take three bytes and encodes them into 4 characters - * If len is less than 3 then remaining bytes are filled with '1'. - * This insures that the last line won't end in spaces and potentiallly - * be truncated. - */ - protected void encodeAtom(OutputStream outStream, byte data[], int offset, int len) - throws IOException { - byte a, b = 1, c = 1; - int c1, c2, c3, c4; - - a = data[offset]; - if (len > 1) { - b = data[offset+1]; - } - if (len > 2) { - c = data[offset+2]; - } - - c1 = (a >>> 2) & 0x3f; - c2 = ((a << 4) & 0x30) | ((b >>> 4) & 0xf); - c3 = ((b << 2) & 0x3c) | ((c >>> 6) & 0x3); - c4 = c & 0x3f; - outStream.write(c1 + ' '); - outStream.write(c2 + ' '); - outStream.write(c3 + ' '); - outStream.write(c4 + ' '); - return; - } - - /** - * Encode the line prefix which consists of the single character. The - * lenght is added to the value of ' ' (32 decimal) and printed. - */ - protected void encodeLinePrefix(OutputStream outStream, int length) - throws IOException { - outStream.write((length & 0x3f) + ' '); - } - - - /** - * The line suffix for uuencoded files is simply a new line. - */ - protected void encodeLineSuffix(OutputStream outStream) throws IOException { - pStream.println(); - } - - /** - * encodeBufferPrefix writes the begin line to the output stream. - */ - protected void encodeBufferPrefix(OutputStream a) throws IOException { - super.pStream = new PrintStream(a); - super.pStream.print("begin "+mode+" "); - if (bufferName != null) { - super.pStream.println(bufferName); - } else { - super.pStream.println("encoder.bin"); - } - super.pStream.flush(); - } - - /** - * encodeBufferSuffix writes the single line containing space (' ') and - * the line containing the word 'end' to the output stream. - */ - protected void encodeBufferSuffix(OutputStream a) throws IOException { - super.pStream.println(" \nend"); - super.pStream.flush(); - } - -}
--- a/src/java.base/share/classes/sun/misc/VM.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/misc/VM.java Tue Dec 22 13:41:12 2015 -0800 @@ -274,9 +274,6 @@ // used by java.lang.Integer.IntegerCache props.remove("java.lang.Integer.IntegerCache.high"); - // used by java.util.zip.ZipFile - props.remove("sun.zip.disableMemoryMapping"); - // used by sun.launcher.LauncherHelper props.remove("sun.java.launcher.diag"); }
--- a/src/java.base/share/classes/sun/net/NetworkServer.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/net/NetworkServer.java Tue Dec 22 13:41:12 2015 -0800 @@ -27,7 +27,6 @@ import java.io.*; import java.net.Socket; import java.net.ServerSocket; -import sun.misc.ManagedLocalsThread; /** * This is the base class for network servers. To define a new type @@ -73,7 +72,7 @@ NetworkServer n = (NetworkServer)clone(); n.serverSocket = null; n.clientSocket = ns; - new ManagedLocalsThread(n).start(); + new Thread(null, n, "NetworkServer", 0, false).start(); } catch(Exception e) { System.out.print("Server failure\n"); e.printStackTrace(); @@ -108,7 +107,7 @@ for each new connection. */ public final void startServer(int port) throws IOException { serverSocket = new ServerSocket(port, 50); - serverInstance = new ManagedLocalsThread(this); + serverInstance = new Thread(null, this, "NetworkServer", 0, false); serverInstance.start(); }
--- a/src/java.base/share/classes/sun/net/www/MimeLauncher.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/net/www/MimeLauncher.java Tue Dec 22 13:41:12 2015 -0800 @@ -27,9 +27,8 @@ import java.net.URL; import java.io.*; import java.util.StringTokenizer; -import sun.misc.ManagedLocalsThread; -class MimeLauncher extends ManagedLocalsThread { +class MimeLauncher extends Thread { java.net.URLConnection uc; MimeEntry m; String genericTempFileTemplate; @@ -38,7 +37,7 @@ MimeLauncher (MimeEntry M, java.net.URLConnection uc, InputStream is, String tempFileTemplate, String threadName) throws ApplicationLaunchException { - super(threadName); + super(null, null, threadName, 0, false); m = M; this.uc = uc; this.is = is;
--- a/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java Tue Dec 22 13:41:12 2015 -0800 @@ -30,7 +30,6 @@ import java.security.PrivilegedAction; import java.io.IOException; import java.util.*; -import sun.misc.ManagedLocalsThread; /** * Base implementation of background poller thread used in watch service @@ -60,7 +59,7 @@ AccessController.doPrivileged(new PrivilegedAction<>() { @Override public Object run() { - Thread thr = new ManagedLocalsThread(thisRunnable); + Thread thr = new Thread(null, thisRunnable, "FileSystemWatchService", 0, false); thr.setDaemon(true); thr.start(); return null;
--- a/src/java.base/share/classes/sun/nio/fs/Cancellable.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/nio/fs/Cancellable.java Tue Dec 22 13:41:12 2015 -0800 @@ -25,7 +25,6 @@ package sun.nio.fs; -import sun.misc.ManagedLocalsThread; import jdk.internal.misc.Unsafe; import java.util.concurrent.ExecutionException; @@ -118,7 +117,7 @@ * thread by writing into the memory location that it polls cooperatively. */ static void runInterruptibly(Cancellable task) throws ExecutionException { - Thread t = new ManagedLocalsThread(task); + Thread t = new Thread(null, task, "NIO-Task", 0, false); t.start(); boolean cancelledByInterrupt = false; while (t.isAlive()) {
--- a/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java Tue Dec 22 13:41:12 2015 -0800 @@ -35,7 +35,6 @@ import java.util.*; import java.util.concurrent.*; import com.sun.nio.file.SensitivityWatchEventModifier; -import sun.misc.ManagedLocalsThread; /** * Simple WatchService implementation that uses periodic tasks to poll @@ -59,7 +58,7 @@ .newSingleThreadScheduledExecutor(new ThreadFactory() { @Override public Thread newThread(Runnable r) { - Thread t = new ManagedLocalsThread(r); + Thread t = new Thread(null, r, "FileSystemWatchService", 0, false); t.setDaemon(true); return t; }});
--- a/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Fri Dec 18 10:00:55 2015 -0800 +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Tue Dec 22 13:41:12 2015 -0800 @@ -62,7 +62,7 @@ decl); if (type instanceof Class) { return new AnnotatedTypeBaseImpl(type, - addNesting(type, currentLoc), + currentLoc, actualTypeAnnos, allOnSameTarget, decl); @@ -74,7 +74,7 @@ decl); } else if (type instanceof ParameterizedType) { return new AnnotatedParameterizedTypeImpl((ParameterizedType)type, - addNesting(type, currentLoc), + currentLoc, actualTypeAnnos, allOnSameTarget, decl); @@ -88,7 +88,7 @@ throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen."); } - private static LocationInfo addNesting(Type type, LocationInfo addTo) { + public static LocationInfo nestingForType(Type type, LocationInfo addTo) { if (isArray(type)) return addTo; if (type instanceof Class) { @@ -96,13 +96,13 @@ if (clz.getEnclosingClass() == null) return addTo; if (Modifier.isStatic(clz.getModifiers())) - return addNesting(clz.getEnclosingClass(), addTo); - return addNesting(clz.getEnclosingClass(), addTo.pushInner()); + return nestingForType(clz.getEnclosingClass(), addTo); + return nestingForType(clz.getEnclosingClass(), addTo.pushInner()); } else if (type instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType)type; if (t.getOwnerType() == null) return addTo; - return addNesting(t.getOwnerType(), addTo.pushInner()); + return nestingForType(t.getOwnerType(), addTo.pushInner()); } return addTo; } @@ -118,8 +118,9 @@ return false; } + static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0]; static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION, - new TypeAnnotation[0], new TypeAnnotation[0], null); + EMPTY_TYPE_ANNOTATION_ARRAY, EMPTY_TYPE_ANNOTATION_ARRAY, null); static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0]; private static class AnnotatedTypeBaseImpl implements AnnotatedType { @@ -177,6 +178,30 @@ return type; } + @Override + public AnnotatedType getAnnotatedOwnerType() { + if (!(type instanceof Class<?>)) + throw new IllegalStateException("Can't compute owner"); + + Class<?> inner = (Class<?>)type; + Class<?> owner = inner.getDeclaringClass(); + if (owner == null) // top-level, local or anonymous + return null; + if (inner.isPrimitive() || inner == Void.TYPE) + return null; + + LocationInfo outerLoc = nestingForType(owner, getLocation().popAllLocations((byte)1)); + TypeAnnotation[]all = getTypeAnnotations(); + List<TypeAnnotation> l = new ArrayList<>(all.length); + + for (TypeAnnotation t : all) + if (t.getLocationInfo().isSameLocationInfo(outerLoc)) + l.add(t); + + return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl()); + + } + // Implementation details final LocationInfo getLocation() { return location; @@ -198,11 +223,17 @@ @Override public AnnotatedType getAnnotatedGenericComponentType() { - return AnnotatedTypeFactory.buildAnnotatedType(getComponentType(), - getLocation().pushArray(), - getTypeAnnotations(), - getTypeAnnotations(), - getDecl()); + Type t = getComponentType(); + return AnnotatedTypeFactory.buildAnnotatedType(t, + nestingForType(t, getLocation().pushArray()), + getTypeAnnotations(), + getTypeAnnotations(), + getDecl()); + } + + @Override + public AnnotatedType getAnnotatedOwnerType() { + return null; } private Type getComponentType() { @@ -227,6 +258,11 @@ return getTypeVariable().getAnnotatedBounds(); } + @Override + public AnnotatedType getAnnotatedOwnerType() { + return null; + } + private TypeVariable<?> getTypeVariable() { return (TypeVariable)getType(); } @@ -248,19 +284,35 @@ int initialCapacity = getTypeAnnotations().length; for (int i = 0; i < res.length; i++) { List<TypeAnnotation> l = new ArrayList<>(initialCapacity); - LocationInfo newLoc = getLocation().pushTypeArg((byte)i); + LocationInfo newLoc = nestingForType(arguments[i], getLocation().pushTypeArg((byte)i)); for (TypeAnnotation t : getTypeAnnotations()) if (t.getLocationInfo().isSameLocationInfo(newLoc)) l.add(t); res[i] = buildAnnotatedType(arguments[i], - newLoc, - l.toArray(new TypeAnnotation[0]), - getTypeAnnotations(), - getDecl()); + newLoc, + l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), + getTypeAnnotations(), + getDecl()); } return res; } + @Override + public AnnotatedType getAnnotatedOwnerType() { + Type owner = getParameterizedType().getOwnerType(); + if (owner == null) + return null; + LocationInfo outerLoc = nestingForType(owner, getLocation().popAllLocations((byte)1)); + TypeAnnotation[]all = getTypeAnnotations(); + List<TypeAnnotation> l = new ArrayList<>(all.length); + + for (TypeAnnotation t : all) + if (t.getLocationInfo().isSameLocationInfo(outerLoc)) + l.add(t); + + return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl()); + } + private ParameterizedType getParameterizedType() { return (ParameterizedType)getType(); } @@ -279,11 +331,11 @@ public AnnotatedType[] getAnnotatedUpperBounds() { if (!hasUpperBounds()) { return new AnnotatedType[] { buildAnnotatedType(Object.class, - LocationInfo.BASE_LOCATION, - new TypeAnnotation[0], - new TypeAnnotation[0], - null) - }; + LocationInfo.BASE_LOCATION, + EMPTY_TYPE_ANNOTATION_ARRAY, + EMPTY_TYPE_ANNOTATION_ARRAY, + null) + }; } return getAnnotatedBounds(getWildcardType().getUpperBounds()); } @@ -295,21 +347,26 @@ return getAnnotatedBounds(getWildcardType().getLowerBounds()); }