From bf63945ad1542dbdcbaf652a518a2381868244d8 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Wed, 30 Aug 2023 11:11:44 +0000 Subject: [PATCH 01/86] 8298992: runtime/NMT/SummarySanityCheck.java failed with "Total committed (MMMMMM) did not match the summarized committed (NNNNNN)" Reviewed-by: gziemski, stuefe --- src/hotspot/share/services/mallocTracker.cpp | 24 ++++++++++++++++++++ src/hotspot/share/services/mallocTracker.hpp | 11 +-------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/services/mallocTracker.cpp b/src/hotspot/share/services/mallocTracker.cpp index bddfcfffc08..363bc2bb418 100644 --- a/src/hotspot/share/services/mallocTracker.cpp +++ b/src/hotspot/share/services/mallocTracker.cpp @@ -70,6 +70,30 @@ size_t MallocMemorySnapshot::total_arena() const { return amount; } +void MallocMemorySnapshot::copy_to(MallocMemorySnapshot* s) { + // Need to make sure that mtChunks don't get deallocated while the + // copy is going on, because their size is adjusted using this + // buffer in make_adjustment(). + ThreadCritical tc; + size_t total_size; + size_t loop_counter = 0; + const size_t loop_limit = 100; + // It is observed that other threads can allocate during the loop of copying. + // This results in inconsistent total and sum of parts. So, the while-loop and + // the local total_size are used to find and try again a limited number of times. + // Acheiving fully consistent total and sum of parts requires to block all mallooc's during + // the copy which is a performance obstacle. + do { + total_size = 0; + s->_all_mallocs = _all_mallocs; + for (int index = 0; index < mt_number_of_types; index ++) { + s->_malloc[index] = _malloc[index]; + total_size += _malloc[index].malloc_size(); + } + } while(s->_all_mallocs.size() != total_size && ++loop_counter < loop_limit); + assert(s->_all_mallocs.size() == total_size, "Total != sum of parts"); +} + // Make adjustment by subtracting chunks used by arenas // from total chunks to get total free chunk size void MallocMemorySnapshot::make_adjustment() { diff --git a/src/hotspot/share/services/mallocTracker.hpp b/src/hotspot/share/services/mallocTracker.hpp index f4f824bb07c..84bba305043 100644 --- a/src/hotspot/share/services/mallocTracker.hpp +++ b/src/hotspot/share/services/mallocTracker.hpp @@ -186,16 +186,7 @@ class MallocMemorySnapshot : public ResourceObj { return s->by_type(mtThreadStack)->malloc_count(); } - void copy_to(MallocMemorySnapshot* s) { - // Need to make sure that mtChunks don't get deallocated while the - // copy is going on, because their size is adjusted using this - // buffer in make_adjustment(). - ThreadCritical tc; - s->_all_mallocs = _all_mallocs; - for (int index = 0; index < mt_number_of_types; index ++) { - s->_malloc[index] = _malloc[index]; - } - } + void copy_to(MallocMemorySnapshot* s); // Make adjustment by subtracting chunks used by arenas // from total chunks to get total free chunk size From e29f0c2d75ed2592682ae718f46be2bb7d2363a4 Mon Sep 17 00:00:00 2001 From: Qing Xiao Date: Wed, 30 Aug 2023 11:26:29 +0000 Subject: [PATCH 02/86] 8297777: Convert jdk.jlink StringSharingPlugin to use Class File API Reviewed-by: asotona --- .../internal/plugins/StringSharingPlugin.java | 186 +++++++----------- 1 file changed, 72 insertions(+), 114 deletions(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java index e4c49c2c18c..db86695eed6 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java @@ -24,20 +24,9 @@ */ package jdk.tools.jlink.internal.plugins; -import com.sun.tools.classfile.Annotation; -import com.sun.tools.classfile.Attribute; -import com.sun.tools.classfile.Attributes; -import com.sun.tools.classfile.ClassFile; -import com.sun.tools.classfile.ConstantPool; -import com.sun.tools.classfile.ConstantPoolException; -import com.sun.tools.classfile.Field; -import com.sun.tools.classfile.LocalVariableTable_attribute; -import com.sun.tools.classfile.LocalVariableTypeTable_attribute; -import com.sun.tools.classfile.Method; -import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; -import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute; -import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute; -import com.sun.tools.classfile.Signature_attribute; +import jdk.internal.classfile.*; +import jdk.internal.classfile.attribute.*; +import jdk.internal.classfile.constantpool.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -80,10 +69,10 @@ private static final class CompactCPHelper { private static final class DescriptorsScanner { - private final ClassFile cf; + private final ClassModel cm; - private DescriptorsScanner(ClassFile cf) { - this.cf = cf; + private DescriptorsScanner(ClassModel cm) { + this.cm = cm; } private Set scan() throws Exception { @@ -94,130 +83,109 @@ private Set scan() throws Exception { scanMethods(utf8Descriptors); - scanAttributes(cf.attributes, utf8Descriptors); + scanAttributes(cm.attributes(), utf8Descriptors); return utf8Descriptors; } - private void scanAttributes(Attributes attributes, + private void scanAttributes(List> attributes, Set utf8Descriptors) throws Exception { - for (Attribute a : attributes) { - if (a instanceof Signature_attribute) { - Signature_attribute sig = (Signature_attribute) a; - utf8Descriptors.add(sig.signature_index); - } else if (a instanceof RuntimeVisibleAnnotations_attribute) { - RuntimeVisibleAnnotations_attribute an - = (RuntimeVisibleAnnotations_attribute) a; - for (Annotation annotation : an.annotations) { - scanAnnotation(annotation, utf8Descriptors); + for (Attribute a : attributes) { + switch (a) { + case SignatureAttribute sig -> { + utf8Descriptors.add(sig.signature().index()); } - } else if (a instanceof RuntimeInvisibleAnnotations_attribute) { - RuntimeInvisibleAnnotations_attribute an - = (RuntimeInvisibleAnnotations_attribute) a; - for (Annotation annotation : an.annotations) { - scanAnnotation(annotation, utf8Descriptors); + case RuntimeVisibleAnnotationsAttribute an -> { + for (Annotation annotation : an.annotations()) + scanAnnotation(annotation, utf8Descriptors); } - } else if (a instanceof RuntimeParameterAnnotations_attribute) { - RuntimeParameterAnnotations_attribute rap - = (RuntimeParameterAnnotations_attribute) a; - for (Annotation[] arr : rap.parameter_annotations) { - for (Annotation an : arr) { - scanAnnotation(an, utf8Descriptors); + case RuntimeInvisibleAnnotationsAttribute an -> { + for (Annotation annotation : an.annotations()) + scanAnnotation(annotation, utf8Descriptors); + } + case RuntimeVisibleParameterAnnotationsAttribute rap -> { + for (List arr : rap.parameterAnnotations()) { + for (Annotation an : arr) + scanAnnotation(an, utf8Descriptors); + } + } + case RuntimeInvisibleParameterAnnotationsAttribute rap -> { + for (List arr : rap.parameterAnnotations()) { + for (Annotation an : arr) + scanAnnotation(an, utf8Descriptors); } } - } else if (a instanceof LocalVariableTable_attribute) { - LocalVariableTable_attribute lvt - = (LocalVariableTable_attribute) a; - for (LocalVariableTable_attribute.Entry entry - : lvt.local_variable_table) { - utf8Descriptors.add(entry.descriptor_index); + case LocalVariableTableAttribute lvt -> { + for (LocalVariableInfo entry: lvt.localVariables()) + utf8Descriptors.add(entry.name().index()); } - } else if (a instanceof LocalVariableTypeTable_attribute) { - LocalVariableTypeTable_attribute lvt - = (LocalVariableTypeTable_attribute) a; - for (LocalVariableTypeTable_attribute.Entry entry - : lvt.local_variable_table) { - utf8Descriptors.add(entry.signature_index); + case LocalVariableTypeTableAttribute lvt -> { + for (LocalVariableTypeInfo entry: lvt.localVariableTypes()) + utf8Descriptors.add(entry.signature().index()); } + default -> {} } } } private void scanAnnotation(Annotation annotation, Set utf8Descriptors) throws Exception { - utf8Descriptors.add(annotation.type_index); - for (Annotation.element_value_pair evp : annotation.element_value_pairs) { - utf8Descriptors.add(evp.element_name_index); - scanElementValue(evp.value, utf8Descriptors); + utf8Descriptors.add(annotation.className().index()); + for (AnnotationElement evp : annotation.elements()) { + utf8Descriptors.add(evp.name().index()); + scanElementValue(evp.value(), utf8Descriptors); } } - private void scanElementValue(Annotation.element_value value, + private void scanElementValue(AnnotationValue value, Set utf8Descriptors) throws Exception { - if (value instanceof Annotation.Enum_element_value) { - Annotation.Enum_element_value eev - = (Annotation.Enum_element_value) value; - utf8Descriptors.add(eev.type_name_index); - } - if (value instanceof Annotation.Class_element_value) { - Annotation.Class_element_value eev - = (Annotation.Class_element_value) value; - utf8Descriptors.add(eev.class_info_index); - } - if (value instanceof Annotation.Annotation_element_value) { - Annotation.Annotation_element_value aev - = (Annotation.Annotation_element_value) value; - scanAnnotation(aev.annotation_value, utf8Descriptors); - } - if (value instanceof Annotation.Array_element_value) { - Annotation.Array_element_value aev - = (Annotation.Array_element_value) value; - for (Annotation.element_value v : aev.values) { - scanElementValue(v, utf8Descriptors); + switch (value) { + case AnnotationValue.OfEnum eev -> + utf8Descriptors.add(eev.className().index()); + case AnnotationValue.OfClass eev -> + utf8Descriptors.add(eev.className().index()); + case AnnotationValue.OfAnnotation aev -> + scanAnnotation(aev.annotation(), utf8Descriptors); + case AnnotationValue.OfArray aev -> { + for (AnnotationValue v : aev.values()) + scanElementValue(v, utf8Descriptors); } + default -> {} } } private void scanFields(Set utf8Descriptors) throws Exception { - for (Field field : cf.fields) { - int descriptorIndex = field.descriptor.index; + for (FieldModel field : cm.fields()) { + int descriptorIndex = field.fieldType().index(); utf8Descriptors.add(descriptorIndex); - scanAttributes(field.attributes, utf8Descriptors); + scanAttributes(field.attributes(), utf8Descriptors); } } private void scanMethods(Set utf8Descriptors) throws Exception { - for (Method m : cf.methods) { - int descriptorIndex = m.descriptor.index; + for (MethodModel m : cm.methods()) { + int descriptorIndex = m.methodType().index(); utf8Descriptors.add(descriptorIndex); - scanAttributes(m.attributes, utf8Descriptors); + scanAttributes(m.attributes(), utf8Descriptors); } } private void scanConstantPool(Set utf8Descriptors) throws Exception { - for (int i = 1; i < cf.constant_pool.size(); i++) { + for (int i = 1; i < cm.constantPool().entryCount(); i += cm.constantPool().entryByIndex(i).width()) { try { - ConstantPool.CPInfo info = cf.constant_pool.get(i); - if (info instanceof ConstantPool.CONSTANT_NameAndType_info) { - ConstantPool.CONSTANT_NameAndType_info nameAndType - = (ConstantPool.CONSTANT_NameAndType_info) info; - utf8Descriptors.add(nameAndType.type_index); + PoolEntry info = cm.constantPool().entryByIndex(i); + switch (info) { + case NameAndTypeEntry nameAndType -> + utf8Descriptors.add(nameAndType.type().index()); + case MethodTypeEntry mt -> + utf8Descriptors.add(mt.descriptor().index()); + default -> {} } - if (info instanceof ConstantPool.CONSTANT_MethodType_info) { - ConstantPool.CONSTANT_MethodType_info mt - = (ConstantPool.CONSTANT_MethodType_info) info; - utf8Descriptors.add(mt.descriptor_index); - } - - if (info instanceof ConstantPool.CONSTANT_Double_info - || info instanceof ConstantPool.CONSTANT_Long_info) { - i++; - } - } catch (ConstantPool.InvalidIndex ex) { + } catch (ConstantPoolException ex) { throw new IOException(ex); } } @@ -227,13 +195,7 @@ private void scanConstantPool(Set utf8Descriptors) public byte[] transform(ResourcePoolEntry resource, ResourcePoolBuilder out, StringTable strings) throws IOException, Exception { byte[] content = resource.contentBytes(); - ClassFile cf; - try (InputStream stream = new ByteArrayInputStream(content)) { - cf = ClassFile.read(stream); - } catch (ConstantPoolException ex) { - throw new IOException("Compressor EX " + ex + " for " - + resource.path() + " content.length " + content.length, ex); - } + ClassModel cf = Classfile.of().parse(content); DescriptorsScanner scanner = new DescriptorsScanner(cf); return optimize(resource, out, strings, scanner.scan(), content); } @@ -254,16 +216,14 @@ private byte[] optimize(ResourcePoolEntry resource, ResourcePoolBuilder resource int tag = stream.readUnsignedByte(); byte[] arr; switch (tag) { - case ConstantPool.CONSTANT_Utf8: { + case Classfile.TAG_UTF8: { String original = stream.readUTF(); // 2 cases, a Descriptor or a simple String if (descriptorIndexes.contains(i)) { SignatureParser.ParseResult parseResult = SignatureParser.parseSignatureDescriptor(original); List indexes - = parseResult.types.stream().map((type) -> { - return strings.addString(type); - }).toList(); + = parseResult.types.stream().map(strings::addString).toList(); if (!indexes.isEmpty()) { out.write(StringSharingDecompressor.EXTERNALIZED_STRING_DESCRIPTOR); int sigIndex = strings.addString(parseResult.formatted); @@ -280,11 +240,9 @@ private byte[] optimize(ResourcePoolEntry resource, ResourcePoolBuilder resource break; } - - case ConstantPool.CONSTANT_Long: - case ConstantPool.CONSTANT_Double: { + case Classfile.TAG_LONG: + case Classfile.TAG_DOUBLE: i++; - } default: { out.write(tag); int size = SIZES[tag]; From 6701eba736ac51db4b0d0d7db6c7bdd4ae8a1c16 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Wed, 30 Aug 2023 11:45:38 +0000 Subject: [PATCH 03/86] 8315117: Update Zlib Data Compression Library to Version 1.3 Reviewed-by: alanb --- .../share/native/libzip/zlib/ChangeLog | 207 +++++-- src/java.base/share/native/libzip/zlib/README | 19 +- .../share/native/libzip/zlib/compress.c | 21 +- .../share/native/libzip/zlib/deflate.c | 569 +++++++----------- .../share/native/libzip/zlib/deflate.h | 16 +- .../share/native/libzip/zlib/gzclose.c | 4 +- .../share/native/libzip/zlib/gzguts.h | 23 +- .../share/native/libzip/zlib/gzlib.c | 101 +--- .../share/native/libzip/zlib/gzread.c | 88 +-- .../share/native/libzip/zlib/gzwrite.c | 84 +-- .../share/native/libzip/zlib/infback.c | 30 +- .../share/native/libzip/zlib/inffast.c | 5 +- .../share/native/libzip/zlib/inffast.h | 2 +- .../share/native/libzip/zlib/inflate.c | 129 +--- .../share/native/libzip/zlib/inftrees.c | 17 +- .../share/native/libzip/zlib/inftrees.h | 6 +- .../native/libzip/zlib/patches/ChangeLog_java | 2 +- .../share/native/libzip/zlib/trees.c | 526 +++++++--------- .../share/native/libzip/zlib/uncompr.c | 16 +- .../share/native/libzip/zlib/zadler32.c | 32 +- .../share/native/libzip/zlib/zconf.h | 8 +- .../share/native/libzip/zlib/zcrc32.c | 248 +++----- src/java.base/share/native/libzip/zlib/zlib.h | 379 ++++++------ .../share/native/libzip/zlib/zutil.c | 60 +- .../share/native/libzip/zlib/zutil.h | 20 +- 25 files changed, 1069 insertions(+), 1543 deletions(-) diff --git a/src/java.base/share/native/libzip/zlib/ChangeLog b/src/java.base/share/native/libzip/zlib/ChangeLog index 9dbeb5e5642..8707988ac18 100644 --- a/src/java.base/share/native/libzip/zlib/ChangeLog +++ b/src/java.base/share/native/libzip/zlib/ChangeLog @@ -1,6 +1,99 @@ ChangeLog file for zlib +Changes in 1.3 (18 Aug 2023) +- Remove K&R function definitions and zlib2ansi +- Fix bug in deflateBound() for level 0 and memLevel 9 +- Fix bug when gzungetc() is used immediately after gzopen() +- Fix bug when using gzflush() with a very small buffer +- Fix crash when gzsetparams() attempted for transparent write +- Fix test/example.c to work with FORCE_STORED +- Rewrite of zran in examples (see zran.c version history) +- Fix minizip to allow it to open an empty zip file +- Fix reading disk number start on zip64 files in minizip +- Fix logic error in minizip argument processing +- Add minizip testing to Makefile +- Read multiple bytes instead of byte-by-byte in minizip unzip.c +- Add memory sanitizer to configure (--memory) +- Various portability improvements +- Various documentation improvements +- Various spelling and typo corrections + +Changes in 1.2.13 (13 Oct 2022) +- Fix configure issue that discarded provided CC definition +- Correct incorrect inputs provided to the CRC functions +- Repair prototypes and exporting of new CRC functions +- Fix inflateBack to detect invalid input with distances too far +- Have infback() deliver all of the available output up to any error +- Fix a bug when getting a gzip header extra field with inflate() +- Fix bug in block type selection when Z_FIXED used +- Tighten deflateBound bounds +- Remove deleted assembler code references +- Various portability and appearance improvements + +Changes in 1.2.12 (27 Mar 2022) +- Cygwin does not have _wopen(), so do not create gzopen_w() there +- Permit a deflateParams() parameter change as soon as possible +- Limit hash table inserts after switch from stored deflate +- Fix bug when window full in deflate_stored() +- Fix CLEAR_HASH macro to be usable as a single statement +- Avoid a conversion error in gzseek when off_t type too small +- Have Makefile return non-zero error code on test failure +- Avoid some conversion warnings in gzread.c and gzwrite.c +- Update use of errno for newer Windows CE versions +- Small speedup to inflate [psumbera] +- Return an error if the gzputs string length can't fit in an int +- Add address checking in clang to -w option of configure +- Don't compute check value for raw inflate if asked to validate +- Handle case where inflateSync used when header never processed +- Avoid the use of ptrdiff_t +- Avoid an undefined behavior of memcpy() in gzappend() +- Avoid undefined behaviors of memcpy() in gz*printf() +- Avoid an undefined behavior of memcpy() in _tr_stored_block() +- Make the names in functions declarations identical to definitions +- Remove old assembler code in which bugs have manifested +- Fix deflateEnd() to not report an error at start of raw deflate +- Add legal disclaimer to README +- Emphasize the need to continue decompressing gzip members +- Correct the initialization requirements for deflateInit2() +- Fix a bug that can crash deflate on some input when using Z_FIXED +- Assure that the number of bits for deflatePrime() is valid +- Use a structure to make globals in enough.c evident +- Use a macro for the printf format of big_t in enough.c +- Clean up code style in enough.c, update version +- Use inline function instead of macro for index in enough.c +- Clarify that prefix codes are counted in enough.c +- Show all the codes for the maximum tables size in enough.c +- Add gznorm.c example, which normalizes gzip files +- Fix the zran.c example to work on a multiple-member gzip file +- Add tables for crc32_combine(), to speed it up by a factor of 200 +- Add crc32_combine_gen() and crc32_combine_op() for fast combines +- Speed up software CRC-32 computation by a factor of 1.5 to 3 +- Use atomic test and set, if available, for dynamic CRC tables +- Don't bother computing check value after successful inflateSync() +- Correct comment in crc32.c +- Add use of the ARMv8 crc32 instructions when requested +- Use ARM crc32 instructions if the ARM architecture has them +- Explicitly note that the 32-bit check values are 32 bits +- Avoid adding empty gzip member after gzflush with Z_FINISH +- Fix memory leak on error in gzlog.c +- Fix error in comment on the polynomial representation of a byte +- Clarify gz* function interfaces, referring to parameter names +- Change macro name in inflate.c to avoid collision in VxWorks +- Correct typo in blast.c +- Improve portability of contrib/minizip +- Fix indentation in minizip's zip.c +- Replace black/white with allow/block. (theresa-m) +- minizip warning fix if MAXU32 already defined. (gvollant) +- Fix unztell64() in minizip to work past 4GB. (Daniël Hörchner) +- Clean up minizip to reduce warnings for testing +- Add fallthrough comments for gcc +- Eliminate use of ULL constants +- Separate out address sanitizing from warnings in configure +- Remove destructive aspects of make distclean +- Check for cc masquerading as gcc or clang in configure +- Fix crc32.c to compile local functions only if used + Changes in 1.2.11 (15 Jan 2017) - Fix deflate stored bug when pulling last block from window - Permit immediate deflateParams changes before any deflate input @@ -96,7 +189,7 @@ Changes in 1.2.7.1 (24 Mar 2013) - Fix types in contrib/minizip to match result of get_crc_table() - Simplify contrib/vstudio/vc10 with 'd' suffix - Add TOP support to win32/Makefile.msc -- Suport i686 and amd64 assembler builds in CMakeLists.txt +- Support i686 and amd64 assembler builds in CMakeLists.txt - Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h - Add vc11 and vc12 build files to contrib/vstudio - Add gzvprintf() as an undocumented function in zlib @@ -296,15 +389,15 @@ Changes in 1.2.5.1 (10 Sep 2011) - Use u4 type for crc_table to avoid conversion warnings - Apply casts in zlib.h to avoid conversion warnings - Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] -- Improve inflateSync() documentation to note indeterminancy +- Improve inflateSync() documentation to note indeterminacy - Add deflatePending() function to return the amount of pending output - Correct the spelling of "specification" in FAQ [Randers-Pehrson] - Add a check in configure for stdarg.h, use for gzprintf() - Check that pointers fit in ints when gzprint() compiled old style - Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] - Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] -- Add debug records in assmebler code [Londer] -- Update RFC references to use https://tools.ietf.org/html/... [Li] +- Add debug records in assembler code [Londer] +- Update RFC references to use http://tools.ietf.org/html/... [Li] - Add --archs option, use of libtool to configure for Mac OS X [Borstel] Changes in 1.2.5 (19 Apr 2010) @@ -511,7 +604,7 @@ Changes in 1.2.3.5 (8 Jan 2010) - Don't use _vsnprintf on later versions of MSVC [Lowman] - Add CMake build script and input file [Lowman] - Update contrib/minizip to 1.1 [Svensson, Vollant] -- Moved nintendods directory from contrib to . +- Moved nintendods directory from contrib to root - Replace gzio.c with a new set of routines with the same functionality - Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above - Update contrib/minizip to 1.1b @@ -685,7 +778,7 @@ Changes in 1.2.2.4 (11 July 2005) - Be more strict on incomplete code sets in inflate_table() and increase ENOUGH and MAXD -- this repairs a possible security vulnerability for invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for - discovering the vulnerability and providing test cases. + discovering the vulnerability and providing test cases - Add ia64 support to configure for HP-UX [Smith] - Add error return to gzread() for format or i/o error [Levin] - Use malloc.h for OS/2 [Necasek] @@ -721,7 +814,7 @@ Changes in 1.2.2.2 (30 December 2004) - Add Z_FIXED strategy option to deflateInit2() to force fixed trees - Add updated make_vms.com [Coghlan], update README - Create a new "examples" directory, move gzappend.c there, add zpipe.c, - fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html - Add FAQ entry and comments in deflate.c on uninitialized memory access - Add Solaris 9 make options in configure [Gilbert] - Allow strerror() usage in gzio.c for STDC @@ -792,7 +885,7 @@ Changes in 1.2.1.1 (9 January 2004) - Fix a big fat bug in inftrees.c that prevented decoding valid dynamic blocks with only literals and no distance codes -- Thanks to "Hot Emu" for the bug report and sample file -- Add a note to puff.c on no distance codes case. +- Add a note to puff.c on no distance codes case Changes in 1.2.1 (17 November 2003) - Remove a tab in contrib/gzappend/gzappend.c @@ -970,7 +1063,7 @@ Changes in 1.2.0.1 (17 March 2003) - Include additional header file on VMS for off_t typedef - Try to use _vsnprintf where it supplants vsprintf [Vollant] - Add some casts in inffast.c -- Enchance comments in zlib.h on what happens if gzprintf() tries to +- Enhance comments in zlib.h on what happens if gzprintf() tries to write more than 4095 bytes before compression - Remove unused state from inflateBackEnd() - Remove exit(0) from minigzip.c, example.c @@ -1036,14 +1129,14 @@ Changes in 1.2.0 (9 March 2003) - Add contrib/puff/ simple inflate for deflate format description Changes in 1.1.4 (11 March 2002) -- ZFREE was repeated on same allocation on some error conditions. +- ZFREE was repeated on same allocation on some error conditions This creates a security problem described in http://www.zlib.org/advisory-2002-03-11.txt - Returned incorrect error (Z_MEM_ERROR) on some invalid data - Avoid accesses before window for invalid distances with inflate window - less than 32K. + less than 32K - force windowBits > 8 to avoid a bug in the encoder for a window size - of 256 bytes. (A complete fix will be available in 1.1.5). + of 256 bytes. (A complete fix will be available in 1.1.5) Changes in 1.1.3 (9 July 1998) - fix "an inflate input buffer bug that shows up on rare but persistent @@ -1117,7 +1210,7 @@ Changes in 1.1.1 (27 Feb 98) - remove block truncation heuristic which had very marginal effect for zlib (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the compression ratio on some files. This also allows inlining _tr_tally for - matches in deflate_slow. + matches in deflate_slow - added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) Changes in 1.1.0 (24 Feb 98) @@ -1148,7 +1241,7 @@ Changes in 1.0.9 (17 Feb 1998) - Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 - in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) - in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with - the declaration of FAR (Gilles VOllant) + the declaration of FAR (Gilles Vollant) - install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) - read_buf buf parameter of type Bytef* instead of charf* - zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) @@ -1162,7 +1255,7 @@ Changes in 1.0.8 (27 Jan 1998) - include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) - use constant arrays for the static trees in trees.c instead of computing them at run time (thanks to Ken Raeburn for this suggestion). To create - trees.h, compile with GEN_TREES_H and run "make test". + trees.h, compile with GEN_TREES_H and run "make test" - check return code of example in "make test" and display result - pass minigzip command line options to file_compress - simplifying code of inflateSync to avoid gcc 2.8 bug @@ -1201,12 +1294,12 @@ Changes in 1.0.6 (19 Jan 1998) - add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) - Fix a deflate bug occurring only with compression level 0 (thanks to - Andy Buckler for finding this one). -- In minigzip, pass transparently also the first byte for .Z files. + Andy Buckler for finding this one) +- In minigzip, pass transparently also the first byte for .Z files - return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() - check Z_FINISH in inflate (thanks to Marc Schluper) - Implement deflateCopy (thanks to Adam Costello) -- make static libraries by default in configure, add --shared option. +- make static libraries by default in configure, add --shared option - move MSDOS or Windows specific files to directory msdos - suppress the notion of partial flush to simplify the interface (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) @@ -1218,7 +1311,7 @@ Changes in 1.0.6 (19 Jan 1998) - added Makefile.nt (thanks to Stephen Williams) - added the unsupported "contrib" directory: contrib/asm386/ by Gilles Vollant - 386 asm code replacing longest_match(). + 386 asm code replacing longest_match() contrib/iostream/ by Kevin Ruland A C++ I/O streams interface to the zlib gz* functions contrib/iostream2/ by Tyge Løvset @@ -1226,7 +1319,7 @@ Changes in 1.0.6 (19 Jan 1998) contrib/untgz/ by "Pedro A. Aranda Guti\irrez" A very simple tar.gz file extractor using zlib contrib/visual-basic.txt by Carlos Rios - How to use compress(), uncompress() and the gz* functions from VB. + How to use compress(), uncompress() and the gz* functions from VB - pass params -f (filtered data), -h (huffman only), -1 to -9 (compression level) in minigzip (thanks to Tom Lane) @@ -1235,8 +1328,8 @@ Changes in 1.0.6 (19 Jan 1998) - add undocumented function inflateSyncPoint() (hack for Paul Mackerras) - add undocumented function zError to convert error code to string (for Tim Smithers) -- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. -- Use default memcpy for Symantec MSDOS compiler. +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code +- Use default memcpy for Symantec MSDOS compiler - Add EXPORT keyword for check_func (needed for Windows DLL) - add current directory to LD_LIBRARY_PATH for "make test" - create also a link for libz.so.1 @@ -1249,7 +1342,7 @@ Changes in 1.0.6 (19 Jan 1998) - allow compilation with ANSI keywords only enabled for TurboC in large model - avoid "versionString"[0] (Borland bug) - add NEED_DUMMY_RETURN for Borland -- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch) - allow compilation with CC - defined STDC for OS/2 (David Charlap) - limit external names to 8 chars for MVS (Thomas Lund) @@ -1259,7 +1352,7 @@ Changes in 1.0.6 (19 Jan 1998) - use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) - added makelcc.bat for lcc-win32 (Tom St Denis) - in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) -- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion - check for unistd.h in configure (for off_t) - remove useless check parameter in inflate_blocks_free - avoid useless assignment of s->check to itself in inflate_blocks_new @@ -1280,7 +1373,7 @@ Changes in 1.0.5 (3 Jan 98) Changes in 1.0.4 (24 Jul 96) - In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF bit, so the decompressor could decompress all the correct data but went - on to attempt decompressing extra garbage data. This affected minigzip too. + on to attempt decompressing extra garbage data. This affected minigzip too - zlibVersion and gzerror return const char* (needed for DLL) - port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) - use z_error only for DEBUG (avoid problem with DLLs) @@ -1310,7 +1403,7 @@ Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] - fix array overlay in deflate.c which sometimes caused bad compressed data - fix inflate bug with empty stored block - fix MSDOS medium model which was broken in 0.99 -- fix deflateParams() which could generate bad compressed data. +- fix deflateParams() which could generate bad compressed data - Bytef is define'd instead of typedef'ed (work around Borland bug) - added an INDEX file - new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), @@ -1331,7 +1424,7 @@ Changes in 0.99 (27 Jan 96) - allow preset dictionary shared between compressor and decompressor - allow compression level 0 (no compression) - add deflateParams in zlib.h: allow dynamic change of compression level - and compression strategy. + and compression strategy - test large buffers and deflateParams in example.c - add optional "configure" to build zlib as a shared library - suppress Makefile.qnx, use configure instead @@ -1370,33 +1463,33 @@ Changes in 0.99 (27 Jan 96) - fix typo in Make_vms.com (f$trnlnm -> f$getsyi) - in fcalloc, normalize pointer if size > 65520 bytes - don't use special fcalloc for 32 bit Borland C++ -- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc. - use Z_BINARY instead of BINARY - document that gzclose after gzdopen will close the file -- allow "a" as mode in gzopen. +- allow "a" as mode in gzopen - fix error checking in gzread - allow skipping .gz extra-field on pipes - added reference to Perl interface in README - put the crc table in FAR data (I dislike more and more the medium model :) - added get_crc_table -- added a dimension to all arrays (Borland C can't count). +- added a dimension to all arrays (Borland C can't count) - workaround Borland C bug in declaration of inflate_codes_new & inflate_fast - guard against multiple inclusion of *.h (for precompiled header on Mac) -- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- Watcom C pretends to be Microsoft C small model even in 32 bit mode - don't use unsized arrays to avoid silly warnings by Visual C++: warning C4746: 'inflate_mask' : unsized array treated as '__far' - (what's wrong with far data in far model?). + (what's wrong with far data in far model?) - define enum out of inflate_blocks_state to allow compilation with C++ Changes in 0.95 (16 Aug 95) - fix MSDOS small and medium model (now easier to adapt to any compiler) - inlined send_bits - fix the final (:-) bug for deflate with flush (output was correct but - not completely flushed in rare occasions). + not completely flushed in rare occasions) - default window size is same for compression and decompression - (it's now sufficient to set MAX_WBITS in zconf.h). + (it's now sufficient to set MAX_WBITS in zconf.h) - voidp -> voidpf and voidnp -> voidp (for consistency with other - typedefs and because voidnp was not near in large model). + typedefs and because voidnp was not near in large model) Changes in 0.94 (13 Aug 95) - support MSDOS medium model @@ -1405,12 +1498,12 @@ Changes in 0.94 (13 Aug 95) - added support for VMS - allow a compression level in gzopen() - gzflush now calls fflush -- For deflate with flush, flush even if no more input is provided. +- For deflate with flush, flush even if no more input is provided - rename libgz.a as libz.a - avoid complex expression in infcodes.c triggering Turbo C bug - work around a problem with gcc on Alpha (in INSERT_STRING) - don't use inline functions (problem with some gcc versions) -- allow renaming of Byte, uInt, etc... with #define. +- allow renaming of Byte, uInt, etc... with #define - avoid warning about (unused) pointer before start of array in deflate.c - avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c - avoid reserved word 'new' in trees.c @@ -1429,7 +1522,7 @@ Changes in 0.92 (3 May 95) - no memcpy on Pyramid - suppressed inftest.c - optimized fill_window, put longest_match inline for gcc -- optimized inflate on stored blocks. +- optimized inflate on stored blocks - untabify all sources to simplify patches Changes in 0.91 (2 May 95) @@ -1447,7 +1540,7 @@ Changes in 0.9 (1 May 95) - let again gzread copy uncompressed data unchanged (was working in 0.71) - deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented - added a test of inflateSync in example.c -- moved MAX_WBITS to zconf.h because users might want to change that. +- moved MAX_WBITS to zconf.h because users might want to change that - document explicitly that zalloc(64K) on MSDOS must return a normalized pointer (zero offset) - added Makefiles for Microsoft C, Turbo C, Borland C++ @@ -1456,7 +1549,7 @@ Changes in 0.9 (1 May 95) Changes in 0.8 (29 April 95) - added fast inflate (inffast.c) - deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this - is incompatible with previous versions of zlib which returned Z_OK. + is incompatible with previous versions of zlib which returned Z_OK - work around a TurboC compiler bug (bad code for b << 0, see infutil.h) (actually that was not a compiler bug, see 0.81 above) - gzread no longer reads one extra byte in certain cases @@ -1466,50 +1559,50 @@ Changes in 0.8 (29 April 95) Changes in 0.71 (14 April 95) - Fixed more MSDOS compilation problems :( There is still a bug with - TurboC large model. + TurboC large model Changes in 0.7 (14 April 95) -- Added full inflate support. +- Added full inflate support - Simplified the crc32() interface. The pre- and post-conditioning (one's complement) is now done inside crc32(). WARNING: this is - incompatible with previous versions; see zlib.h for the new usage. + incompatible with previous versions; see zlib.h for the new usage Changes in 0.61 (12 April 95) -- workaround for a bug in TurboC. example and minigzip now work on MSDOS. +- workaround for a bug in TurboC. example and minigzip now work on MSDOS Changes in 0.6 (11 April 95) - added minigzip.c - added gzdopen to reopen a file descriptor as gzFile -- added transparent reading of non-gziped files in gzread. +- added transparent reading of non-gziped files in gzread - fixed bug in gzread (don't read crc as data) -- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose) - don't allocate big arrays in the stack (for MSDOS) - fix some MSDOS compilation problems Changes in 0.5: - do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but - not yet Z_FULL_FLUSH. + not yet Z_FULL_FLUSH - support decompression but only in a single step (forced Z_FINISH) -- added opaque object for zalloc and zfree. +- added opaque object for zalloc and zfree - added deflateReset and inflateReset -- added a variable zlib_version for consistency checking. -- renamed the 'filter' parameter of deflateInit2 as 'strategy'. - Added Z_FILTERED and Z_HUFFMAN_ONLY constants. +- added a variable zlib_version for consistency checking +- renamed the 'filter' parameter of deflateInit2 as 'strategy' + Added Z_FILTERED and Z_HUFFMAN_ONLY constants Changes in 0.4: -- avoid "zip" everywhere, use zlib instead of ziplib. +- avoid "zip" everywhere, use zlib instead of ziplib - suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush - if compression method == 8. + if compression method == 8 - added adler32 and crc32 - renamed deflateOptions as deflateInit2, call one or the other but not both -- added the method parameter for deflateInit2. +- added the method parameter for deflateInit2 - added inflateInit2 -- simplied considerably deflateInit and inflateInit by not supporting +- simplified considerably deflateInit and inflateInit by not supporting user-provided history buffer. This is supported only in deflateInit2 - and inflateInit2. + and inflateInit2 Changes in 0.3: - prefix all macro names with Z_ -- use Z_FINISH instead of deflateEnd to finish compression. +- use Z_FINISH instead of deflateEnd to finish compression - added Z_HUFFMAN_ONLY - added gzerror() diff --git a/src/java.base/share/native/libzip/zlib/README b/src/java.base/share/native/libzip/zlib/README index ba34d1894a9..e02fc5aa206 100644 --- a/src/java.base/share/native/libzip/zlib/README +++ b/src/java.base/share/native/libzip/zlib/README @@ -1,6 +1,6 @@ ZLIB DATA COMPRESSION LIBRARY -zlib 1.2.13 is a general purpose data compression library. All the code is +zlib 1.3 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and @@ -29,18 +29,17 @@ PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Mark Nelson wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at -http://marknelson.us/1997/01/01/zlib-engine/ . +https://marknelson.us/posts/1997/01/01/zlib-engine.html . -The changes made in version 1.2.13 are documented in the file ChangeLog. +The changes made in version 1.3 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory contrib/ . -zlib is available in Java using the java.util.zip package, documented at -http://java.sun.com/developer/technicalArticles/Programming/compression/ . +zlib is available in Java using the java.util.zip package. Follow the API +Documentation link at: https://docs.oracle.com/search/?q=java.util.zip . -A Perl interface to zlib written by Paul Marquess is available -at CPAN (Comprehensive Perl Archive Network) sites, including -http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . +A Perl interface to zlib and bzip2 written by Paul Marquess +can be found at https://github.com/pmqs/IO-Compress . A Python interface to zlib written by A.M. Kuchling is available in Python 1.5 and later versions, see @@ -64,7 +63,7 @@ Notes for some targets: - zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works when compiled with cc. -- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is +- On Digital Unix 4.0D (formerly OSF/1) on AlphaServer, the cc option -std1 is necessary to get gzprintf working correctly. This is done by configure. - zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with @@ -84,7 +83,7 @@ Acknowledgments: Copyright notice: - (C) 1995-2022 Jean-loup Gailly and Mark Adler + (C) 1995-2023 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/java.base/share/native/libzip/zlib/compress.c b/src/java.base/share/native/libzip/zlib/compress.c index bc090096785..d7421379673 100644 --- a/src/java.base/share/native/libzip/zlib/compress.c +++ b/src/java.base/share/native/libzip/zlib/compress.c @@ -43,13 +43,8 @@ memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ -int ZEXPORT compress2(dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ +int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong sourceLen, int level) { z_stream stream; int err; const uInt max = (uInt)-1; @@ -89,12 +84,8 @@ int ZEXPORT compress2(dest, destLen, source, sourceLen, level) /* =========================================================================== */ -int ZEXPORT compress(dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ +int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong sourceLen) { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } @@ -102,9 +93,7 @@ int ZEXPORT compress(dest, destLen, source, sourceLen) If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ -uLong ZEXPORT compressBound(sourceLen) - uLong sourceLen; -{ +uLong ZEXPORT compressBound(uLong sourceLen) { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } diff --git a/src/java.base/share/native/libzip/zlib/deflate.c b/src/java.base/share/native/libzip/zlib/deflate.c index 46d512d4200..c701ce2836b 100644 --- a/src/java.base/share/native/libzip/zlib/deflate.c +++ b/src/java.base/share/native/libzip/zlib/deflate.c @@ -23,7 +23,7 @@ */ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + * Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -76,7 +76,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; + " deflate 1.3 Copyright 1995-2023 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -84,9 +84,6 @@ const char deflate_copyright[] = copyright string in the executable of your product. */ -/* =========================================================================== - * Function prototypes. - */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ @@ -94,29 +91,16 @@ typedef enum { finish_done /* finish done, accept no more input or output */ } block_state; -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +typedef block_state (*compress_func)(deflate_state *s, int flush); /* Compression function. Returns the block state after the call. */ -local int deflateStateCheck OF((z_streamp strm)); -local void slide_hash OF((deflate_state *s)); -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_stored(deflate_state *s, int flush); +local block_state deflate_fast(deflate_state *s, int flush); #ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local block_state deflate_rle OF((deflate_state *s, int flush)); -local block_state deflate_huff OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -local uInt longest_match OF((deflate_state *s, IPos cur_match)); - -#ifdef ZLIB_DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); +local block_state deflate_slow(deflate_state *s, int flush); #endif +local block_state deflate_rle(deflate_state *s, int flush); +local block_state deflate_huff(deflate_state *s, int flush); /* =========================================================================== * Local data @@ -219,9 +203,12 @@ local const config configuration_table[10] = { * bit values at the expense of memory usage). We slide even when level == 0 to * keep the hash table consistent if we switch back to level > 0 later. */ -local void slide_hash(s) - deflate_state *s; -{ +#if defined(__has_feature) +# if __has_feature(memory_sanitizer) + __attribute__((no_sanitize("memory"))) +# endif +#endif +local void slide_hash(deflate_state *s) { unsigned n, m; Posf *p; uInt wsize = s->w_size; @@ -245,30 +232,177 @@ local void slide_hash(s) #endif } +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) { + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return len; +} + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(deflate_state *s) { + unsigned n; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize + MAX_DIST(s)) { + + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + if (s->insert > s->strstart) + s->insert = s->strstart; + slide_hash(s); + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + /* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ +int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version, + int stream_size) { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ +int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, int strategy, + const char *version, int stream_size) { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; @@ -410,9 +544,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ -local int deflateStateCheck(strm) - z_streamp strm; -{ +local int deflateStateCheck(z_streamp strm) { deflate_state *s; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) @@ -433,11 +565,8 @@ local int deflateStateCheck(strm) } /* ========================================================================= */ -int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ +int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { deflate_state *s; uInt str, n; int wrap; @@ -502,11 +631,8 @@ int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength) - z_streamp strm; - Bytef *dictionary; - uInt *dictLength; -{ +int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { deflate_state *s; uInt len; @@ -524,9 +650,7 @@ int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateResetKeep(strm) - z_streamp strm; -{ +int ZEXPORT deflateResetKeep(z_streamp strm) { deflate_state *s; if (deflateStateCheck(strm)) { @@ -561,10 +685,32 @@ int ZEXPORT deflateResetKeep(strm) return Z_OK; } +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init(deflate_state *s) { + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +} + /* ========================================================================= */ -int ZEXPORT deflateReset(strm) - z_streamp strm; -{ +int ZEXPORT deflateReset(z_streamp strm) { int ret; ret = deflateResetKeep(strm); @@ -574,10 +720,7 @@ int ZEXPORT deflateReset(strm) } /* ========================================================================= */ -int ZEXPORT deflateSetHeader(strm, head) - z_streamp strm; - gz_headerp head; -{ +int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) { if (deflateStateCheck(strm) || strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; @@ -585,11 +728,7 @@ int ZEXPORT deflateSetHeader(strm, head) } /* ========================================================================= */ -int ZEXPORT deflatePending(strm, pending, bits) - unsigned *pending; - int *bits; - z_streamp strm; -{ +int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; @@ -599,11 +738,7 @@ int ZEXPORT deflatePending(strm, pending, bits) } /* ========================================================================= */ -int ZEXPORT deflatePrime(strm, bits, value) - z_streamp strm; - int bits; - int value; -{ +int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) { deflate_state *s; int put; @@ -626,11 +761,7 @@ int ZEXPORT deflatePrime(strm, bits, value) } /* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ +int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) { deflate_state *s; compress_func func; @@ -675,13 +806,8 @@ int ZEXPORT deflateParams(strm, level, strategy) } /* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ +int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy, + int nice_length, int max_chain) { deflate_state *s; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -717,10 +843,7 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) * * Shifts are used to approximate divisions, for speed. */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ +uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) { deflate_state *s; uLong fixedlen, storelen, wraplen; @@ -776,7 +899,8 @@ uLong ZEXPORT deflateBound(strm, sourceLen) /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return (s->w_bits <= s->hash_bits ? fixedlen : storelen) + wraplen; + return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) + + wraplen; /* default settings: return tight bound for that case -- ~0.03% overhead plus a small constant */ @@ -789,10 +913,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ -local void putShortMSB(s, b) - deflate_state *s; - uInt b; -{ +local void putShortMSB(deflate_state *s, uInt b) { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } @@ -803,9 +924,7 @@ local void putShortMSB(s, b) * applications may wish to modify it to avoid allocating a large * strm->next_out buffer and copying into it. (See also read_buf()). */ -local void flush_pending(strm) - z_streamp strm; -{ +local void flush_pending(z_streamp strm) { unsigned len; deflate_state *s = strm->state; @@ -836,10 +955,7 @@ local void flush_pending(strm) } while (0) /* ========================================================================= */ -int ZEXPORT deflate(strm, flush) - z_streamp strm; - int flush; -{ +int ZEXPORT deflate(z_streamp strm, int flush) { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; @@ -1151,9 +1267,7 @@ int ZEXPORT deflate(strm, flush) } /* ========================================================================= */ -int ZEXPORT deflateEnd(strm) - z_streamp strm; -{ +int ZEXPORT deflateEnd(z_streamp strm) { int status; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1177,11 +1291,10 @@ int ZEXPORT deflateEnd(strm) * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ -int ZEXPORT deflateCopy(dest, source) - z_streamp dest; - z_streamp source; -{ +int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) { #ifdef MAXSEG_64K + (void)dest; + (void)source; return Z_STREAM_ERROR; #else deflate_state *ds; @@ -1229,66 +1342,6 @@ int ZEXPORT deflateCopy(dest, source) #endif /* MAXSEG_64K */ } -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local unsigned read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - zmemcpy(buf, strm->next_in, len); - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, buf, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, buf, len); - } -#endif - strm->next_in += len; - strm->total_in += len; - - return len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init(s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->insert = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -} - #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and @@ -1299,10 +1352,7 @@ local void lm_init(s) * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ +local uInt longest_match(deflate_state *s, IPos cur_match) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ @@ -1450,10 +1500,7 @@ local uInt longest_match(s, cur_match) /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ +local uInt longest_match(deflate_state *s, IPos cur_match) { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ @@ -1514,11 +1561,7 @@ local uInt longest_match(s, cur_match) /* =========================================================================== * Check that the match at match_start is indeed a match. */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ +local void check_match(deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { @@ -1538,137 +1581,6 @@ local void check_match(s, start, match, length) # define check_match(s, start, match, length) #endif /* ZLIB_DEBUG */ -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - unsigned n; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize + MAX_DIST(s)) { - - zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - if (s->insert > s->strstart) - s->insert = s->strstart; - slide_hash(s); - more += wsize; - } - if (s->strm->avail_in == 0) break; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead + s->insert >= MIN_MATCH) { - uInt str = s->strstart - s->insert; - s->ins_h = s->window[str]; - UPDATE_HASH(s, s->ins_h, s->window[str + 1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - while (s->insert) { - UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); -#ifndef FASTEST - s->prev[str & s->w_mask] = s->head[s->ins_h]; -#endif - s->head[s->ins_h] = (Pos)str; - str++; - s->insert--; - if (s->lookahead + s->insert < MIN_MATCH) - break; - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); - - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ - if (s->high_water < s->window_size) { - ulg curr = s->strstart + (ulg)(s->lookahead); - ulg init; - - if (s->high_water < curr) { - /* Previous high water mark below current data -- zero WIN_INIT - * bytes or up to end of window, whichever is less. - */ - init = s->window_size - curr; - if (init > WIN_INIT) - init = WIN_INIT; - zmemzero(s->window + curr, (unsigned)init); - s->high_water = curr + init; - } - else if (s->high_water < (ulg)curr + WIN_INIT) { - /* High water mark at or above current data, but below current data - * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up - * to end of window, whichever is less. - */ - init = (ulg)curr + WIN_INIT - s->high_water; - if (init > s->window_size - s->high_water) - init = s->window_size - s->high_water; - zmemzero(s->window + s->high_water, (unsigned)init); - s->high_water += init; - } - } - - Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, - "not enough room for search"); -} - /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. @@ -1711,10 +1623,7 @@ local void fill_window(s) * copied. It is most efficient with large input and output buffers, which * maximizes the opportunities to have a single copy from next_in to next_out. */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_stored(deflate_state *s, int flush) { /* Smallest worthy block size when not flushing or finishing. By default * this is 32K. This can be as small as 507 bytes for memLevel == 1. For * large input and output buffers, the stored block size will be larger. @@ -1898,10 +1807,7 @@ local block_state deflate_stored(s, flush) * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_fast(deflate_state *s, int flush) { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ @@ -2000,10 +1906,7 @@ local block_state deflate_fast(s, flush) * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_slow(deflate_state *s, int flush) { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ @@ -2131,10 +2034,7 @@ local block_state deflate_slow(s, flush) * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_rle(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ @@ -2205,10 +2105,7 @@ local block_state deflate_rle(s, flush) * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ -local block_state deflate_huff(s, flush) - deflate_state *s; - int flush; -{ +local block_state deflate_huff(deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ for (;;) { diff --git a/src/java.base/share/native/libzip/zlib/deflate.h b/src/java.base/share/native/libzip/zlib/deflate.h index b73f5a04e14..3bba1be7476 100644 --- a/src/java.base/share/native/libzip/zlib/deflate.h +++ b/src/java.base/share/native/libzip/zlib/deflate.h @@ -315,14 +315,14 @@ typedef struct internal_state { memory checker errors from longest match routines */ /* in trees.c */ -void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); -int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); -void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_init(deflate_state *s); +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc); +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last); +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s); +void ZLIB_INTERNAL _tr_align(deflate_state *s); +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) diff --git a/src/java.base/share/native/libzip/zlib/gzclose.c b/src/java.base/share/native/libzip/zlib/gzclose.c index 5cce4b03d2f..eff53ace042 100644 --- a/src/java.base/share/native/libzip/zlib/gzclose.c +++ b/src/java.base/share/native/libzip/zlib/gzclose.c @@ -32,9 +32,7 @@ /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ -int ZEXPORT gzclose(file) - gzFile file; -{ +int ZEXPORT gzclose(gzFile file) { #ifndef NO_GZCOMPRESS gz_statep state; diff --git a/src/java.base/share/native/libzip/zlib/gzguts.h b/src/java.base/share/native/libzip/zlib/gzguts.h index 81bedce5445..ec8655c67fc 100644 --- a/src/java.base/share/native/libzip/zlib/gzguts.h +++ b/src/java.base/share/native/libzip/zlib/gzguts.h @@ -31,9 +31,8 @@ # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif -# ifdef _FILE_OFFSET_BITS -# undef _FILE_OFFSET_BITS -# endif +# undef _FILE_OFFSET_BITS +# undef _TIME_BITS #endif #ifdef HAVE_HIDDEN @@ -143,8 +142,8 @@ /* gz* functions always use library allocation functions */ #ifndef STDC - extern voidp malloc OF((uInt size)); - extern void free OF((voidpf ptr)); + extern voidp malloc(uInt size); + extern void free(voidpf ptr); #endif /* get errno and strerror definition */ @@ -162,10 +161,10 @@ /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); #endif /* default memLevel */ @@ -227,9 +226,9 @@ typedef struct { typedef gz_state FAR *gz_statep; /* shared functions */ -void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +void ZLIB_INTERNAL gz_error(gz_statep, int, const char *); #if defined UNDER_CE -char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +char ZLIB_INTERNAL *gz_strwinerror(DWORD error); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t @@ -238,6 +237,6 @@ char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #ifdef INT_MAX # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #else -unsigned ZLIB_INTERNAL gz_intmax OF((void)); +unsigned ZLIB_INTERNAL gz_intmax(void); # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) #endif diff --git a/src/java.base/share/native/libzip/zlib/gzlib.c b/src/java.base/share/native/libzip/zlib/gzlib.c index 1cbc6d25b16..2900e459f62 100644 --- a/src/java.base/share/native/libzip/zlib/gzlib.c +++ b/src/java.base/share/native/libzip/zlib/gzlib.c @@ -39,10 +39,6 @@ #endif #endif -/* Local functions */ -local void gz_reset OF((gz_statep)); -local gzFile gz_open OF((const void *, int, const char *)); - #if defined UNDER_CE /* Map the Windows error number in ERROR to a locale-dependent error message @@ -54,9 +50,7 @@ local gzFile gz_open OF((const void *, int, const char *)); The gz_strwinerror function does not change the current setting of GetLastError. */ -char ZLIB_INTERNAL *gz_strwinerror(error) - DWORD error; -{ +char ZLIB_INTERNAL *gz_strwinerror(DWORD error) { static char buf[1024]; wchar_t *msgbuf; @@ -96,9 +90,7 @@ char ZLIB_INTERNAL *gz_strwinerror(error) #endif /* UNDER_CE */ /* Reset gzip file state */ -local void gz_reset(state) - gz_statep state; -{ +local void gz_reset(gz_statep state) { state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ state->eof = 0; /* not at end of file */ @@ -114,11 +106,7 @@ local void gz_reset(state) } /* Open a gzip file either by name or file descriptor. */ -local gzFile gz_open(path, fd, mode) - const void *path; - int fd; - const char *mode; -{ +local gzFile gz_open(const void *path, int fd, const char *mode) { gz_statep state; z_size_t len; int oflag; @@ -293,26 +281,17 @@ local gzFile gz_open(path, fd, mode) } /* -- see zlib.h -- */ -gzFile ZEXPORT gzopen(path, mode) - const char *path; - const char *mode; -{ +gzFile ZEXPORT gzopen(const char *path, const char *mode) { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ -gzFile ZEXPORT gzopen64(path, mode) - const char *path; - const char *mode; -{ +gzFile ZEXPORT gzopen64(const char *path, const char *mode) { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ -gzFile ZEXPORT gzdopen(fd, mode) - int fd; - const char *mode; -{ +gzFile ZEXPORT gzdopen(int fd, const char *mode) { char *path; /* identifier for error messages */ gzFile gz; @@ -330,19 +309,13 @@ gzFile ZEXPORT gzdopen(fd, mode) /* -- see zlib.h -- */ #ifdef WIDECHAR -gzFile ZEXPORT gzopen_w(path, mode) - const wchar_t *path; - const char *mode; -{ +gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) { return gz_open(path, -2, mode); } #endif /* -- see zlib.h -- */ -int ZEXPORT gzbuffer(file, size) - gzFile file; - unsigned size; -{ +int ZEXPORT gzbuffer(gzFile file, unsigned size) { gz_statep state; /* get internal structure and check integrity */ @@ -359,16 +332,14 @@ int ZEXPORT gzbuffer(file, size) /* check and set requested size */ if ((size << 1) < size) return -1; /* need to be able to double it */ - if (size < 2) - size = 2; /* need two bytes to check magic header */ + if (size < 8) + size = 8; /* needed to behave well with flushing */ state->want = size; return 0; } /* -- see zlib.h -- */ -int ZEXPORT gzrewind(file) - gzFile file; -{ +int ZEXPORT gzrewind(gzFile file) { gz_statep state; /* get internal structure */ @@ -389,11 +360,7 @@ int ZEXPORT gzrewind(file) } /* -- see zlib.h -- */ -z_off64_t ZEXPORT gzseek64(file, offset, whence) - gzFile file; - z_off64_t offset; - int whence; -{ +z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) { unsigned n; z_off64_t ret; gz_statep state; @@ -466,11 +433,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence) } /* -- see zlib.h -- */ -z_off_t ZEXPORT gzseek(file, offset, whence) - gzFile file; - z_off_t offset; - int whence; -{ +z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) { z_off64_t ret; ret = gzseek64(file, (z_off64_t)offset, whence); @@ -478,9 +441,7 @@ z_off_t ZEXPORT gzseek(file, offset, whence) } /* -- see zlib.h -- */ -z_off64_t ZEXPORT gztell64(file) - gzFile file; -{ +z_off64_t ZEXPORT gztell64(gzFile file) { gz_statep state; /* get internal structure and check integrity */ @@ -495,9 +456,7 @@ z_off64_t ZEXPORT gztell64(file) } /* -- see zlib.h -- */ -z_off_t ZEXPORT gztell(file) - gzFile file; -{ +z_off_t ZEXPORT gztell(gzFile file) { z_off64_t ret; ret = gztell64(file); @@ -505,9 +464,7 @@ z_off_t ZEXPORT gztell(file) } /* -- see zlib.h -- */ -z_off64_t ZEXPORT gzoffset64(file) - gzFile file; -{ +z_off64_t ZEXPORT gzoffset64(gzFile file) { z_off64_t offset; gz_statep state; @@ -528,9 +485,7 @@ z_off64_t ZEXPORT gzoffset64(file) } /* -- see zlib.h -- */ -z_off_t ZEXPORT gzoffset(file) - gzFile file; -{ +z_off_t ZEXPORT gzoffset(gzFile file) { z_off64_t ret; ret = gzoffset64(file); @@ -538,9 +493,7 @@ z_off_t ZEXPORT gzoffset(file) } /* -- see zlib.h -- */ -int ZEXPORT gzeof(file) - gzFile file; -{ +int ZEXPORT gzeof(gzFile file) { gz_statep state; /* get internal structure and check integrity */ @@ -555,10 +508,7 @@ int ZEXPORT gzeof(file) } /* -- see zlib.h -- */ -const char * ZEXPORT gzerror(file, errnum) - gzFile file; - int *errnum; -{ +const char * ZEXPORT gzerror(gzFile file, int *errnum) { gz_statep state; /* get internal structure and check integrity */ @@ -576,9 +526,7 @@ const char * ZEXPORT gzerror(file, errnum) } /* -- see zlib.h -- */ -void ZEXPORT gzclearerr(file) - gzFile file; -{ +void ZEXPORT gzclearerr(gzFile file) { gz_statep state; /* get internal structure and check integrity */ @@ -602,11 +550,7 @@ void ZEXPORT gzclearerr(file) memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ -void ZLIB_INTERNAL gz_error(state, err, msg) - gz_statep state; - int err; - const char *msg; -{ +void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) { /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) @@ -648,8 +592,7 @@ void ZLIB_INTERNAL gz_error(state, err, msg) available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ -unsigned ZLIB_INTERNAL gz_intmax() -{ +unsigned ZLIB_INTERNAL gz_intmax(void) { unsigned p, q; p = 1; diff --git a/src/java.base/share/native/libzip/zlib/gzread.c b/src/java.base/share/native/libzip/zlib/gzread.c index fbe4281b4e0..7b9c9df5fa1 100644 --- a/src/java.base/share/native/libzip/zlib/gzread.c +++ b/src/java.base/share/native/libzip/zlib/gzread.c @@ -29,25 +29,12 @@ #include "gzguts.h" -/* Local functions */ -local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); -local int gz_avail OF((gz_statep)); -local int gz_look OF((gz_statep)); -local int gz_decomp OF((gz_statep)); -local int gz_fetch OF((gz_statep)); -local int gz_skip OF((gz_statep, z_off64_t)); -local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); - /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ -local int gz_load(state, buf, len, have) - gz_statep state; - unsigned char *buf; - unsigned len; - unsigned *have; -{ +local int gz_load(gz_statep state, unsigned char *buf, unsigned len, + unsigned *have) { int ret; unsigned get, max = ((unsigned)-1 >> 2) + 1; @@ -77,9 +64,7 @@ local int gz_load(state, buf, len, have) If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ -local int gz_avail(state) - gz_statep state; -{ +local int gz_avail(gz_statep state) { unsigned got; z_streamp strm = &(state->strm); @@ -112,9 +97,7 @@ local int gz_avail(state) case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ -local int gz_look(state) - gz_statep state; -{ +local int gz_look(gz_statep state) { z_streamp strm = &(state->strm); /* allocate read buffers and inflate memory */ @@ -194,9 +177,7 @@ local int gz_look(state) data. If the gzip stream completes, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->x.have is depleted. Returns 0 on success, -1 on failure. */ -local int gz_decomp(state) - gz_statep state; -{ +local int gz_decomp(gz_statep state) { int ret = Z_OK; unsigned had; z_streamp strm = &(state->strm); @@ -248,9 +229,7 @@ local int gz_decomp(state) looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ -local int gz_fetch(state) - gz_statep state; -{ +local int gz_fetch(gz_statep state) { z_streamp strm = &(state->strm); do { @@ -278,10 +257,7 @@ local int gz_fetch(state) } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ -local int gz_skip(state, len) - gz_statep state; - z_off64_t len; -{ +local int gz_skip(gz_statep state, z_off64_t len) { unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ @@ -313,11 +289,7 @@ local int gz_skip(state, len) input. Return the number of bytes read. If zero is returned, either the end of file was reached, or there was an error. state->err must be consulted in that case to determine which. */ -local z_size_t gz_read(state, buf, len) - gz_statep state; - voidp buf; - z_size_t len; -{ +local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { z_size_t got; unsigned n; @@ -394,11 +366,7 @@ local z_size_t gz_read(state, buf, len) } /* -- see zlib.h -- */ -int ZEXPORT gzread(file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ +int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) { gz_statep state; /* get internal structure */ @@ -430,12 +398,7 @@ int ZEXPORT gzread(file, buf, len) } /* -- see zlib.h -- */ -z_size_t ZEXPORT gzfread(buf, size, nitems, file) - voidp buf; - z_size_t size; - z_size_t nitems; - gzFile file; -{ +z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) { z_size_t len; gz_statep state; @@ -466,9 +429,7 @@ z_size_t ZEXPORT gzfread(buf, size, nitems, file) #else # undef gzgetc #endif -int ZEXPORT gzgetc(file) - gzFile file; -{ +int ZEXPORT gzgetc(gzFile file) { unsigned char buf[1]; gz_statep state; @@ -493,17 +454,12 @@ int ZEXPORT gzgetc(file) return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; } -int ZEXPORT gzgetc_(file) -gzFile file; -{ +int ZEXPORT gzgetc_(gzFile file) { return gzgetc(file); } /* -- see zlib.h -- */ -int ZEXPORT gzungetc(c, file) - int c; - gzFile file; -{ +int ZEXPORT gzungetc(int c, gzFile file) { gz_statep state; /* get internal structure */ @@ -511,6 +467,10 @@ int ZEXPORT gzungetc(c, file) return -1; state = (gz_statep)file; + /* in case this was just opened, set up the input buffer */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) @@ -560,11 +520,7 @@ int ZEXPORT gzungetc(c, file) } /* -- see zlib.h -- */ -char * ZEXPORT gzgets(file, buf, len) - gzFile file; - char *buf; - int len; -{ +char * ZEXPORT gzgets(gzFile file, char *buf, int len) { unsigned left, n; char *str; unsigned char *eol; @@ -624,9 +580,7 @@ char * ZEXPORT gzgets(file, buf, len) } /* -- see zlib.h -- */ -int ZEXPORT gzdirect(file) - gzFile file; -{ +int ZEXPORT gzdirect(gzFile file) { gz_statep state; /* get internal structure */ @@ -644,9 +598,7 @@ int ZEXPORT gzdirect(file) } /* -- see zlib.h -- */ -int ZEXPORT gzclose_r(file) - gzFile file; -{ +int ZEXPORT gzclose_r(gzFile file) { int ret, err; gz_statep state; diff --git a/src/java.base/share/native/libzip/zlib/gzwrite.c b/src/java.base/share/native/libzip/zlib/gzwrite.c index 3aff44cc940..008b03e7021 100644 --- a/src/java.base/share/native/libzip/zlib/gzwrite.c +++ b/src/java.base/share/native/libzip/zlib/gzwrite.c @@ -29,18 +29,10 @@ #include "gzguts.h" -/* Local functions */ -local int gz_init OF((gz_statep)); -local int gz_comp OF((gz_statep, int)); -local int gz_zero OF((gz_statep, z_off64_t)); -local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); - /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on a memory allocation failure, or 0 on success. */ -local int gz_init(state) - gz_statep state; -{ +local int gz_init(gz_statep state) { int ret; z_streamp strm = &(state->strm); @@ -94,10 +86,7 @@ local int gz_init(state) deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ -local int gz_comp(state, flush) - gz_statep state; - int flush; -{ +local int gz_comp(gz_statep state, int flush) { int ret, writ; unsigned have, put, max = ((unsigned)-1 >> 2) + 1; z_streamp strm = &(state->strm); @@ -175,10 +164,7 @@ local int gz_comp(state, flush) /* Compress len zeros to output. Return -1 on a write error or memory allocation failure by gz_comp(), or 0 on success. */ -local int gz_zero(state, len) - gz_statep state; - z_off64_t len; -{ +local int gz_zero(gz_statep state, z_off64_t len) { int first; unsigned n; z_streamp strm = &(state->strm); @@ -208,11 +194,7 @@ local int gz_zero(state, len) /* Write len bytes from buf to file. Return the number of bytes written. If the returned value is less than len, then there was an error. */ -local z_size_t gz_write(state, buf, len) - gz_statep state; - voidpc buf; - z_size_t len; -{ +local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) { z_size_t put = len; /* if len is zero, avoid unnecessary operations */ @@ -276,11 +258,7 @@ local z_size_t gz_write(state, buf, len) } /* -- see zlib.h -- */ -int ZEXPORT gzwrite(file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ +int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) { gz_statep state; /* get internal structure */ @@ -304,12 +282,8 @@ int ZEXPORT gzwrite(file, buf, len) } /* -- see zlib.h -- */ -z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) - voidpc buf; - z_size_t size; - z_size_t nitems; - gzFile file; -{ +z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems, + gzFile file) { z_size_t len; gz_statep state; @@ -334,10 +308,7 @@ z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) } /* -- see zlib.h -- */ -int ZEXPORT gzputc(file, c) - gzFile file; - int c; -{ +int ZEXPORT gzputc(gzFile file, int c) { unsigned have; unsigned char buf[1]; gz_statep state; @@ -382,10 +353,7 @@ int ZEXPORT gzputc(file, c) } /* -- see zlib.h -- */ -int ZEXPORT gzputs(file, s) - gzFile file; - const char *s; -{ +int ZEXPORT gzputs(gzFile file, const char *s) { z_size_t len, put; gz_statep state; @@ -412,8 +380,7 @@ int ZEXPORT gzputs(file, s) #include /* -- see zlib.h -- */ -int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) -{ +int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { int len; unsigned left; char *next; @@ -484,8 +451,7 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) return len; } -int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) -{ +int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { va_list va; int ret; @@ -498,13 +464,10 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) #else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ -int ZEXPORTVA gzprintf(file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) - gzFile file; - const char *format; - int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, - a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; -{ +int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3, + int a4, int a5, int a6, int a7, int a8, int a9, int a10, + int a11, int a12, int a13, int a14, int a15, int a16, + int a17, int a18, int a19, int a20) { unsigned len, left; char *next; gz_statep state; @@ -586,10 +549,7 @@ int ZEXPORTVA gzprintf(file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, #endif /* -- see zlib.h -- */ -int ZEXPORT gzflush(file, flush) - gzFile file; - int flush; -{ +int ZEXPORT gzflush(gzFile file, int flush) { gz_statep state; /* get internal structure */ @@ -618,11 +578,7 @@ int ZEXPORT gzflush(file, flush) } /* -- see zlib.h -- */ -int ZEXPORT gzsetparams(file, level, strategy) - gzFile file; - int level; - int strategy; -{ +int ZEXPORT gzsetparams(gzFile file, int level, int strategy) { gz_statep state; z_streamp strm; @@ -633,7 +589,7 @@ int ZEXPORT gzsetparams(file, level, strategy) strm = &(state->strm); /* check that we're writing and that there's no error */ - if (state->mode != GZ_WRITE || state->err != Z_OK) + if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ @@ -660,9 +616,7 @@ int ZEXPORT gzsetparams(file, level, strategy) } /* -- see zlib.h -- */ -int ZEXPORT gzclose_w(file) - gzFile file; -{ +int ZEXPORT gzclose_w(gzFile file) { int ret = Z_OK; gz_statep state; diff --git a/src/java.base/share/native/libzip/zlib/infback.c b/src/java.base/share/native/libzip/zlib/infback.c index ea7ea83d8d2..f680e2cdbdc 100644 --- a/src/java.base/share/native/libzip/zlib/infback.c +++ b/src/java.base/share/native/libzip/zlib/infback.c @@ -39,9 +39,6 @@ #include "inflate.h" #include "inffast.h" -/* function prototypes */ -local void fixedtables OF((struct inflate_state FAR *state)); - /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. @@ -49,13 +46,9 @@ local void fixedtables OF((struct inflate_state FAR *state)); windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ -int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_streamp strm; -int windowBits; -unsigned char FAR *window; -const char *version; -int stream_size; -{ +int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, const char *version, + int stream_size) { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || @@ -104,9 +97,7 @@ int stream_size; used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ +local void fixedtables(struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; @@ -272,13 +263,8 @@ struct inflate_state FAR *state; inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ -int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_streamp strm; -in_func in; -void FAR *in_desc; -out_func out; -void FAR *out_desc; -{ +int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ @@ -656,9 +642,7 @@ void FAR *out_desc; return ret; } -int ZEXPORT inflateBackEnd(strm) -z_streamp strm; -{ +int ZEXPORT inflateBackEnd(z_streamp strm) { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); diff --git a/src/java.base/share/native/libzip/zlib/inffast.c b/src/java.base/share/native/libzip/zlib/inffast.c index 45aa17d201f..e86dd78d801 100644 --- a/src/java.base/share/native/libzip/zlib/inffast.c +++ b/src/java.base/share/native/libzip/zlib/inffast.c @@ -71,10 +71,7 @@ requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ -void ZLIB_INTERNAL inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ diff --git a/src/java.base/share/native/libzip/zlib/inffast.h b/src/java.base/share/native/libzip/zlib/inffast.h index b8da8bb757a..bc4fb6b0df8 100644 --- a/src/java.base/share/native/libzip/zlib/inffast.h +++ b/src/java.base/share/native/libzip/zlib/inffast.h @@ -32,4 +32,4 @@ subject to change. Applications should only use zlib.h. */ -void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); +void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start); diff --git a/src/java.base/share/native/libzip/zlib/inflate.c b/src/java.base/share/native/libzip/zlib/inflate.c index b236dcafd80..2bbbabc0901 100644 --- a/src/java.base/share/native/libzip/zlib/inflate.c +++ b/src/java.base/share/native/libzip/zlib/inflate.c @@ -115,20 +115,7 @@ # endif #endif -/* function prototypes */ -local int inflateStateCheck OF((z_streamp strm)); -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, - unsigned copy)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, - unsigned len)); - -local int inflateStateCheck(strm) -z_streamp strm; -{ +local int inflateStateCheck(z_streamp strm) { struct inflate_state FAR *state; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) @@ -140,9 +127,7 @@ z_streamp strm; return 0; } -int ZEXPORT inflateResetKeep(strm) -z_streamp strm; -{ +int ZEXPORT inflateResetKeep(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -166,9 +151,7 @@ z_streamp strm; return Z_OK; } -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ +int ZEXPORT inflateReset(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -179,10 +162,7 @@ z_streamp strm; return inflateResetKeep(strm); } -int ZEXPORT inflateReset2(strm, windowBits) -z_streamp strm; -int windowBits; -{ +int ZEXPORT inflateReset2(z_streamp strm, int windowBits) { int wrap; struct inflate_state FAR *state; @@ -219,12 +199,8 @@ int windowBits; return inflateReset(strm); } -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ +int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size) { int ret; struct inflate_state FAR *state; @@ -263,22 +239,17 @@ int stream_size; return ret; } -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ +int ZEXPORT inflateInit_(z_streamp strm, const char *version, + int stream_size) { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ +int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + if (bits == 0) + return Z_OK; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; @@ -302,9 +273,7 @@ int value; used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ +local void fixedtables(struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; @@ -366,7 +335,7 @@ struct inflate_state FAR *state; a.out > inffixed.h */ -void makefixed() +void makefixed(void) { unsigned low, size; struct inflate_state state; @@ -420,11 +389,7 @@ void makefixed() output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ -local int updatewindow(strm, end, copy) -z_streamp strm; -const Bytef *end; -unsigned copy; -{ +local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) { struct inflate_state FAR *state; unsigned dist; @@ -646,10 +611,7 @@ unsigned copy; will return Z_BUF_ERROR if it has not reached the end of the stream. */ -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ +int ZEXPORT inflate(z_streamp strm, int flush) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ @@ -1325,9 +1287,7 @@ int flush; return ret; } -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ +int ZEXPORT inflateEnd(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1339,11 +1299,8 @@ z_streamp strm; return Z_OK; } -int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) -z_streamp strm; -Bytef *dictionary; -uInt *dictLength; -{ +int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, + uInt *dictLength) { struct inflate_state FAR *state; /* check state */ @@ -1362,11 +1319,8 @@ uInt *dictLength; return Z_OK; } -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ +int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, + uInt dictLength) { struct inflate_state FAR *state; unsigned long dictid; int ret; @@ -1397,10 +1351,7 @@ uInt dictLength; return Z_OK; } -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ +int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) { struct inflate_state FAR *state; /* check state */ @@ -1425,11 +1376,8 @@ gz_headerp head; called again with more data and the *have state. *have is initialized to zero for the first call. */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -const unsigned char FAR *buf; -unsigned len; -{ +local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf, + unsigned len) { unsigned got; unsigned next; @@ -1448,9 +1396,7 @@ unsigned len; return next; } -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ +int ZEXPORT inflateSync(z_streamp strm) { unsigned len; /* number of bytes to look at or looked at */ int flags; /* temporary to save header status */ unsigned long in, out; /* temporary to save total_in and total_out */ @@ -1506,9 +1452,7 @@ z_streamp strm; block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ +int ZEXPORT inflateSyncPoint(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1516,10 +1460,7 @@ z_streamp strm; return state->mode == STORED && state->bits == 0; } -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ +int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; @@ -1563,10 +1504,7 @@ z_streamp source; return Z_OK; } -int ZEXPORT inflateUndermine(strm, subvert) -z_streamp strm; -int subvert; -{ +int ZEXPORT inflateUndermine(z_streamp strm, int subvert) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1581,10 +1519,7 @@ int subvert; #endif } -int ZEXPORT inflateValidate(strm, check) -z_streamp strm; -int check; -{ +int ZEXPORT inflateValidate(z_streamp strm, int check) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; @@ -1596,9 +1531,7 @@ int check; return Z_OK; } -long ZEXPORT inflateMark(strm) -z_streamp strm; -{ +long ZEXPORT inflateMark(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) @@ -1609,9 +1542,7 @@ z_streamp strm; (state->mode == MATCH ? state->was - state->length : 0)); } -unsigned long ZEXPORT inflateCodesUsed(strm) -z_streamp strm; -{ +unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return (unsigned long)-1; state = (struct inflate_state FAR *)strm->state; diff --git a/src/java.base/share/native/libzip/zlib/inftrees.c b/src/java.base/share/native/libzip/zlib/inftrees.c index a60b1bfb393..f5a99831c74 100644 --- a/src/java.base/share/native/libzip/zlib/inftrees.c +++ b/src/java.base/share/native/libzip/zlib/inftrees.c @@ -23,7 +23,7 @@ */ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2022 Mark Adler + * Copyright (C) 1995-2023 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -33,7 +33,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.13 Copyright 1995-2022 Mark Adler "; + " inflate 1.3 Copyright 1995-2023 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -53,14 +53,9 @@ const char inflate_copyright[] = table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ -int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work) { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ @@ -86,7 +81,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 203}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, diff --git a/src/java.base/share/native/libzip/zlib/inftrees.h b/src/java.base/share/native/libzip/zlib/inftrees.h index a05314fefbd..21b6dbeb038 100644 --- a/src/java.base/share/native/libzip/zlib/inftrees.h +++ b/src/java.base/share/native/libzip/zlib/inftrees.h @@ -81,6 +81,6 @@ typedef enum { DISTS } codetype; -int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); +int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work); diff --git a/src/java.base/share/native/libzip/zlib/patches/ChangeLog_java b/src/java.base/share/native/libzip/zlib/patches/ChangeLog_java index ff48fdaea06..a5d9e98a7d4 100644 --- a/src/java.base/share/native/libzip/zlib/patches/ChangeLog_java +++ b/src/java.base/share/native/libzip/zlib/patches/ChangeLog_java @@ -1,4 +1,4 @@ -Changes from zlib 1.2.13 +Changes from zlib 1.3 (1) renamed adler32.c -> zadler32.c, crc32c -> zcrc32.c diff --git a/src/java.base/share/native/libzip/zlib/trees.c b/src/java.base/share/native/libzip/zlib/trees.c index 7214373826f..fb26d42babf 100644 --- a/src/java.base/share/native/libzip/zlib/trees.c +++ b/src/java.base/share/native/libzip/zlib/trees.c @@ -146,39 +146,116 @@ struct static_tree_desc_s { int max_length; /* max bit length for the codes */ }; -local const static_tree_desc static_l_desc = +#ifdef NO_INIT_GLOBAL_POINTERS +# define TCONST +#else +# define TCONST const +#endif + +local TCONST static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; -local const static_tree_desc static_d_desc = +local TCONST static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; -local const static_tree_desc static_bl_desc = +local TCONST static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== - * Local (static) routines in this file. + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 */ +local unsigned bi_reverse(unsigned code, int len) { + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, const ct_data *ltree, - const ct_data *dtree)); -local int detect_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned code, int len)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(deflate_state *s) { + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(deflate_state *s) { + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef ZLIB_DEBUG + s->bits_sent = (s->bits_sent + 7) & ~7; +#endif +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) { + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + unsigned code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits - 1]) << 1; + next_code[bits] = (ush)code; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = (ush)bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); + } +} #ifdef GEN_TREES_H -local void gen_trees_header OF((void)); +local void gen_trees_header(void); #endif #ifndef ZLIB_DEBUG @@ -191,27 +268,12 @@ local void gen_trees_header OF((void)); send_bits(s, tree[c].Code, tree[c].Len); } #endif -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef ZLIB_DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ +local void send_bits(deflate_state *s, int value, int length) { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; @@ -253,8 +315,7 @@ local void send_bits(s, value, length) /* =========================================================================== * Initialize the various 'constant' tables. */ -local void tr_static_init() -{ +local void tr_static_init(void) { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ @@ -347,8 +408,7 @@ local void tr_static_init() ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width) - 1 ? ",\n" : ", ")) -void gen_trees_header() -{ +void gen_trees_header(void) { FILE *header = fopen("trees.h", "w"); int i; @@ -397,12 +457,26 @@ void gen_trees_header() } #endif /* GEN_TREES_H */ +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(deflate_state *s) { + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->sym_next = s->matches = 0; +} + /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ -void ZLIB_INTERNAL _tr_init(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_init(deflate_state *s) { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; @@ -425,24 +499,6 @@ void ZLIB_INTERNAL _tr_init(s) init_block(s); } -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->sym_next = s->matches = 0; -} - #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ @@ -472,11 +528,7 @@ local void init_block(s) * when the heap property is re-established (each father smaller than its * two sons). */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ +local void pqdownheap(deflate_state *s, ct_data *tree, int k) { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { @@ -507,10 +559,7 @@ local void pqdownheap(s, tree, k) * The length opt_len is updated; static_len is also updated if stree is * not null. */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ +local void gen_bitlen(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; @@ -585,48 +634,9 @@ local void gen_bitlen(s, desc) } } -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes(tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - unsigned code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits - 1]) << 1; - next_code[bits] = (ush)code; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, - "inconsistent bit counts"); - Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); - - for (n = 0; n <= max_code; n++) { - int len = tree[n].Len; - if (len == 0) continue; - /* Now reverse the bits */ - tree[n].Code = (ush)bi_reverse(next_code[len]++, len); - - Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", - n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1)); - } -} +#ifdef DUMP_BL_TREE +# include +#endif /* =========================================================================== * Construct one Huffman tree and assigns the code bit strings and lengths. @@ -636,10 +646,7 @@ local void gen_codes(tree, max_code, bl_count) * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ -local void build_tree(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ +local void build_tree(deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; @@ -724,11 +731,7 @@ local void build_tree(s, desc) * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -local void scan_tree(s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ +local void scan_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -769,11 +772,7 @@ local void scan_tree(s, tree, max_code) * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -local void send_tree(s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ +local void send_tree(deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ @@ -820,9 +819,7 @@ local void send_tree(s, tree, max_code) * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ -local int build_bl_tree(s) - deflate_state *s; -{ +local int build_bl_tree(deflate_state *s) { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ @@ -855,10 +852,8 @@ local int build_bl_tree(s) * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ +local void send_all_trees(deflate_state *s, int lcodes, int dcodes, + int blcodes) { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); @@ -884,12 +879,8 @@ local void send_all_trees(s, lcodes, dcodes, blcodes) /* =========================================================================== * Send a stored block */ -void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ +void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); @@ -908,9 +899,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ -void ZLIB_INTERNAL _tr_flush_bits(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) { bi_flush(s); } @@ -918,9 +907,7 @@ void ZLIB_INTERNAL _tr_flush_bits(s) * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ -void ZLIB_INTERNAL _tr_align(s) - deflate_state *s; -{ +void ZLIB_INTERNAL _tr_align(deflate_state *s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef ZLIB_DEBUG @@ -929,16 +916,99 @@ void ZLIB_INTERNAL _tr_align(s) bi_flush(s); } +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(deflate_state *s, const ct_data *ltree, + const ct_data *dtree) { + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned sx = 0; /* running index in sym_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->sym_next != 0) do { + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS + 1, ltree); /* send length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= (unsigned)base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and sym_buf is ok: */ + Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); + + } while (sx < s->sym_next); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "block list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(deflate_state *s) { + /* block_mask is the bit mask of block-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long block_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("block-listed") bytes. */ + for (n = 0; n <= 31; n++, block_mask >>= 1) + if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("allow-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "block-listed" or "allow-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and write out the encoded block. */ -void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ +void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf, + ulg stored_len, int last) { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ @@ -1035,11 +1105,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ -int ZLIB_INTERNAL _tr_tally(s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length - MIN_MATCH or unmatched char (dist==0) */ -{ +int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) { s->sym_buf[s->sym_next++] = (uch)dist; s->sym_buf[s->sym_next++] = (uch)(dist >> 8); s->sym_buf[s->sym_next++] = (uch)lc; @@ -1059,147 +1125,3 @@ int ZLIB_INTERNAL _tr_tally(s, dist, lc) } return (s->sym_next == s->sym_end); } - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - const ct_data *ltree; /* literal tree */ - const ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned sx = 0; /* running index in sym_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->sym_next != 0) do { - dist = s->sym_buf[sx++] & 0xff; - dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; - lc = s->sym_buf[sx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code + LITERALS + 1, ltree); /* send length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= (unsigned)base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and sym_buf is ok: */ - Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); - - } while (sx < s->sym_next); - - send_code(s, END_BLOCK, ltree); -} - -/* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "block list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local int detect_data_type(s) - deflate_state *s; -{ - /* block_mask is the bit mask of block-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - unsigned long block_mask = 0xf3ffc07fUL; - int n; - - /* Check for non-textual ("block-listed") bytes. */ - for (n = 0; n <= 31; n++, block_mask >>= 1) - if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0)) - return Z_BINARY; - - /* Check for textual ("allow-listed") bytes. */ - if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 - || s->dyn_ltree[13].Freq != 0) - return Z_TEXT; - for (n = 32; n < LITERALS; n++) - if (s->dyn_ltree[n].Freq != 0) - return Z_TEXT; - - /* There are no "block-listed" or "allow-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef ZLIB_DEBUG - s->bits_sent = (s->bits_sent + 7) & ~7; -#endif -} diff --git a/src/java.base/share/native/libzip/zlib/uncompr.c b/src/java.base/share/native/libzip/zlib/uncompr.c index 24af8d2453f..219c1d264d5 100644 --- a/src/java.base/share/native/libzip/zlib/uncompr.c +++ b/src/java.base/share/native/libzip/zlib/uncompr.c @@ -48,12 +48,8 @@ Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ -int ZEXPORT uncompress2(dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong *sourceLen; -{ +int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong *sourceLen) { z_stream stream; int err; const uInt max = (uInt)-1; @@ -107,11 +103,7 @@ int ZEXPORT uncompress2(dest, destLen, source, sourceLen) err; } -int ZEXPORT uncompress(dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ +int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, + uLong sourceLen) { return uncompress2(dest, destLen, source, &sourceLen); } diff --git a/src/java.base/share/native/libzip/zlib/zadler32.c b/src/java.base/share/native/libzip/zlib/zadler32.c index e1480226310..acfd75b908e 100644 --- a/src/java.base/share/native/libzip/zlib/zadler32.c +++ b/src/java.base/share/native/libzip/zlib/zadler32.c @@ -31,8 +31,6 @@ #include "zutil.h" -local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); - #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ @@ -84,11 +82,7 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #endif /* ========================================================================= */ -uLong ZEXPORT adler32_z(adler, buf, len) - uLong adler; - const Bytef *buf; - z_size_t len; -{ +uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) { unsigned long sum2; unsigned n; @@ -155,20 +149,12 @@ uLong ZEXPORT adler32_z(adler, buf, len) } /* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ +uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) { return adler32_z(adler, buf, len); } /* ========================================================================= */ -local uLong adler32_combine_(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ +local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) { unsigned long sum1; unsigned long sum2; unsigned rem; @@ -193,18 +179,10 @@ local uLong adler32_combine_(adler1, adler2, len2) } /* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ +uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) { return adler32_combine_(adler1, adler2, len2); } -uLong ZEXPORT adler32_combine64(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ +uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) { return adler32_combine_(adler1, adler2, len2); } diff --git a/src/java.base/share/native/libzip/zlib/zconf.h b/src/java.base/share/native/libzip/zlib/zconf.h index 92b7eb23886..2dc7e97efcc 100644 --- a/src/java.base/share/native/libzip/zlib/zconf.h +++ b/src/java.base/share/native/libzip/zlib/zconf.h @@ -265,7 +265,11 @@ #endif #ifdef Z_SOLO - typedef unsigned long z_size_t; +# ifdef _WIN64 + typedef unsigned long long z_size_t; +# else + typedef unsigned long z_size_t; +# endif #else # define z_longlong long long # if defined(NO_SIZE_T) @@ -544,7 +548,7 @@ typedef uLong FAR uLongf; #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else -# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# if defined(_WIN32) && !defined(__GNUC__) # define z_off64_t __int64 # else # define z_off64_t z_off_t diff --git a/src/java.base/share/native/libzip/zlib/zcrc32.c b/src/java.base/share/native/libzip/zlib/zcrc32.c index 24f2350b55d..3f918f76b7c 100644 --- a/src/java.base/share/native/libzip/zlib/zcrc32.c +++ b/src/java.base/share/native/libzip/zlib/zcrc32.c @@ -127,19 +127,6 @@ # define ARMCRC32 #endif -/* Local functions. */ -local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); -local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); - -#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) - local z_word_t byte_swap OF((z_word_t word)); -#endif - -#if defined(W) && !defined(ARMCRC32) - local z_crc_t crc_word OF((z_word_t data)); - local z_word_t crc_word_big OF((z_word_t data)); -#endif - #if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) /* Swap the bytes in a z_word_t to convert between little and big endian. Any @@ -147,9 +134,7 @@ local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); instruction, if one is available. This assumes that word_t is either 32 bits or 64 bits. */ -local z_word_t byte_swap(word) - z_word_t word; -{ +local z_word_t byte_swap(z_word_t word) { # if W == 8 return (word & 0xff00000000000000) >> 56 | @@ -170,24 +155,77 @@ local z_word_t byte_swap(word) } #endif +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Table of powers of x for combining CRC-32s, filled in by make_crc_table() + * below. + */ + local z_crc_t FAR x2n_table[32]; +#else +/* ========================================================================= + * Tables for byte-wise and braided CRC-32 calculations, and a table of powers + * of x for combining CRC-32s, all made by make_crc_table(). + */ +# include "crc32.h" +#endif + /* CRC polynomial. */ #define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */ -#ifdef DYNAMIC_CRC_TABLE +/* + Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, + reflected. For speed, this requires that a not be zero. + */ +local z_crc_t multmodp(z_crc_t a, z_crc_t b) { + z_crc_t m, p; + + m = (z_crc_t)1 << 31; + p = 0; + for (;;) { + if (a & m) { + p ^= b; + if ((a & (m - 1)) == 0) + break; + } + m >>= 1; + b = b & 1 ? (b >> 1) ^ POLY : b >> 1; + } + return p; +} +/* + Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been + initialized. + */ +local z_crc_t x2nmodp(z_off64_t n, unsigned k) { + z_crc_t p; + + p = (z_crc_t)1 << 31; /* x^0 == 1 */ + while (n) { + if (n & 1) + p = multmodp(x2n_table[k & 31], p); + n >>= 1; + k++; + } + return p; +} + +#ifdef DYNAMIC_CRC_TABLE +/* ========================================================================= + * Build the tables for byte-wise and braided CRC-32 calculations, and a table + * of powers of x for combining CRC-32s. + */ local z_crc_t FAR crc_table[256]; -local z_crc_t FAR x2n_table[32]; -local void make_crc_table OF((void)); #ifdef W local z_word_t FAR crc_big_table[256]; local z_crc_t FAR crc_braid_table[W][256]; local z_word_t FAR crc_braid_big_table[W][256]; - local void braid OF((z_crc_t [][256], z_word_t [][256], int, int)); + local void braid(z_crc_t [][256], z_word_t [][256], int, int); #endif #ifdef MAKECRCH - local void write_table OF((FILE *, const z_crc_t FAR *, int)); - local void write_table32hi OF((FILE *, const z_word_t FAR *, int)); - local void write_table64 OF((FILE *, const z_word_t FAR *, int)); + local void write_table(FILE *, const z_crc_t FAR *, int); + local void write_table32hi(FILE *, const z_word_t FAR *, int); + local void write_table64(FILE *, const z_word_t FAR *, int); #endif /* MAKECRCH */ /* @@ -200,7 +238,6 @@ local void make_crc_table OF((void)); /* Definition of once functionality. */ typedef struct once_s once_t; -local void once OF((once_t *, void (*)(void))); /* Check for the availability of atomics. */ #if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \ @@ -220,10 +257,7 @@ struct once_s { invoke once() at the same time. The state must be a once_t initialized with ONCE_INIT. */ -local void once(state, init) - once_t *state; - void (*init)(void); -{ +local void once(once_t *state, void (*init)(void)) { if (!atomic_load(&state->done)) { if (atomic_flag_test_and_set(&state->begun)) while (!atomic_load(&state->done)) @@ -246,10 +280,7 @@ struct once_s { /* Test and set. Alas, not atomic, but tries to minimize the period of vulnerability. */ -local int test_and_set OF((int volatile *)); -local int test_and_set(flag) - int volatile *flag; -{ +local int test_and_set(int volatile *flag) { int was; was = *flag; @@ -258,10 +289,7 @@ local int test_and_set(flag) } /* Run the provided init() function once. This is not thread-safe. */ -local void once(state, init) - once_t *state; - void (*init)(void); -{ +local void once(once_t *state, void (*init)(void)) { if (!state->done) { if (test_and_set(&state->begun)) while (!state->done) @@ -303,8 +331,7 @@ local once_t made = ONCE_INIT; combinations of CRC register values and incoming bytes. */ -local void make_crc_table() -{ +local void make_crc_table(void) { unsigned i, j, n; z_crc_t p; @@ -471,11 +498,7 @@ local void make_crc_table() Write the 32-bit values in table[0..k-1] to out, five per line in hexadecimal separated by commas. */ -local void write_table(out, table, k) - FILE *out; - const z_crc_t FAR *table; - int k; -{ +local void write_table(FILE *out, const z_crc_t FAR *table, int k) { int n; for (n = 0; n < k; n++) @@ -488,11 +511,7 @@ local void write_table(out, table, k) Write the high 32-bits of each value in table[0..k-1] to out, five per line in hexadecimal separated by commas. */ -local void write_table32hi(out, table, k) -FILE *out; -const z_word_t FAR *table; -int k; -{ +local void write_table32hi(FILE *out, const z_word_t FAR *table, int k) { int n; for (n = 0; n < k; n++) @@ -508,11 +527,7 @@ int k; bits. If not, then the type cast and format string can be adjusted accordingly. */ -local void write_table64(out, table, k) - FILE *out; - const z_word_t FAR *table; - int k; -{ +local void write_table64(FILE *out, const z_word_t FAR *table, int k) { int n; for (n = 0; n < k; n++) @@ -522,8 +537,7 @@ local void write_table64(out, table, k) } /* Actually do the deed. */ -int main() -{ +int main(void) { make_crc_table(); return 0; } @@ -535,12 +549,7 @@ int main() Generate the little and big-endian braid tables for the given n and z_word_t size w. Each array must have room for w blocks of 256 elements. */ -local void braid(ltl, big, n, w) - z_crc_t ltl[][256]; - z_word_t big[][256]; - int n; - int w; -{ +local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) { int k; z_crc_t i, p, q; for (k = 0; k < w; k++) { @@ -555,69 +564,13 @@ local void braid(ltl, big, n, w) } #endif -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables for byte-wise and braided CRC-32 calculations, and a table of powers - * of x for combining CRC-32s, all made by make_crc_table(). - */ -#include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Routines used for CRC calculation. Some are also required for the table - * generation above. - */ - -/* - Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, - reflected. For speed, this requires that a not be zero. - */ -local z_crc_t multmodp(a, b) - z_crc_t a; - z_crc_t b; -{ - z_crc_t m, p; - - m = (z_crc_t)1 << 31; - p = 0; - for (;;) { - if (a & m) { - p ^= b; - if ((a & (m - 1)) == 0) - break; - } - m >>= 1; - b = b & 1 ? (b >> 1) ^ POLY : b >> 1; - } - return p; -} - -/* - Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been - initialized. - */ -local z_crc_t x2nmodp(n, k) - z_off64_t n; - unsigned k; -{ - z_crc_t p; - - p = (z_crc_t)1 << 31; /* x^0 == 1 */ - while (n) { - if (n & 1) - p = multmodp(x2n_table[k & 31], p); - n >>= 1; - k++; - } - return p; -} - /* ========================================================================= * This function can be used by asm versions of crc32(), and to force the * generation of the CRC tables in a threaded application. */ -const z_crc_t FAR * ZEXPORT get_crc_table() -{ +const z_crc_t FAR * ZEXPORT get_crc_table(void) { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ @@ -643,11 +596,8 @@ const z_crc_t FAR * ZEXPORT get_crc_table() #define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */ #define Z_BATCH_MIN 800 /* fewest words in a final batch */ -unsigned long ZEXPORT crc32_z(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { z_crc_t val; z_word_t crc1, crc2; const z_word_t *word; @@ -747,18 +697,14 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) least-significant byte of the word as the first byte of data, without any pre or post conditioning. This is used to combine the CRCs of each braid. */ -local z_crc_t crc_word(data) - z_word_t data; -{ +local z_crc_t crc_word(z_word_t data) { int k; for (k = 0; k < W; k++) data = (data >> 8) ^ crc_table[data & 0xff]; return (z_crc_t)data; } -local z_word_t crc_word_big(data) - z_word_t data; -{ +local z_word_t crc_word_big(z_word_t data) { int k; for (k = 0; k < W; k++) data = (data << 8) ^ @@ -769,11 +715,8 @@ local z_word_t crc_word_big(data) #endif /* ========================================================================= */ -unsigned long ZEXPORT crc32_z(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ +unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf, + z_size_t len) { /* Return initial CRC, if requested. */ if (buf == Z_NULL) return 0; @@ -805,8 +748,8 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) words = (z_word_t const *)buf; /* Do endian check at execution time instead of compile time, since ARM - processors can change the endianess at execution time. If the - compiler knows what the endianess will be, it can optimize out the + processors can change the endianness at execution time. If the + compiler knows what the endianness will be, it can optimize out the check and the unused branch. */ endian = 1; if (*(unsigned char *)&endian) { @@ -1093,20 +1036,13 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) #endif /* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - uInt len; -{ +unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf, + uInt len) { return crc32_z(crc, buf, len); } /* ========================================================================= */ -uLong ZEXPORT crc32_combine64(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off64_t len2; -{ +uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ @@ -1114,18 +1050,12 @@ uLong ZEXPORT crc32_combine64(crc1, crc2, len2) } /* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ +uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) { return crc32_combine64(crc1, crc2, (z_off64_t)len2); } /* ========================================================================= */ -uLong ZEXPORT crc32_combine_gen64(len2) - z_off64_t len2; -{ +uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) { #ifdef DYNAMIC_CRC_TABLE once(&made, make_crc_table); #endif /* DYNAMIC_CRC_TABLE */ @@ -1133,17 +1063,11 @@ uLong ZEXPORT crc32_combine_gen64(len2) } /* ========================================================================= */ -uLong ZEXPORT crc32_combine_gen(len2) - z_off_t len2; -{ +uLong ZEXPORT crc32_combine_gen(z_off_t len2) { return crc32_combine_gen64((z_off64_t)len2); } /* ========================================================================= */ -uLong ZEXPORT crc32_combine_op(crc1, crc2, op) - uLong crc1; - uLong crc2; - uLong op; -{ +uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) { return multmodp(op, crc1) ^ (crc2 & 0xffffffff); } diff --git a/src/java.base/share/native/libzip/zlib/zlib.h b/src/java.base/share/native/libzip/zlib/zlib.h index 10146088795..89892a062a3 100644 --- a/src/java.base/share/native/libzip/zlib/zlib.h +++ b/src/java.base/share/native/libzip/zlib/zlib.h @@ -23,9 +23,9 @@ */ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.13, October 13th, 2022 + version 1.3, August 18th, 2023 - Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -61,11 +61,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.13" -#define ZLIB_VERNUM 0x12d0 +#define ZLIB_VERSION "1.3" +#define ZLIB_VERNUM 0x1300 #define ZLIB_VER_MAJOR 1 -#define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 13 +#define ZLIB_VER_MINOR 3 +#define ZLIB_VER_REVISION 0 #define ZLIB_VER_SUBREVISION 0 /* @@ -102,8 +102,8 @@ extern "C" { even in the case of corrupted input. */ -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); +typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size); +typedef void (*free_func)(voidpf opaque, voidpf address); struct internal_state; @@ -241,7 +241,7 @@ typedef gz_header FAR *gz_headerp; /* basic functions */ -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +ZEXTERN const char * ZEXPORT zlibVersion(void); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check @@ -249,12 +249,12 @@ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); */ /* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); +ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default - allocation functions. + allocation functions. total_in, total_out, adler, and msg are initialized. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all @@ -271,7 +271,7 @@ ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); */ -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce @@ -344,8 +344,8 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. + avail_out is greater than six when the flush marker begins, in order to avoid + repeated flush markers upon calling deflate() again when avail_out == 0. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was @@ -384,7 +384,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); */ -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending @@ -399,7 +399,7 @@ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateInit(z_streamp strm); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by @@ -407,7 +407,8 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); read or consumed. The allocation of a sliding window will be deferred to the first call of inflate (if the decompression does not complete on the first call). If zalloc and zfree are set to Z_NULL, inflateInit updates - them to use default allocation functions. + them to use default allocation functions. total_in, total_out, adler, and + msg are initialized. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the @@ -421,7 +422,7 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); */ -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce @@ -541,7 +542,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); */ -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateEnd(z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending @@ -559,12 +560,12 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); */ /* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); +ZEXTERN int ZEXPORT deflateInit2(z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy); This is another version of deflateInit with more compression options. The fields zalloc, zfree and opaque must be initialized before by the caller. @@ -631,9 +632,9 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, compression: this will be done by deflate(). */ -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); +ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this @@ -675,9 +676,9 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, not perform any compression: this will be done by deflate(). */ -ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); +ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); /* Returns the sliding dictionary being maintained by deflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied @@ -697,8 +698,8 @@ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, stream state is inconsistent. */ -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); +ZEXTERN int ZEXPORT deflateCopy(z_streamp dest, + z_streamp source); /* Sets the destination stream as a complete copy of the source stream. @@ -715,20 +716,20 @@ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, destination. */ -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT deflateReset(z_streamp strm); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been - set unchanged. + set unchanged. total_in, total_out, adler, and msg are initialized. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); +ZEXTERN int ZEXPORT deflateParams(z_streamp strm, + int level, + int strategy); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2(). This can be @@ -753,7 +754,7 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be - applied to the the data compressed after deflateParams(). + applied to the data compressed after deflateParams(). deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if @@ -764,11 +765,11 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, retried with more output space. */ -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); +ZEXTERN int ZEXPORT deflateTune(z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for @@ -781,8 +782,8 @@ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); +ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, + uLong sourceLen); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or @@ -796,9 +797,9 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, than Z_FINISH or Z_NO_FLUSH are used. */ -ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, - unsigned *pending, - int *bits)); +ZEXTERN int ZEXPORT deflatePending(z_streamp strm, + unsigned *pending, + int *bits); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not @@ -811,9 +812,9 @@ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, stream state was inconsistent. */ -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); +ZEXTERN int ZEXPORT deflatePrime(z_streamp strm, + int bits, + int value); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits @@ -828,8 +829,8 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, source stream state was inconsistent. */ -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); +ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm, + gz_headerp head); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called @@ -845,16 +846,17 @@ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). + the time set to zero, and os set to the current operating system, with no + extra, name, or comment fields. The gzip header is returned to the default + state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); +ZEXTERN int ZEXPORT inflateInit2(z_streamp strm, + int windowBits); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized @@ -907,9 +909,9 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, deferred until inflate() is called. */ -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); +ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm, + const Bytef *dictionary, + uInt dictLength); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, @@ -930,9 +932,9 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, inflate(). */ -ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); +ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm, + Bytef *dictionary, + uInt *dictLength); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied @@ -945,7 +947,7 @@ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, stream state is inconsistent. */ -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateSync(z_streamp strm); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all @@ -964,8 +966,8 @@ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); input each time, until success or end of the input data. */ -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); +ZEXTERN int ZEXPORT inflateCopy(z_streamp dest, + z_streamp source); /* Sets the destination stream as a complete copy of the source stream. @@ -980,18 +982,19 @@ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, destination. */ -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateReset(z_streamp strm); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. + total_in, total_out, adler, and msg are initialized. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ -ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, - int windowBits)); +ZEXTERN int ZEXPORT inflateReset2(z_streamp strm, + int windowBits); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted @@ -1004,9 +1007,9 @@ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, the windowBits parameter is invalid. */ -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); +ZEXTERN int ZEXPORT inflatePrime(z_streamp strm, + int bits, + int value); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the @@ -1025,7 +1028,7 @@ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, stream state was inconsistent. */ -ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +ZEXTERN long ZEXPORT inflateMark(z_streamp strm); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the @@ -1053,8 +1056,8 @@ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); source stream state was inconsistent. */ -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); +ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm, + gz_headerp head); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after @@ -1094,8 +1097,8 @@ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, */ /* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); +ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits, + unsigned char FAR *window); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized @@ -1115,13 +1118,13 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, the version of the header file. */ -typedef unsigned (*in_func) OF((void FAR *, - z_const unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); +typedef unsigned (*in_func)(void FAR *, + z_const unsigned char FAR * FAR *); +typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned); -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); +ZEXTERN int ZEXPORT inflateBack(z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than @@ -1189,7 +1192,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, cannot return Z_OK. */ -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm); /* All memory allocated by inflateBackInit() is freed. @@ -1197,7 +1200,7 @@ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); state was inconsistent. */ -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +ZEXTERN uLong ZEXPORT zlibCompileFlags(void); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: @@ -1250,8 +1253,8 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); you need special options. */ -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); +ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size @@ -1265,9 +1268,9 @@ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, buffer. */ -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); +ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte @@ -1281,15 +1284,15 @@ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, Z_STREAM_ERROR if the level parameter is invalid. */ -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); +ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size @@ -1306,8 +1309,8 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, buffer with the uncompressed data up to that point. */ -ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong *sourceLen)); +ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen); /* Same as uncompress, except that sourceLen is a pointer, where the length of the source is *sourceLen. On return, *sourceLen is the number of @@ -1326,7 +1329,7 @@ ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode); Open the gzip (.gz) file at path for reading and decompressing, or compressing and writing. The mode parameter is as in fopen ("rb" or "wb") @@ -1363,7 +1366,7 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); file could not be opened. */ -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode); /* Associate a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has @@ -1386,7 +1389,7 @@ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); will not detect if fd is invalid (unless fd is -1). */ -ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size); /* Set the internal buffer size used by this library's functions for file to size. The default buffer size is 8192 bytes. This function must be called @@ -1402,7 +1405,7 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); too late. */ -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy); /* Dynamically update the compression level and strategy for file. See the description of deflateInit2 for the meaning of these parameters. Previously @@ -1413,7 +1416,7 @@ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); or Z_MEM_ERROR if there is a memory allocation error. */ -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len); /* Read and decompress up to len uncompressed bytes from file into buf. If the input file is not in gzip format, gzread copies the given number of @@ -1443,8 +1446,8 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); Z_STREAM_ERROR. */ -ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, - gzFile file)); +ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, + gzFile file); /* Read and decompress up to nitems items of size size from file into buf, otherwise operating as gzread() does. This duplicates the interface of @@ -1469,14 +1472,14 @@ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, file, resetting and retrying on end-of-file, when size is not 1. */ -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); +ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len); /* Compress and write the len uncompressed bytes at buf to file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ -ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, - z_size_t nitems, gzFile file)); +ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, + z_size_t nitems, gzFile file); /* Compress and write nitems items of size size from buf to file, duplicating the interface of stdio's fwrite(), with size_t request and return types. If @@ -1489,7 +1492,7 @@ ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, is returned, and the error state is set to Z_STREAM_ERROR. */ -ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...); /* Convert, format, compress, and write the arguments (...) to file under control of the string format, as in fprintf. gzprintf returns the number of @@ -1504,7 +1507,7 @@ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); This can be determined using zlibCompileFlags(). */ -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s); /* Compress and write the given null-terminated string s to file, excluding the terminating null character. @@ -1512,7 +1515,7 @@ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); gzputs returns the number of characters written, or -1 in case of error. */ -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len); /* Read and decompress bytes from file into buf, until len-1 characters are read, or until a newline character is read and transferred to buf, or an @@ -1526,13 +1529,13 @@ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); buf are indeterminate. */ -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +ZEXTERN int ZEXPORT gzputc(gzFile file, int c); /* Compress and write c, converted to an unsigned char, into file. gzputc returns the value that was written, or -1 in case of error. */ -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +ZEXTERN int ZEXPORT gzgetc(gzFile file); /* Read and decompress one byte from file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. @@ -1541,7 +1544,7 @@ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); points to has been clobbered or not. */ -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +ZEXTERN int ZEXPORT gzungetc(int c, gzFile file); /* Push c back onto the stream for file to be read as the first character on the next read. At least one character of push-back is always allowed. @@ -1553,7 +1556,7 @@ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); gzseek() or gzrewind(). */ -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +ZEXTERN int ZEXPORT gzflush(gzFile file, int flush); /* Flush all pending output to file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function @@ -1569,8 +1572,8 @@ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); */ /* -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); +ZEXTERN z_off_t ZEXPORT gzseek(gzFile file, + z_off_t offset, int whence); Set the starting position to offset relative to whence for the next gzread or gzwrite on file. The offset represents a number of bytes in the @@ -1588,7 +1591,7 @@ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, would be before the current position. */ -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +ZEXTERN int ZEXPORT gzrewind(gzFile file); /* Rewind file. This function is supported only for reading. @@ -1596,7 +1599,7 @@ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); */ /* -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +ZEXTERN z_off_t ZEXPORT gztell(gzFile file); Return the starting position for the next gzread or gzwrite on file. This position represents a number of bytes in the uncompressed data stream, @@ -1607,7 +1610,7 @@ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); */ /* -ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); +ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file); Return the current compressed (actual) read or write offset of file. This offset includes the count of bytes that precede the gzip stream, for example @@ -1616,7 +1619,7 @@ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); be used for a progress indicator. On error, gzoffset() returns -1. */ -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +ZEXTERN int ZEXPORT gzeof(gzFile file); /* Return true (1) if the end-of-file indicator for file has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set @@ -1631,7 +1634,7 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); has grown since the previous end of file was detected. */ -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +ZEXTERN int ZEXPORT gzdirect(gzFile file); /* Return true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. @@ -1652,7 +1655,7 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); gzip file reading and decompression, which may not be desired.) */ -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose(gzFile file); /* Flush all pending output for file, if necessary, close file and deallocate the (de)compression state. Note that once file is closed, you @@ -1665,8 +1668,8 @@ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); last read ended in the middle of a gzip stream, or Z_OK on success. */ -ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); -ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_r(gzFile file); +ZEXTERN int ZEXPORT gzclose_w(gzFile file); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to @@ -1677,7 +1680,7 @@ ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); zlib library. */ -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum); /* Return the error message for the last error which occurred on file. errnum is set to zlib error number. If an error occurred in the file system @@ -1693,7 +1696,7 @@ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); functions above that do not distinguish those cases in their return values. */ -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +ZEXTERN void ZEXPORT gzclearerr(gzFile file); /* Clear the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip @@ -1710,7 +1713,7 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); library. */ -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. An Adler-32 value is in the range of a 32-bit @@ -1730,15 +1733,15 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); if (adler != original_adler) error(); */ -ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, - z_size_t len)); +ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, + z_size_t len); /* Same as adler32(), but with a size_t length. */ /* -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); +ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, + z_off_t len2); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for @@ -1748,7 +1751,7 @@ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, negative, the result has no meaning or utility. */ -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer. @@ -1766,14 +1769,14 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); if (crc != original_crc) error(); */ -ZEXTERN uLong ZEXPORT crc32_z OF((uLong crc, const Bytef *buf, - z_size_t len)); +ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf, + z_size_t len); /* Same as crc32(), but with a size_t length. */ /* -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); +ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were @@ -1783,13 +1786,13 @@ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); */ /* -ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t len2)); +ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2); Return the operator corresponding to length len2, to be used with crc32_combine_op(). */ -ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op)); +ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op); /* Give the same result as crc32_combine(), using op in place of len2. op is is generated from len2 by crc32_combine_gen(). This will be faster than @@ -1802,20 +1805,20 @@ ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op)); /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); +ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateInit_(z_streamp strm, + const char *version, int stream_size); +ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size); +ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, + const char *version, int stream_size); +ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size); #ifdef Z_PREFIX_SET # define z_deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) @@ -1860,7 +1863,7 @@ struct gzFile_s { unsigned char *next; z_off64_t pos; }; -ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ @@ -1877,13 +1880,13 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off64_t)); + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int); + ZEXTERN z_off64_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) @@ -1905,50 +1908,50 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ # define crc32_combine_gen crc32_combine_gen64 # endif # ifndef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); + ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell64(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); # endif #else - ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); + ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *); + ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int); + ZEXTERN z_off_t ZEXPORT gztell(gzFile); + ZEXTERN z_off_t ZEXPORT gzoffset(gzFile); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); #endif #else /* Z_SOLO */ - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t)); + ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t); #endif /* !Z_SOLO */ /* undocumented functions */ -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); -ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); -ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); -ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp)); -ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); -ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +ZEXTERN const char * ZEXPORT zError(int); +ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void); +ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int); +ZEXTERN int ZEXPORT inflateValidate(z_streamp, int); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp); +ZEXTERN int ZEXPORT inflateResetKeep(z_streamp); +ZEXTERN int ZEXPORT deflateResetKeep(z_streamp); #if defined(_WIN32) && !defined(Z_SOLO) -ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, - const char *mode)); +ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path, + const char *mode); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO -ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, - const char *format, - va_list va)); +ZEXTERN int ZEXPORTVA gzvprintf(gzFile file, + const char *format, + va_list va); # endif #endif diff --git a/src/java.base/share/native/libzip/zlib/zutil.c b/src/java.base/share/native/libzip/zlib/zutil.c index ae147967861..92dda78497b 100644 --- a/src/java.base/share/native/libzip/zlib/zutil.c +++ b/src/java.base/share/native/libzip/zlib/zutil.c @@ -48,13 +48,11 @@ z_const char * const z_errmsg[10] = { }; -const char * ZEXPORT zlibVersion() -{ +const char * ZEXPORT zlibVersion(void) { return ZLIB_VERSION; } -uLong ZEXPORT zlibCompileFlags() -{ +uLong ZEXPORT zlibCompileFlags(void) { uLong flags; flags = 0; @@ -145,9 +143,7 @@ uLong ZEXPORT zlibCompileFlags() # endif int ZLIB_INTERNAL z_verbose = verbose; -void ZLIB_INTERNAL z_error(m) - char *m; -{ +void ZLIB_INTERNAL z_error(char *m) { fprintf(stderr, "%s\n", m); exit(1); } @@ -156,9 +152,7 @@ void ZLIB_INTERNAL z_error(m) /* exported to allow conversion of error code to string for compress() and * uncompress() */ -const char * ZEXPORT zError(err) - int err; -{ +const char * ZEXPORT zError(int err) { return ERR_MSG(err); } @@ -172,22 +166,14 @@ const char * ZEXPORT zError(err) #ifndef HAVE_MEMCPY -void ZLIB_INTERNAL zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ +void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } -int ZLIB_INTERNAL zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ +int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) { uInt j; for (j = 0; j < len; j++) { @@ -196,10 +182,7 @@ int ZLIB_INTERNAL zmemcmp(s1, s2, len) return 0; } -void ZLIB_INTERNAL zmemzero(dest, len) - Bytef* dest; - uInt len; -{ +void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ @@ -240,8 +223,7 @@ local ptr_table table[MAX_PTR]; * a protected system like OS/2. Use Microsoft C instead. */ -voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) -{ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; @@ -266,8 +248,7 @@ voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) return buf; } -void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; (void)opaque; @@ -303,14 +284,12 @@ void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) # define _hfree hfree #endif -voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) -{ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } -void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); } @@ -323,25 +302,18 @@ void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); +extern voidp malloc(uInt size); +extern voidp calloc(uInt items, uInt size); +extern void free(voidpf ptr); #endif -voidpf ZLIB_INTERNAL zcalloc(opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } -void ZLIB_INTERNAL zcfree(opaque, ptr) - voidpf opaque; - voidpf ptr; -{ +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; free(ptr); } diff --git a/src/java.base/share/native/libzip/zlib/zutil.h b/src/java.base/share/native/libzip/zlib/zutil.h index a7c842d26df..03922185c96 100644 --- a/src/java.base/share/native/libzip/zlib/zutil.h +++ b/src/java.base/share/native/libzip/zlib/zutil.h @@ -215,9 +215,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); + ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t); + ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t); #endif /* common defaults */ @@ -256,16 +256,16 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # define zmemzero(dest, len) memset(dest, 0, len) # endif #else - void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); + void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len); + int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len); + void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len); #endif /* Diagnostic functions */ #ifdef ZLIB_DEBUG # include extern int ZLIB_INTERNAL z_verbose; - extern void ZLIB_INTERNAL z_error OF((char *m)); + extern void ZLIB_INTERNAL z_error(char *m); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} @@ -282,9 +282,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #endif #ifndef Z_SOLO - voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, - unsigned size)); - void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); + voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, + unsigned size); + void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr); #endif #define ZALLOC(strm, items, size) \ From 7daae1fb4267f92b38f0152611d69b7b89691087 Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Wed, 30 Aug 2023 12:54:57 +0000 Subject: [PATCH 04/86] 8314263: Signed jars triggering Logger finder recursion and StackOverflowError Co-authored-by: Daniel Fuchs Reviewed-by: dfuchs --- .../share/classes/java/lang/System.java | 10 +- .../jdk/internal/logger/BootstrapLogger.java | 53 +++- .../jdk/internal/logger/LazyLoggers.java | 33 +- .../internal/logger/LoggerFinderLoader.java | 60 +++- .../services/java.lang.System$LoggerFinder | 1 + .../PlatformRecursiveLoadingTest.java | 93 ++++++ .../RecursiveLoadingTest.java | 88 ++++++ .../RecursiveLoading/SimpleLoggerFinder.java | 132 ++++++++ .../services/java.lang.System$LoggerFinder | 1 + .../SignedLoggerFinderTest.java | 297 ++++++++++++++++++ .../SimpleLoggerFinder.java | 74 +++++ .../SignedLoggerFinderTest/logging.properties | 14 + 12 files changed, 828 insertions(+), 28 deletions(-) create mode 100644 test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/META-INF/services/java.lang.System$LoggerFinder create mode 100644 test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/PlatformRecursiveLoadingTest.java create mode 100644 test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/RecursiveLoadingTest.java create mode 100644 test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/SimpleLoggerFinder.java create mode 100644 test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/META-INF/services/java.lang.System$LoggerFinder create mode 100644 test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/SignedLoggerFinderTest.java create mode 100644 test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/SimpleLoggerFinder.java create mode 100644 test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/logging.properties diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 31a830782c3..e50858b26f1 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -68,6 +68,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder; import jdk.internal.misc.CarrierThreadLocal; import jdk.internal.misc.Unsafe; import jdk.internal.util.StaticProperty; @@ -1766,13 +1767,16 @@ static LoggerFinder accessProvider() { // We do not need to synchronize: LoggerFinderLoader will // always return the same instance, so if we don't have it, // just fetch it again. - if (service == null) { + LoggerFinder finder = service; + if (finder == null) { PrivilegedAction pa = () -> LoggerFinderLoader.getLoggerFinder(); - service = AccessController.doPrivileged(pa, null, + finder = AccessController.doPrivileged(pa, null, LOGGERFINDER_PERMISSION); + if (finder instanceof TemporaryLoggerFinder) return finder; + service = finder; } - return service; + return finder; } } diff --git a/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java b/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java index 3c99d832b0a..f351b52968d 100644 --- a/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java +++ b/src/java.base/share/classes/jdk/internal/logger/BootstrapLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,6 @@ import java.util.function.Supplier; import java.lang.System.LoggerFinder; import java.lang.System.Logger; -import java.lang.System.Logger.Level; import java.lang.ref.WeakReference; import java.util.Objects; import java.util.concurrent.ExecutionException; @@ -227,9 +226,19 @@ static void flush() { // The accessor in which this logger is temporarily set. final LazyLoggerAccessor holder; + // tests whether the logger is invoked by the loading thread before + // the LoggerFinder is loaded; can be null; + final BooleanSupplier isLoadingThread; + + // returns true if the logger is invoked by the loading thread before the + // LoggerFinder service is loaded + boolean isLoadingThread() { + return isLoadingThread != null && isLoadingThread.getAsBoolean(); + } - BootstrapLogger(LazyLoggerAccessor holder) { + BootstrapLogger(LazyLoggerAccessor holder, BooleanSupplier isLoadingThread) { this.holder = holder; + this.isLoadingThread = isLoadingThread; } // Temporary data object storing log events @@ -505,14 +514,15 @@ static LogEvent valueOf(BootstrapLogger bootstrap, PlatformLogger.Level level, static void log(LogEvent log, PlatformLogger.Bridge logger) { final SecurityManager sm = System.getSecurityManager(); if (sm == null || log.acc == null) { - log.log(logger); + BootstrapExecutors.submit(() -> log.log(logger)); } else { // not sure we can actually use lambda here. We may need to create // an anonymous class. Although if we reach here, then it means // the VM is booted. - AccessController.doPrivileged((PrivilegedAction) () -> { - log.log(logger); return null; - }, log.acc); + BootstrapExecutors.submit(() -> + AccessController.doPrivileged((PrivilegedAction) () -> { + log.log(logger); return null; + }, log.acc)); } } @@ -559,8 +569,9 @@ public String getName() { * @return true if the VM is still bootstrapping. */ boolean checkBootstrapping() { - if (isBooted()) { + if (isBooted() && !isLoadingThread()) { BootstrapExecutors.flush(); + holder.getConcreteLogger(this); return false; } return true; @@ -935,10 +946,16 @@ private static boolean useSurrogateLoggers() { // - the logging backend is a custom backend // - the logging backend is JUL, there is no custom config, // and the LogManager has not been initialized yet. - public static synchronized boolean useLazyLoggers() { - return !BootstrapLogger.isBooted() - || DetectBackend.detectedBackend == LoggingBackend.CUSTOM - || useSurrogateLoggers(); + public static boolean useLazyLoggers() { + // Note: avoid triggering the initialization of the DetectBackend class + // while holding the BootstrapLogger class monitor + if (!BootstrapLogger.isBooted() || + DetectBackend.detectedBackend == LoggingBackend.CUSTOM) { + return true; + } + synchronized (BootstrapLogger.class) { + return useSurrogateLoggers(); + } } // Called by LazyLoggerAccessor. This method will determine whether @@ -946,9 +963,9 @@ public static synchronized boolean useLazyLoggers() { // a SurrogateLogger (if JUL is the default backend and there // is no custom JUL configuration and LogManager is not yet initialized), // or a logger returned by the loaded LoggerFinder (all other cases). - static Logger getLogger(LazyLoggerAccessor accessor) { - if (!BootstrapLogger.isBooted()) { - return new BootstrapLogger(accessor); + static Logger getLogger(LazyLoggerAccessor accessor, BooleanSupplier isLoading) { + if (!BootstrapLogger.isBooted() || isLoading != null && isLoading.getAsBoolean()) { + return new BootstrapLogger(accessor, isLoading); } else { if (useSurrogateLoggers()) { // JUL is the default backend, there is no custom configuration, @@ -964,6 +981,12 @@ static Logger getLogger(LazyLoggerAccessor accessor) { } } + // trigger class initialization outside of holding lock + static void ensureBackendDetected() { + assert VM.isBooted() : "VM is not booted"; + // triggers detection of the backend + var backend = DetectBackend.detectedBackend; + } // If the backend is JUL, and there is no custom configuration, and // nobody has attempted to call LogManager.getLogManager() yet, then diff --git a/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java b/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java index c7f24a70b59..2c624962876 100644 --- a/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java +++ b/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,9 @@ import java.lang.System.Logger; import java.lang.ref.WeakReference; import java.util.Objects; +import java.util.function.BooleanSupplier; + +import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder; import jdk.internal.misc.VM; import sun.util.logging.PlatformLogger; @@ -110,6 +113,9 @@ static final class LazyLoggerAccessor implements LoggerAccessor { // We need to pass the actual caller module when creating the logger. private final WeakReference moduleRef; + // whether this is the loading thread, can be null + private final BooleanSupplier isLoadingThread; + // The name of the logger that will be created lazyly final String name; // The plain logger SPI object - null until it is accessed for the @@ -122,16 +128,24 @@ static final class LazyLoggerAccessor implements LoggerAccessor { private LazyLoggerAccessor(String name, LazyLoggerFactories factories, Module module) { + this(name, factories, module, null); + } + + private LazyLoggerAccessor(String name, + LazyLoggerFactories factories, + Module module, BooleanSupplier isLoading) { + this(Objects.requireNonNull(name), Objects.requireNonNull(factories), - Objects.requireNonNull(module), null); + Objects.requireNonNull(module), isLoading, null); } private LazyLoggerAccessor(String name, LazyLoggerFactories factories, - Module module, Void unused) { + Module module, BooleanSupplier isLoading, Void unused) { this.name = name; this.factories = factories; this.moduleRef = new WeakReference<>(module); + this.isLoadingThread = isLoading; } /** @@ -162,7 +176,7 @@ public Logger wrapped() { // BootstrapLogger has the logic to decide whether to invoke the // SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger) // logger. - wrapped = BootstrapLogger.getLogger(this); + wrapped = BootstrapLogger.getLogger(this, isLoadingThread); synchronized(this) { // if w has already been in between, simply drop 'wrapped'. setWrappedIfNotSet(wrapped); @@ -194,7 +208,7 @@ public PlatformLogger.Bridge platform() { // BootstrapLogger has the logic to decide whether to invoke the // SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger) // logger. - final Logger wrapped = BootstrapLogger.getLogger(this); + final Logger wrapped = BootstrapLogger.getLogger(this, isLoadingThread); synchronized(this) { // if w has already been set, simply drop 'wrapped'. setWrappedIfNotSet(wrapped); @@ -282,10 +296,10 @@ Logger createLogger() { * Creates a new lazy logger accessor for the named logger. The given * factories will be use when it becomes necessary to actually create * the logger. - * @param An interface that extends {@link Logger}. * @param name The logger name. * @param factories The factories that should be used to create the * wrapped logger. + * @param module The module for which the logger is being created * @return A new LazyLoggerAccessor. */ public static LazyLoggerAccessor makeAccessor(String name, @@ -340,6 +354,7 @@ private static LoggerFinder accessLoggerFinder() { prov = sm == null ? LoggerFinder.getLoggerFinder() : AccessController.doPrivileged( (PrivilegedAction)LoggerFinder::getLoggerFinder); + if (prov instanceof TemporaryLoggerFinder) return prov; provider = prov; } return prov; @@ -359,7 +374,6 @@ public Logger apply(String name, Module module) { new LazyLoggerFactories<>(loggerSupplier); - // A concrete implementation of Logger that delegates to a System.Logger, // but only creates the System.Logger instance lazily when it's used for // the first time. @@ -377,6 +391,11 @@ private JdkLazyLogger(LazyLoggerAccessor holder, Void unused) { } } + static Logger makeLazyLogger(String name, Module module, BooleanSupplier isLoading) { + final LazyLoggerAccessor holder = new LazyLoggerAccessor(name, factories, module, isLoading); + return new JdkLazyLogger(holder, null); + } + /** * Gets a logger from the LoggerFinder. Creates the actual concrete * logger. diff --git a/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java b/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java index 89ab26b8974..932de4ef554 100644 --- a/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java +++ b/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package jdk.internal.logger; import java.io.FilePermission; +import java.lang.System.Logger; +import java.lang.System.LoggerFinder; import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedAction; @@ -32,6 +34,9 @@ import java.util.Locale; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; +import java.util.function.BooleanSupplier; + +import jdk.internal.vm.annotation.Stable; import sun.security.util.SecurityConstants; import sun.security.action.GetBooleanAction; import sun.security.action.GetPropertyAction; @@ -65,13 +70,28 @@ private LoggerFinderLoader() { throw new InternalError("LoggerFinderLoader cannot be instantiated"); } - + // record the loadingThread while loading the backend + static volatile Thread loadingThread; // Return the loaded LoggerFinder, or load it if not already loaded. private static System.LoggerFinder service() { if (service != null) return service; + // ensure backend is detected before attempting to load the finder + BootstrapLogger.ensureBackendDetected(); synchronized(lock) { if (service != null) return service; - service = loadLoggerFinder(); + Thread currentThread = Thread.currentThread(); + if (loadingThread == currentThread) { + // recursive attempt to load the backend while loading the backend + // use a temporary logger finder that returns special BootstrapLogger + // which will wait until loading is finished + return TemporaryLoggerFinder.INSTANCE; + } + loadingThread = currentThread; + try { + service = loadLoggerFinder(); + } finally { + loadingThread = null; + } } // Since the LoggerFinder is already loaded - we can stop using // temporary loggers. @@ -79,6 +99,12 @@ private static System.LoggerFinder service() { return service; } + // returns true if called by the thread that loads the LoggerFinder, while + // loading the LoggerFinder. + static boolean isLoadingThread() { + return loadingThread != null && loadingThread == Thread.currentThread(); + } + // Get configuration error policy private static ErrorPolicy configurationErrorPolicy() { String errorPolicy = @@ -117,6 +143,34 @@ private static Iterator findLoggerFinderProviders() { return iterator; } + public static final class TemporaryLoggerFinder extends LoggerFinder { + private TemporaryLoggerFinder() {} + @Stable + private LoggerFinder loadedService; + + private static final BooleanSupplier isLoadingThread = new BooleanSupplier() { + @Override + public boolean getAsBoolean() { + return LoggerFinderLoader.isLoadingThread(); + } + }; + private static final TemporaryLoggerFinder INSTANCE = new TemporaryLoggerFinder(); + + @Override + public Logger getLogger(String name, Module module) { + if (loadedService == null) { + loadedService = service; + if (loadedService == null) { + return LazyLoggers.makeLazyLogger(name, module, isLoadingThread); + } + } + assert loadedService != null; + assert !LoggerFinderLoader.isLoadingThread(); + assert loadedService != this; + return LazyLoggers.getLogger(name, module); + } + } + // Loads the LoggerFinder using ServiceLoader. If no LoggerFinder // is found returns the default (possibly JUL based) implementation private static System.LoggerFinder loadLoggerFinder() { diff --git a/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/META-INF/services/java.lang.System$LoggerFinder b/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/META-INF/services/java.lang.System$LoggerFinder new file mode 100644 index 00000000000..2471db0e957 --- /dev/null +++ b/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/META-INF/services/java.lang.System$LoggerFinder @@ -0,0 +1 @@ +loggerfinder.SimpleLoggerFinder diff --git a/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/PlatformRecursiveLoadingTest.java b/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/PlatformRecursiveLoadingTest.java new file mode 100644 index 00000000000..9865523e127 --- /dev/null +++ b/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/PlatformRecursiveLoadingTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8314263 + * @summary Creating a logger while loading the Logger finder + * triggers recursion and StackOverflowError + * @modules java.base/sun.util.logging + * @library /test/lib + * @compile RecursiveLoadingTest.java SimpleLoggerFinder.java + * @run main/othervm PlatformRecursiveLoadingTest + */ + + +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.logging.LogRecord; + +import sun.util.logging.PlatformLogger; + +public class PlatformRecursiveLoadingTest { + + /** + * This test triggers recursion by calling `System.getLogger` in the class init and constructor + * of a custom LoggerFinder. Without the fix, this is expected to throw + * java.lang.NoClassDefFoundError: Could not initialize class jdk.internal.logger.LoggerFinderLoader$ErrorPolicy + * caused by: java.lang.StackOverflowError + */ + public static void main(String[] args) throws Throwable { + PlatformLogger.getLogger("main").info("in main"); + List logs = loggerfinder.SimpleLoggerFinder.LOGS; + logs.stream().map(SimpleLogRecord::of).forEach(System.out::println); + logs.stream().map(SimpleLogRecord::of).forEach(SimpleLogRecord::check); + assertEquals(String.valueOf(logs.size()), String.valueOf(3)); + } + + static List asList(Object[] params) { + return params == null ? null : Arrays.asList(params); + } + + record SimpleLogRecord(String message, Instant instant, String loggerName, + java.util.logging.Level level, List params, + String resourceBundleName, long seqNumber, + String sourceClassName, String methodName, Throwable thrown) { + SimpleLogRecord(LogRecord record) { + this(record.getMessage(), record.getInstant(), record.getLoggerName(), record.getLevel(), + asList(record.getParameters()), record.getResourceBundleName(), record.getSequenceNumber(), + record.getSourceClassName(), record.getSourceMethodName(), record.getThrown()); + } + static SimpleLogRecord of(Object o) { + return (o instanceof LogRecord record) ? new SimpleLogRecord(record) : null; + } + static SimpleLogRecord check(SimpleLogRecord record) { + if (record.loggerName.equals("dummy")) { + assertEquals(record.sourceClassName, "jdk.internal.logger.BootstrapLogger$LogEvent"); + assertEquals(record.methodName(), "log"); + } + if (record.loggerName.equals("main")) { + assertEquals(record.sourceClassName, PlatformRecursiveLoadingTest.class.getName()); + assertEquals(record.methodName, "main"); + } + return record; + } + } + + private static void assertEquals(String received, String expected) { + if (!expected.equals(received)) { + throw new RuntimeException("Received: " + received); + } + } +} diff --git a/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/RecursiveLoadingTest.java b/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/RecursiveLoadingTest.java new file mode 100644 index 00000000000..4a7d2b397c5 --- /dev/null +++ b/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/RecursiveLoadingTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8314263 + * @summary Creating a logger while loading the Logger finder + * triggers recursion and StackOverflowError + * @compile RecursiveLoadingTest.java SimpleLoggerFinder.java + * @run main/othervm RecursiveLoadingTest + */ + +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.logging.LogRecord; + +public class RecursiveLoadingTest { + + /** + * This test triggers recursion by calling `System.getLogger` in the class init and constructor + * of a custom LoggerFinder. Without the fix, this is expected to throw + * java.lang.NoClassDefFoundError: Could not initialize class jdk.internal.logger.LoggerFinderLoader$ErrorPolicy + * caused by: java.lang.StackOverflowError + */ + public static void main(String[] args) throws Throwable { + System.getLogger("main").log(System.Logger.Level.INFO, "in main"); + List logs = loggerfinder.SimpleLoggerFinder.LOGS; + logs.stream().map(SimpleLogRecord::of).forEach(System.out::println); + logs.stream().map(SimpleLogRecord::of).forEach(SimpleLogRecord::check); + assertEquals(String.valueOf(logs.size()), String.valueOf(3)); + } + + static List asList(Object[] params) { + return params == null ? null : Arrays.asList(params); + } + + record SimpleLogRecord(String message, Instant instant, String loggerName, + java.util.logging.Level level, List params, + String resourceBundleName, long seqNumber, + String sourceClassName, String methodName, Throwable thrown) { + SimpleLogRecord(LogRecord record) { + this(record.getMessage(), record.getInstant(), record.getLoggerName(), record.getLevel(), + asList(record.getParameters()), record.getResourceBundleName(), record.getSequenceNumber(), + record.getSourceClassName(), record.getSourceMethodName(), record.getThrown()); + } + static SimpleLogRecord of(Object o) { + return (o instanceof LogRecord record) ? new SimpleLogRecord(record) : null; + } + static SimpleLogRecord check(SimpleLogRecord record) { + if (record.loggerName.equals("dummy")) { + assertEquals(record.sourceClassName, "jdk.internal.logger.BootstrapLogger$LogEvent"); + assertEquals(record.methodName(), "log"); + } + if (record.loggerName.equals("main")) { + assertEquals(record.sourceClassName, RecursiveLoadingTest.class.getName()); + assertEquals(record.methodName, "main"); + } + return record; + } + } + + private static void assertEquals(String received, String expected) { + if (!expected.equals(received)) { + throw new RuntimeException("Received: " + received); + } + } +} diff --git a/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/SimpleLoggerFinder.java b/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/SimpleLoggerFinder.java new file mode 100644 index 00000000000..bfa89bbbdae --- /dev/null +++ b/test/jdk/java/lang/System/LoggerFinder/RecursiveLoading/SimpleLoggerFinder.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package loggerfinder; + +import java.lang.*; +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +public class SimpleLoggerFinder extends System.LoggerFinder { + + public static final CopyOnWriteArrayList LOGS = new CopyOnWriteArrayList<>(); + static { + try { + long sleep = new Random().nextLong(1000L) + 1L; + // simulate a slow load service + Thread.sleep(sleep); + System.getLogger("dummy") + .log(System.Logger.Level.INFO, + "Logger finder service load sleep value: " + sleep); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private final Map loggers = new ConcurrentHashMap<>(); + public SimpleLoggerFinder() { + System.getLogger("dummy") + .log(System.Logger.Level.INFO, + "Logger finder service created"); + } + + @Override + public System.Logger getLogger(String name, Module module) { + return loggers.computeIfAbsent(name, SimpleLogger::new); + } + + private static class SimpleLogger implements System.Logger { + private final java.util.logging.Logger logger; + + private static final class SimpleHandler extends Handler { + @Override + public void publish(LogRecord record) { + LOGS.add(record); + } + @Override public void flush() { } + @Override public void close() { } + } + + public SimpleLogger(String name) { + logger = Logger.getLogger(name); + logger.addHandler(new SimpleHandler()); + } + + @Override + public String getName() { + return logger.getName(); + } + + java.util.logging.Level level(Level level) { + return switch (level) { + case ALL -> java.util.logging.Level.ALL; + case DEBUG -> java.util.logging.Level.FINE; + case TRACE -> java.util.logging.Level.FINER; + case INFO -> java.util.logging.Level.INFO; + case WARNING -> java.util.logging.Level.WARNING; + case ERROR -> java.util.logging.Level.SEVERE; + case OFF -> java.util.logging.Level.OFF; + }; + } + + @Override + public boolean isLoggable(Level level) { + return logger.isLoggable(level(level)); + } + + @Override + public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) { + var julLevel = level(level); + if (!logger.isLoggable(julLevel)) return; + if (bundle != null) { + logger.logrb(julLevel, bundle, msg, thrown); + } else { + logger.log(julLevel, msg, thrown); + } + } + + @Override + public void log(Level level, ResourceBundle bundle, String format, Object... params) { + var julLevel = level(level); + if (!logger.isLoggable(julLevel)) return; + if (params == null) { + if (bundle == null) { + logger.log(julLevel, format); + } else { + logger.logrb(julLevel, bundle, format); + } + } else { + if (bundle == null) { + logger.log(julLevel, format, params); + } else { + logger.logrb(julLevel, bundle, format, params); + } + } + } + } +} + diff --git a/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/META-INF/services/java.lang.System$LoggerFinder b/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/META-INF/services/java.lang.System$LoggerFinder new file mode 100644 index 00000000000..2471db0e957 --- /dev/null +++ b/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/META-INF/services/java.lang.System$LoggerFinder @@ -0,0 +1 @@ +loggerfinder.SimpleLoggerFinder diff --git a/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/SignedLoggerFinderTest.java b/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/SignedLoggerFinderTest.java new file mode 100644 index 00000000000..f7b8a316b7f --- /dev/null +++ b/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/SignedLoggerFinderTest.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8314263 + * @summary Signed jars triggering Logger finder recursion and StackOverflowError + * @library /test/lib + * @build jdk.test.lib.compiler.CompilerUtils + * jdk.test.lib.process.* + * jdk.test.lib.util.JarUtils + * jdk.test.lib.JDKToolLauncher + * @compile SignedLoggerFinderTest.java SimpleLoggerFinder.java + * @run main SignedLoggerFinderTest init + * @run main SignedLoggerFinderTest init sign + */ + +import java.io.File; +import java.nio.file.*; +import java.security.*; +import java.util.*; +import java.util.function.*; +import java.util.jar.*; + +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.JarUtils; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static java.util.Arrays.asList; + +public class SignedLoggerFinderTest { + + /** + * This test triggers recursion in the broken JDK. The error can + * manifest in a few different ways. + * One error seen is "java.lang.NoClassDefFoundError: + * Could not initialize class jdk.internal.logger.LoggerFinderLoader$ErrorPolicy" + * + * The original reported error was a StackOverflow (also seen in different iterations + * of this run). Running test in signed and unsigned jar mode for sanity coverage. + * The current bug only manifests when jars are signed. + */ + + private static boolean init = false; + private static boolean signJars = false; + private static boolean mutliThreadLoad = false; + private static volatile boolean testComplete = false; + + private static final String KEYSTORE = "8314263.keystore"; + private static final String ALIAS = "JavaTest"; + private static final String STOREPASS = "changeit"; + private static final String KEYPASS = "changeit"; + private static final String DNAME = "CN=sample"; + private static final String CUSTOM_LOGGER_FINDER_NAME = + "loggerfinder.SimpleLoggerFinder"; + private static final String CUSTOM_LOGGER_NAME = + "loggerfinder.SimpleLoggerFinder$SimpleLogger"; + private static final String INTERNAL_LOGGER_FINDER_NAME = + "sun.util.logging.internal.LoggingProviderImpl"; + private static final String INTERNAL_LOGGER_NAME = + "sun.util.logging.internal.LoggingProviderImpl$JULWrapper"; + private static final Path jarPath1 = + Path.of(System.getProperty("test.classes", "."), "SimpleLoggerFinder.jar"); + private static final Path jarPath2 = + Path.of(System.getProperty("test.classes", "."), "SimpleLoggerFinder2.jar"); + + public static void main(String[] args) throws Throwable { + init = args.length >=1 && args[0].equals("init"); + signJars = args.length >=2 && args[1].equals("sign"); + + // init only passed in by jtreg test run, initialize the environment + // for the subsequent test run + if (init) { + initialize(); + launchTest(false, false); + launchTest(false, true); + launchTest(true, false); + launchTest(true, true); + + } else { + // set up complete. Run the code to trigger the recursion + // We're in the JVM launched by ProcessTools.executeCommand + boolean multiThreadLoad = Boolean.getBoolean("multiThreadLoad"); + boolean withCustomLoggerFinder = Boolean.getBoolean("withCustomLoggerFinder"); + + if (multiThreadLoad) { + long sleep = new Random().nextLong(100L) + 1L; + System.out.println("multi thread load sleep value: " + sleep); + new Thread(runnableWithSleep( + () -> System.getLogger("logger" + System.currentTimeMillis()), + sleep, "System.getLogger type: ")).start(); + new Thread(runnableWithSleep( + () -> System.LoggerFinder.getLoggerFinder(), + sleep, "System.getLoggerFinder type: ")).start(); + } + + if (withCustomLoggerFinder) { + JarFile jf = new JarFile(jarPath1.toString(), true); + jf.getInputStream(jf.getJarEntry("loggerfinder/SimpleLoggerFinder.class")); + JarFile jf2 = new JarFile(jarPath2.toString(), true); + jf2.getInputStream(jf.getJarEntry("loggerfinder/SimpleLoggerFinder.class")); + } else { + // some other call to prod LoggerFinder loading + System.getLogger("random" + System.currentTimeMillis()); + System.LoggerFinder.getLoggerFinder(); + } + Security.setProperty("test_1", "test"); + + // some extra sanity checks + if (withCustomLoggerFinder) { + assertEquals(System.LoggerFinder.getLoggerFinder().getClass().getName(), + CUSTOM_LOGGER_FINDER_NAME); + System.Logger testLogger = System.getLogger("jdk.event.security"); + assertEquals(testLogger.getClass().getName(), CUSTOM_LOGGER_NAME); + } else { + assertEquals(System.LoggerFinder.getLoggerFinder().getClass().getName(), + INTERNAL_LOGGER_FINDER_NAME); + System.Logger testLogger = System.getLogger("jdk.event.security"); + assertEquals(testLogger.getClass().getName(), INTERNAL_LOGGER_NAME); + } + testComplete = true; + + // LoggerFinder should be initialized, trigger a simple log call + Security.setProperty("test_2", "test"); + } + } + + // helper to create the inner test. Run config variations with the LoggerFinder jars + // on the classpath and with other threads running System.Logger calls during load + private static void launchTest(boolean multiThreadLoad, boolean withCustomLoggerFinder) { + List cmds = new ArrayList<>(); + cmds.add(JDKToolFinder.getJDKTool("java")); + cmds.addAll(asList(Utils.getTestJavaOpts())); + if (withCustomLoggerFinder) { + cmds.addAll(List.of("-classpath", + System.getProperty("test.classes") + File.pathSeparator + + jarPath1.toString() + File.pathSeparator + jarPath2.toString(), + "-Dtest.classes=" + System.getProperty("test.classes"))); + } else { + cmds.addAll(List.of("-classpath", + System.getProperty("test.classes"))); + } + cmds.addAll(List.of( + // following debug property seems useful to tickle the issue + "-Dsun.misc.URLClassPath.debug=true", + // console logger level to capture event output + "-Djdk.system.logger.level=DEBUG", + // useful for debug purposes + "-Djdk.logger.finder.error=DEBUG", + // enable logging to verify correct output + "-Djava.util.logging.config.file=" + + Path.of(System.getProperty("test.src", "."), "logging.properties"))); + if (multiThreadLoad) { + cmds.add("-DmultiThreadLoad=true"); + } + if (withCustomLoggerFinder) { + cmds.add("-DwithCustomLoggerFinder=true"); + } + cmds.addAll(List.of( + "SignedLoggerFinderTest", + "no-init")); + + try { + OutputAnalyzer outputAnalyzer = ProcessTools.executeCommand(cmds.stream() + .filter(t -> !t.isEmpty()) + .toArray(String[]::new)) + .shouldHaveExitValue(0); + if (withCustomLoggerFinder) { + outputAnalyzer + .shouldContain("TEST LOGGER: [test_1, test]") + .shouldContain("TEST LOGGER: [test_2, test]"); + } else { + outputAnalyzer + .shouldContain("SecurityPropertyModification: key:test_1") + .shouldContain("SecurityPropertyModification: key:test_2"); + } + if (withCustomLoggerFinder && signJars) { + // X509 cert generated during verification of signed jar file + outputAnalyzer + .shouldContain(DNAME); + } + + } catch (Throwable t) { + throw new RuntimeException("Unexpected fail.", t); + } + } + + private static Runnable runnableWithSleep(Supplier s, long sleep, String desc) { + return () -> { + while(!testComplete) { + System.out.println(desc + s.get().getClass().getName()); + try { + Thread.sleep(sleep); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + }; + } + + private static void initialize() throws Throwable { + if (signJars) { + genKey(); + } + + Path classes = Paths.get(System.getProperty("test.classes", "")); + JarUtils.createJarFile(jarPath1, + classes, + classes.resolve("loggerfinder/SimpleLoggerFinder.class"), + classes.resolve("loggerfinder/SimpleLoggerFinder$SimpleLogger.class")); + + JarUtils.updateJarFile(jarPath1, Path.of(System.getProperty("test.src")), + Path.of("META-INF", "services", "java.lang.System$LoggerFinder")); + if (signJars) { + signJar(jarPath1.toString()); + } + // multiple signed jars with services to have ServiceLoader iteration + Files.copy(jarPath1, jarPath2, REPLACE_EXISTING); + } + + private static void genKey() throws Throwable { + String keytool = JDKToolFinder.getJDKTool("keytool"); + Files.deleteIfExists(Paths.get(KEYSTORE)); + ProcessTools.executeCommand(keytool, + "-J-Duser.language=en", + "-J-Duser.country=US", + "-genkey", + "-keyalg", "rsa", + "-alias", ALIAS, + "-keystore", KEYSTORE, + "-keypass", KEYPASS, + "-dname", DNAME, + "-storepass", STOREPASS + ).shouldHaveExitValue(0); + } + + + private static OutputAnalyzer signJar(String jarName) throws Throwable { + List args = new ArrayList<>(); + args.add("-verbose"); + args.add(jarName); + args.add(ALIAS); + + return jarsigner(args); + } + + private static OutputAnalyzer jarsigner(List extra) + throws Throwable { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jarsigner") + .addVMArg("-Duser.language=en") + .addVMArg("-Duser.country=US") + .addToolArg("-keystore") + .addToolArg(KEYSTORE) + .addToolArg("-storepass") + .addToolArg(STOREPASS) + .addToolArg("-keypass") + .addToolArg(KEYPASS); + for (String s : extra) { + if (s.startsWith("-J")) { + launcher.addVMArg(s.substring(2)); + } else { + launcher.addToolArg(s); + } + } + return ProcessTools.executeCommand(launcher.getCommand()); + } + + private static void assertEquals(String received, String expected) { + if (!expected.equals(received)) { + throw new RuntimeException("Received: " + received); + } + } +} diff --git a/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/SimpleLoggerFinder.java b/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/SimpleLoggerFinder.java new file mode 100644 index 00000000000..f8e021f4073 --- /dev/null +++ b/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/SimpleLoggerFinder.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package loggerfinder; + +import java.lang.*; +import java.util.*; + +public class SimpleLoggerFinder extends System.LoggerFinder { + + static { + try { + long sleep = new Random().nextLong(1000L) + 1L; + System.out.println("Logger finder service load sleep value: " + sleep); + // simulate a slow load service + Thread.sleep(sleep); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + @Override + public System.Logger getLogger(String name, Module module) { + return new SimpleLogger(name); + } + + private static class SimpleLogger implements System.Logger { + private final String name; + + public SimpleLogger(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isLoggable(Level level) { + return true; + } + + @Override + public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) { + System.out.println("TEST LOGGER: " + msg); + } + + @Override + public void log(Level level, ResourceBundle bundle, String format, Object... params) { + System.out.println("TEST LOGGER: " + Arrays.asList(params)); + + } + } +} diff --git a/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/logging.properties b/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/logging.properties new file mode 100644 index 00000000000..33595267e5e --- /dev/null +++ b/test/jdk/java/lang/System/LoggerFinder/SignedLoggerFinderTest/logging.properties @@ -0,0 +1,14 @@ +############################################################ +# Configuration file for log testing +# +############################################################ + +handlers= java.util.logging.ConsoleHandler + +.level= FINE + +java.util.logging.ConsoleHandler.level = FINE +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter + +jdk.event.security.level = FINE + From 93e82c01460a70f214653a558d53c1c6180ae0d3 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 30 Aug 2023 16:11:56 +0000 Subject: [PATCH 05/86] 8314824: Fix serviceability/jvmti/8036666/GetObjectLockCount.java to use vm flags Reviewed-by: sspitsyn, kevinw --- .../serviceability/jvmti/8036666/GetObjectLockCount.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jvmti/8036666/GetObjectLockCount.java b/test/hotspot/jtreg/serviceability/jvmti/8036666/GetObjectLockCount.java index 70b525f552e..e34da9013d5 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/8036666/GetObjectLockCount.java +++ b/test/hotspot/jtreg/serviceability/jvmti/8036666/GetObjectLockCount.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2014 SAP SE. All rights reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,12 +57,14 @@ import com.sun.jdi.request.ClassPrepareRequest; import com.sun.jdi.request.EventRequestManager; +import jdk.test.lib.Utils; /* * @test GetObjectLockCount.java * @bug 8036666 * @summary verify jvm returns correct lock recursion count * @requires vm.jvmti + * @library /test/lib * @run compile -g RecursiveObjectLock.java * @run main/othervm GetObjectLockCount * @author axel.siebenborn@sap.com @@ -71,8 +74,6 @@ public class GetObjectLockCount { public static final String CLASS_NAME = "RecursiveObjectLock"; public static final String METHOD_NAME = "breakpoint1"; - public static final String ARGUMENTS = ""; - /** * Find a com.sun.jdi.CommandLineLaunch connector @@ -119,7 +120,7 @@ static Map connectorArguments(LaunchingConnector con if (optionsArg == null) { throw new Error("Bad launching connector"); } - optionsArg.setValue(ARGUMENTS); + optionsArg.setValue(String.join(" ", Utils.getTestJavaOpts())); return arguments; } From 1ea6463fbb95258725ed4a11621ec662859a76e0 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 30 Aug 2023 16:12:17 +0000 Subject: [PATCH 06/86] 8314835: gtest wrappers should be marked as flagless Reviewed-by: dholmes, stuefe --- test/hotspot/jtreg/gtest/AsyncLogGtest.java | 2 ++ test/hotspot/jtreg/gtest/NMTGtests.java | 5 ++++- test/hotspot/jtreg/gtest/NativeHeapTrimmerGtest.java | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gtest/AsyncLogGtest.java b/test/hotspot/jtreg/gtest/AsyncLogGtest.java index f85f6d5c7e2..302730b1515 100644 --- a/test/hotspot/jtreg/gtest/AsyncLogGtest.java +++ b/test/hotspot/jtreg/gtest/AsyncLogGtest.java @@ -1,5 +1,6 @@ /* * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +34,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml + * @requires vm.flagless * @run main/native GTestWrapper --gtest_filter=AsyncLogTest* -Xlog:async * @run main/native GTestWrapper --gtest_filter=Log*Test* -Xlog:async */ diff --git a/test/hotspot/jtreg/gtest/NMTGtests.java b/test/hotspot/jtreg/gtest/NMTGtests.java index 57666680b6b..6516fde8da5 100644 --- a/test/hotspot/jtreg/gtest/NMTGtests.java +++ b/test/hotspot/jtreg/gtest/NMTGtests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -32,6 +32,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml + * @requires vm.flagless * @run main/native GTestWrapper --gtest_filter=NMT*:os* -XX:NativeMemoryTracking=off */ @@ -40,6 +41,7 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml + * @requires vm.flagless * @run main/native GTestWrapper --gtest_filter=NMT*:os* -XX:NativeMemoryTracking=summary */ @@ -48,5 +50,6 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml + * @requires vm.flagless * @run main/native GTestWrapper --gtest_filter=NMT*:os* -XX:NativeMemoryTracking=detail */ diff --git a/test/hotspot/jtreg/gtest/NativeHeapTrimmerGtest.java b/test/hotspot/jtreg/gtest/NativeHeapTrimmerGtest.java index 7aa3dd8a322..60a93e748f6 100644 --- a/test/hotspot/jtreg/gtest/NativeHeapTrimmerGtest.java +++ b/test/hotspot/jtreg/gtest/NativeHeapTrimmerGtest.java @@ -28,5 +28,6 @@ * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml + * @requires vm.flagless * @run main/native GTestWrapper --gtest_filter=os.trim* -Xlog:trimnative -XX:+UnlockExperimentalVMOptions -XX:TrimNativeHeapInterval=100 */ From 8e4cda063c96f285d4659dbf5bc8bd064393ee93 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 30 Aug 2023 16:14:07 +0000 Subject: [PATCH 07/86] 8314834: serviceability/jdwp/AllModulesCommandTest.java ignores VM flags Reviewed-by: sspitsyn --- .../serviceability/jdwp/DebuggeeLauncher.java | 33 +++---------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java b/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java index 5c3d01ec2dc..8c939833edb 100644 --- a/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java +++ b/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ import jdk.test.lib.JDKToolFinder; import jdk.test.lib.JDWP; import static jdk.test.lib.Asserts.assertFalse; +import jdk.test.lib.process.ProcessTools; /** * Launches the debuggee with the necessary JDWP options and handles the output @@ -54,8 +55,9 @@ public interface Listener { } private int jdwpPort = -1; - private static final String CLS_DIR = System.getProperty("test.classes", "").trim(); private static final String DEBUGGEE = "AllModulesCommandTestDebuggee"; + private static final String JDWP_OPT = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0"; + private Process p; private final Listener listener; private StreamHandler inputHandler; @@ -76,7 +78,7 @@ public DebuggeeLauncher(Listener listener) { */ public void launchDebuggee() throws Throwable { - ProcessBuilder pb = new ProcessBuilder(getCommand()); + ProcessBuilder pb = ProcessTools.createTestJvm(JDWP_OPT, DEBUGGEE); p = pb.start(); inputHandler = new StreamHandler(p.getInputStream(), this); errorHandler = new StreamHandler(p.getErrorStream(), this); @@ -84,22 +86,6 @@ public void launchDebuggee() throws Throwable { errorHandler.start(); } - /** - * Command to start the debuggee with the JDWP options and using the JDK - * under test - * - * @return the command - */ - private String[] getCommand() { - return new String[]{ - JDKToolFinder.getTestJDKTool("java"), - getJdwpOptions(), - "-cp", - CLS_DIR, - DEBUGGEE - }; - } - /** * Terminates the debuggee */ @@ -109,15 +95,6 @@ public void terminateDebuggee() { } } - /** - * Debuggee JDWP options - * - * @return the JDWP options to start the debuggee with - */ - private static String getJdwpOptions() { - return "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0"; - } - /** * Gets JDWP port debuggee is listening on. * From dd64a4a483a831fd66912491af10502c4cf8596b Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 30 Aug 2023 16:58:16 +0000 Subject: [PATCH 08/86] 8315241: (fs) Move toRealPath tests in java/nio/file/Path/Misc.java to separate JUnit 5 test Reviewed-by: rriggs --- test/jdk/java/nio/file/Path/Misc.java | 145 +-------------- test/jdk/java/nio/file/Path/ToRealPath.java | 191 ++++++++++++++++++++ 2 files changed, 193 insertions(+), 143 deletions(-) create mode 100644 test/jdk/java/nio/file/Path/ToRealPath.java diff --git a/test/jdk/java/nio/file/Path/Misc.java b/test/jdk/java/nio/file/Path/Misc.java index 98a68446d22..550f4588f20 100644 --- a/test/jdk/java/nio/file/Path/Misc.java +++ b/test/jdk/java/nio/file/Path/Misc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 7029979 8295753 + * @bug 4313887 6838333 7029979 * @summary Unit test for miscellenous java.nio.file.Path methods * @library .. /test/lib * @build jdk.test.lib.Platform @@ -32,28 +32,17 @@ import java.io.*; import java.nio.file.*; -import static java.nio.file.LinkOption.*; - import jdk.test.lib.Platform; public class Misc { - static boolean supportsLinks; - public static void main(String[] args) throws IOException { Path dir = TestUtil.createTemporaryDirectory(); try { - supportsLinks = TestUtil.supportsLinks(dir); - // equals and hashCode methods testEqualsAndHashCode(); // toFile method testToFile(dir); - - // toRealPath method - testToRealPath(dir); - - } finally { TestUtil.removeAll(dir); } @@ -92,136 +81,6 @@ static void testToFile(Path dir) throws IOException { assertTrue(d.toPath().equals(dir)); } - /** - * Exercise toRealPath method - */ - static void testToRealPath(Path dir) throws IOException { - final Path file = Files.createFile(dir.resolve("foo")); - final Path link = dir.resolve("link"); - - /** - * Test: toRealPath() will access same file as toRealPath(NOFOLLOW_LINKS) - */ - assertTrue(Files.isSameFile(file.toRealPath(), file.toRealPath(NOFOLLOW_LINKS))); - - /** - * Test: toRealPath should fail if file does not exist - */ - Path doesNotExist = dir.resolve("DoesNotExist"); - try { - doesNotExist.toRealPath(); - throw new RuntimeException("IOException expected"); - } catch (IOException expected) { - } - try { - doesNotExist.toRealPath(NOFOLLOW_LINKS); - throw new RuntimeException("IOException expected"); - } catch (IOException expected) { - } - - /** - * Test: toRealPath() should resolve links - */ - if (supportsLinks) { - Path resolvedFile = file; - if (Platform.isWindows()) { - // Path::toRealPath does not work with environments using the - // legacy subst mechanism. This is a workaround to keep the - // test working if 'dir' points to a location on a subst drive. - // See JDK-8213216. - // - Path tempLink = dir.resolve("tempLink"); - Files.createSymbolicLink(tempLink, dir.toAbsolutePath()); - Path resolvedDir = tempLink.toRealPath(); - Files.delete(tempLink); - resolvedFile = resolvedDir.resolve(file.getFileName()); - } - - Files.createSymbolicLink(link, resolvedFile.toAbsolutePath()); - assertTrue(link.toRealPath().equals(resolvedFile.toRealPath())); - Files.delete(link); - } - - /** - * Test: toRealPath(NOFOLLOW_LINKS) should not resolve links - */ - if (supportsLinks) { - Files.createSymbolicLink(link, file.toAbsolutePath()); - assertTrue(link.toRealPath(NOFOLLOW_LINKS).getFileName().equals(link.getFileName())); - Files.delete(link); - } - - /** - * Test: toRealPath(NOFOLLOW_LINKS) with broken link - */ - if (supportsLinks) { - Path broken = Files.createSymbolicLink(link, doesNotExist); - assertTrue(link.toRealPath(NOFOLLOW_LINKS).getFileName().equals(link.getFileName())); - Files.delete(link); - } - - /** - * Test: toRealPath should eliminate "." - */ - assertTrue(dir.resolve(".").toRealPath().equals(dir.toRealPath())); - assertTrue(dir.resolve(".").toRealPath(NOFOLLOW_LINKS).equals(dir.toRealPath(NOFOLLOW_LINKS))); - - /** - * Test: toRealPath should eliminate ".." when it doesn't follow a - * symbolic link - */ - Path subdir = Files.createDirectory(dir.resolve("subdir")); - assertTrue(subdir.resolve("..").toRealPath().equals(dir.toRealPath())); - assertTrue(subdir.resolve("..").toRealPath(NOFOLLOW_LINKS).equals(dir.toRealPath(NOFOLLOW_LINKS))); - - /** - * Test: toRealPath yields accurate case of path elements when - * not following links - */ - if (Platform.isOSX()) { - // theTarget = dir/subdir/theTarget - Path theTarget = Path.of(subdir.toString(), "theTarget"); - Files.createFile(theTarget); - - // dir/theLink -> dir/subdir - Path theLink = Path.of(dir.toString(), "theLink"); - Files.createSymbolicLink(theLink, subdir); - - // thePath = dir/thelink/thetarget (all lower case) - Path thePath = Path.of(dir.toString(), "thelink", "thetarget"); - Path noFollow = thePath.toRealPath(NOFOLLOW_LINKS); - int nc = noFollow.getNameCount(); - - // Real path should retain case as dir/theLink/theTarget - assertTrue(noFollow.getName(nc - 2).equals(Path.of("theLink"))); - assertTrue(noFollow.getName(nc - 1).equals(Path.of("theTarget"))); - assertTrue(noFollow.toString().equals( - Path.of(dir.toString(), "theLink", "theTarget").toString())); - - // Test where a link is preceded by ".." in the path - Path superBeforeLink = - Path.of(subdir.toString(), "..", "thelink", "thetarget"); - noFollow = superBeforeLink.toRealPath(NOFOLLOW_LINKS); - nc = noFollow.getNameCount(); - assertTrue(noFollow.getName(nc - 2).equals(Path.of("theLink"))); - assertTrue(noFollow.getName(nc - 1).equals(Path.of("theTarget"))); - - // Test where a link is followed by ".." in the path - Path linkBeforeSuper = - Path.of(dir.toString(), "thelink", "..", "subdir", "thetarget"); - noFollow = linkBeforeSuper.toRealPath(NOFOLLOW_LINKS); - nc = noFollow.getNameCount(); - assertTrue(noFollow.getName(nc - 4).equals(Path.of("theLink"))); - assertTrue(noFollow.getName(nc - 1).equals(Path.of("theTarget"))); - - Files.delete(theTarget); - } - - // clean-up - Files.delete(subdir); - Files.delete(file); - } - static void assertTrue(boolean okay) { if (!okay) throw new RuntimeException("Assertion Failed"); diff --git a/test/jdk/java/nio/file/Path/ToRealPath.java b/test/jdk/java/nio/file/Path/ToRealPath.java new file mode 100644 index 00000000000..bbf7973b4ff --- /dev/null +++ b/test/jdk/java/nio/file/Path/ToRealPath.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8295753 + * @summary Verify correct operation of Path.toRealPath + * @library .. /test/lib + * @build ToRealPath jdk.test.lib.Platform + * @run junit ToRealPath + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import jdk.test.lib.Platform; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; + +import static java.nio.file.LinkOption.*; +import static org.junit.jupiter.api.Assertions.*; + +public class ToRealPath { + static final boolean SUPPORTS_LINKS; + static final Path DIR; + static final Path SUBDIR; + static final Path FILE; + static final Path LINK; + + static { + try { + DIR = TestUtil.createTemporaryDirectory(); + SUBDIR = Files.createDirectory(DIR.resolve("subdir")); + FILE = Files.createFile(DIR.resolve("foo")); + LINK = DIR.resolve("link"); + SUPPORTS_LINKS = TestUtil.supportsLinks(DIR); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }; + + public boolean supportsLinks() { + return SUPPORTS_LINKS; + } + + @Test + public void locateSameFile() throws IOException { + assertTrue(Files.isSameFile(FILE.toRealPath(), + FILE.toRealPath(NOFOLLOW_LINKS))); + } + + @Test + public void failNotExist() { + Path doesNotExist = DIR.resolve("DoesNotExist"); + assertThrows(IOException.class, () -> doesNotExist.toRealPath()); + } + + @Test + public void failNotExistNoFollow() { + Path doesNotExist = DIR.resolve("DoesNotExist"); + assertThrows(IOException.class, + () -> doesNotExist.toRealPath(NOFOLLOW_LINKS)); + } + + @EnabledIf("supportsLinks") + @Test + public void shouldResolveLinks() throws IOException { + Path resolvedFile = FILE; + if (Platform.isWindows()) { + // Path::toRealPath does not work with environments using the + // legacy subst mechanism. This is a workaround to keep the + // test working if 'dir' points to a location on a subst drive. + // See JDK-8213216. + // + Path tempLink = DIR.resolve("tempLink"); + Files.createSymbolicLink(tempLink, DIR.toAbsolutePath()); + Path resolvedDir = tempLink.toRealPath(); + Files.delete(tempLink); + resolvedFile = resolvedDir.resolve(FILE.getFileName()); + } + + Files.createSymbolicLink(LINK, resolvedFile.toAbsolutePath()); + assertTrue(LINK.toRealPath().equals(resolvedFile.toRealPath())); + Files.delete(LINK); + } + + @Test + @EnabledIf("supportsLinks") + public void shouldNotResolveLinks() throws IOException { + Files.createSymbolicLink(LINK, FILE.toAbsolutePath()); + assertEquals(LINK.toRealPath(NOFOLLOW_LINKS).getFileName(), + LINK.getFileName()); + Files.delete(LINK); + } + + @Test + public void eliminateDot() throws IOException { + assertEquals(DIR.resolve(".").toRealPath(), + DIR.toRealPath()); + } + + @Test + public void eliminateDotNoFollow() throws IOException { + assertEquals(DIR.resolve(".").toRealPath(NOFOLLOW_LINKS), + DIR.toRealPath(NOFOLLOW_LINKS)); + } + + @Test + public void eliminateDots() throws IOException { + assertEquals(SUBDIR.resolve("..").toRealPath(), + DIR.toRealPath()); + } + + @Test + public void eliminateDotsNoFollow() throws IOException { + assertEquals(SUBDIR.resolve("..").toRealPath(NOFOLLOW_LINKS), + DIR.toRealPath(NOFOLLOW_LINKS)); + } + + @Test + @EnabledOnOs(OS.MAC) + public final void macOSTests() throws IOException { + // theTarget = dir/subdir/theTarget + Path theTarget = Path.of(SUBDIR.toString(), "theTarget"); + Files.createFile(theTarget); + + // dir/theLink -> dir/subdir + Path theLink = Path.of(DIR.toString(), "theLink"); + Files.createSymbolicLink(theLink, SUBDIR); + + // thePath = dir/thelink/thetarget (all lower case) + Path thePath = Path.of(DIR.toString(), "thelink", "thetarget"); + Path noFollow = thePath.toRealPath(NOFOLLOW_LINKS); + int nc = noFollow.getNameCount(); + + // Real path should retain case as dir/theLink/theTarget + assertEquals(noFollow.getName(nc - 2), Path.of("theLink")); + assertEquals(noFollow.getName(nc - 1), Path.of("theTarget")); + assertEquals(noFollow.toString(), + Path.of(DIR.toString(), "theLink", "theTarget").toString()); + + // Test where a link is preceded by ".." in the path + Path superBeforeLink = + Path.of(SUBDIR.toString(), "..", "thelink", "thetarget"); + noFollow = superBeforeLink.toRealPath(NOFOLLOW_LINKS); + nc = noFollow.getNameCount(); + assertEquals(noFollow.getName(nc - 2), Path.of("theLink")); + assertEquals(noFollow.getName(nc - 1), Path.of("theTarget")); + + // Test where a link is followed by ".." in the path + Path linkBeforeSuper = + Path.of(DIR.toString(), "thelink", "..", "subdir", "thetarget"); + noFollow = linkBeforeSuper.toRealPath(NOFOLLOW_LINKS); + nc = noFollow.getNameCount(); + assertEquals(noFollow.getName(nc - 4), Path.of("theLink")); + assertEquals(noFollow.getName(nc - 1), Path.of("theTarget")); + + Files.delete(theTarget); + } + + @AfterAll + public static void cleanup() throws IOException { + Files.delete(SUBDIR); + Files.delete(FILE); + } +} From 89d18ea40f3508f4053824fd47f0b0f85fe1d7c2 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 30 Aug 2023 17:51:28 +0000 Subject: [PATCH 09/86] 8312018: Improve reservation of class space and CDS 8313669: Reduced chance for zero-based nKlass encoding since JDK-8296565 Reviewed-by: iklam, adinn --- src/hotspot/os/aix/os_aix.cpp | 9 + src/hotspot/os/bsd/os_bsd.cpp | 11 + src/hotspot/os/linux/os_linux.cpp | 18 + src/hotspot/os/windows/os_windows.cpp | 5 + src/hotspot/share/cds/metaspaceShared.cpp | 8 +- src/hotspot/share/memory/metaspace.cpp | 157 ++++---- src/hotspot/share/memory/metaspace.hpp | 10 +- src/hotspot/share/memory/virtualspace.cpp | 21 +- src/hotspot/share/memory/virtualspace.hpp | 4 + src/hotspot/share/oops/compressedKlass.cpp | 3 +- src/hotspot/share/runtime/globals.hpp | 3 + src/hotspot/share/runtime/os.cpp | 194 ++++++++++ src/hotspot/share/runtime/os.hpp | 12 + src/hotspot/share/utilities/fastrand.hpp | 47 +++ test/hotspot/gtest/runtime/test_os.cpp | 11 + .../gtest/runtime/test_os_reserve_between.cpp | 346 ++++++++++++++++++ test/hotspot/gtest/testutils.hpp | 3 + 17 files changed, 747 insertions(+), 115 deletions(-) create mode 100644 src/hotspot/share/utilities/fastrand.hpp create mode 100644 test/hotspot/gtest/runtime/test_os_reserve_between.cpp diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index f373ab12bd0..e0a403b26f8 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -2166,6 +2166,15 @@ char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool return addr; } +size_t os::vm_min_address() { + // On AIX, we need to make sure we don't block the sbrk. However, this is + // done at actual reservation time, where we honor a "no-mmap" area following + // the break. See MaxExpectedDataSegmentSize. So we can return a very low + // address here. + assert(is_aligned(_vm_min_address_default, os::vm_allocation_granularity()), "Sanity"); + return _vm_min_address_default; +} + // Used to convert frequent JVM_Yield() to nops bool os::dont_yield() { return DontYieldALot; diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index ae4bc6e42a9..054c89f5554 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1822,6 +1822,17 @@ char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool return nullptr; } +size_t os::vm_min_address() { +#ifdef __APPLE__ + // On MacOS, the lowest 4G are denied to the application (see "PAGEZERO" resp. + // -pagezero_size linker option). + return 4 * G; +#else + assert(is_aligned(_vm_min_address_default, os::vm_allocation_granularity()), "Sanity"); + return _vm_min_address_default; +#endif +} + // Used to convert frequent JVM_Yield() to nops bool os::dont_yield() { return DontYieldALot; diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 2563fbf8f5c..3a1785b27b5 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -70,6 +70,7 @@ #include "services/runtimeService.hpp" #include "utilities/align.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/debug.hpp" #include "utilities/decoder.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" @@ -4244,6 +4245,23 @@ char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool return nullptr; } +size_t os::vm_min_address() { + // Determined by sysctl vm.mmap_min_addr. It exists as a safety zone to prevent + // NULL pointer dereferences. + // Most distros set this value to 64 KB. It *can* be zero, but rarely is. Here, + // we impose a minimum value if vm.mmap_min_addr is too low, for increased protection. + static size_t value = 0; + if (value == 0) { + assert(is_aligned(_vm_min_address_default, os::vm_allocation_granularity()), "Sanity"); + FILE* f = fopen("/proc/sys/vm/mmap_min_addr", "r"); + if (fscanf(f, "%zu", &value) != 1) { + value = _vm_min_address_default; + } + value = MAX2(_vm_min_address_default, value); + } + return value; +} + // Used to convert frequent JVM_Yield() to nops bool os::dont_yield() { return DontYieldALot; diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index ad88e714bfc..5563169151b 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3435,6 +3435,11 @@ char* os::pd_attempt_reserve_memory_at(char* addr, size_t bytes, bool exec) { return res; } +size_t os::vm_min_address() { + assert(is_aligned(_vm_min_address_default, os::vm_allocation_granularity()), "Sanity"); + return _vm_min_address_default; +} + char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) { assert(file_desc >= 0, "file_desc is not valid"); return map_memory_to_file(requested_addr, bytes, file_desc); diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index e99ef29ef4e..e5bfb742840 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -1328,8 +1328,12 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma total_space_rs = ReservedSpace(total_range_size, archive_space_alignment, os::vm_page_size(), (char*) base_address); } else { - // Reserve at any address, but leave it up to the platform to choose a good one. - total_space_rs = Metaspace::reserve_address_space_for_compressed_classes(total_range_size); + // We did not manage to reserve at the preferred address, or were instructed to relocate. In that + // case we reserve whereever possible, but the start address needs to be encodable as narrow Klass + // encoding base since the archived heap objects contain nKlass IDs precalculated toward the start + // of the shared Metaspace. That prevents us from using zero-based encoding and therefore we won't + // try allocating in low-address regions. + total_space_rs = Metaspace::reserve_address_space_for_compressed_classes(total_range_size, false /* try_in_low_address_ranges */); } if (!total_space_rs.is_reserved()) { diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index a149deedd23..d8d01e7fd73 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -59,6 +59,7 @@ #include "utilities/debug.hpp" #include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" +#include "virtualspace.hpp" using metaspace::ChunkManager; using metaspace::CommitLimiter; @@ -581,86 +582,71 @@ bool Metaspace::class_space_is_initialized() { return MetaspaceContext::context_class() != nullptr; } -// Reserve a range of memory at an address suitable for en/decoding narrow -// Klass pointers (see: CompressedClassPointers::is_valid_base()). -// The returned address shall both be suitable as a compressed class pointers -// base, and aligned to Metaspace::reserve_alignment (which is equal to or a -// multiple of allocation granularity). -// On error, returns an unreserved space. -ReservedSpace Metaspace::reserve_address_space_for_compressed_classes(size_t size) { - -#if defined(AARCH64) || defined(PPC64) - const size_t alignment = Metaspace::reserve_alignment(); - - // AArch64: Try to align metaspace class space so that we can decode a - // compressed klass with a single MOVK instruction. We can do this iff the - // compressed class base is a multiple of 4G. - // Additionally, above 32G, ensure the lower LogKlassAlignmentInBytes bits - // of the upper 32-bits of the address are zero so we can handle a shift - // when decoding. - - // PPC64: smaller heaps up to 2g will be mapped just below 4g. Then the - // attempt to place the compressed class space just after the heap fails on - // Linux 4.1.42 and higher because the launcher is loaded at 4g - // (ELF_ET_DYN_BASE). In that case we reach here and search the address space - // below 32g to get a zerobased CCS. For simplicity we reuse the search - // strategy for AARCH64. - - static const struct { - address from; - address to; - size_t increment; - } search_ranges[] = { - { (address)(4*G), (address)(32*G), 4*G, }, - { (address)(32*G), (address)(1024*G), (4 << LogKlassAlignmentInBytes) * G }, - { nullptr, nullptr, 0 } - }; - - // Calculate a list of all possible values for the starting address for the - // compressed class space. - ResourceMark rm; - GrowableArray
list(36); - for (int i = 0; search_ranges[i].from != nullptr; i ++) { - address a = search_ranges[i].from; - assert(CompressedKlassPointers::is_valid_base(a), "Sanity"); - while (a < search_ranges[i].to) { - list.append(a); - a += search_ranges[i].increment; +// Reserve a range of memory that is to contain narrow Klass IDs. If "try_in_low_address_ranges" +// is true, we will attempt to reserve memory suitable for zero-based encoding. +ReservedSpace Metaspace::reserve_address_space_for_compressed_classes(size_t size, bool try_in_low_address_ranges) { + + char* result = nullptr; + const bool randomize = RandomizeClassSpaceLocation; + + // First try to reserve in low address ranges. + if (try_in_low_address_ranges) { + constexpr uintptr_t unscaled_max = ((uintptr_t)UINT_MAX + 1); + log_debug(metaspace, map)("Trying below " SIZE_FORMAT_X " for unscaled narrow Klass encoding", unscaled_max); + result = os::attempt_reserve_memory_between(nullptr, (char*)unscaled_max, + size, Metaspace::reserve_alignment(), randomize); + if (result == nullptr) { + constexpr uintptr_t zerobased_max = unscaled_max << LogKlassAlignmentInBytes; + log_debug(metaspace, map)("Trying below " SIZE_FORMAT_X " for zero-based narrow Klass encoding", zerobased_max); + result = os::attempt_reserve_memory_between((char*)unscaled_max, (char*)zerobased_max, + size, Metaspace::reserve_alignment(), randomize); } + } // end: low-address reservation + +#if defined(AARCH64) || defined(PPC64) || defined(S390) + if (result == nullptr) { + // Failing zero-based allocation, or in strict_base mode, try to come up with + // an optimized start address that is amenable to JITs that use 16-bit moves to + // load the encoding base as a short immediate. + // Therefore we try here for an address that when right-shifted by + // LogKlassAlignmentInBytes has only 1s in the third 16-bit quadrant. + // + // Example: for shift=3, the address space searched would be + // [0x0080_0000_0000 - 0xFFF8_0000_0000]. + + // Number of least significant bits that should be zero + constexpr int lo_zero_bits = 32 + LogKlassAlignmentInBytes; + // Number of most significant bits that should be zero + constexpr int hi_zero_bits = 16; + + constexpr size_t alignment = nth_bit(lo_zero_bits); + assert(alignment >= Metaspace::reserve_alignment(), "Sanity"); + constexpr uint64_t min = alignment; + constexpr uint64_t max = nth_bit(64 - hi_zero_bits); + + log_debug(metaspace, map)("Trying between " UINT64_FORMAT_X " and " UINT64_FORMAT_X + " with " SIZE_FORMAT_X " alignment", min, max, alignment); + result = os::attempt_reserve_memory_between((char*)min, (char*)max, size, alignment, randomize); } +#endif // defined(AARCH64) || defined(PPC64) || defined(S390) - int len = list.length(); - int r = 0; - if (!DumpSharedSpaces) { - // Starting from a random position in the list. If the address cannot be reserved - // (the OS already assigned it for something else), go to the next position, wrapping - // around if necessary, until we exhaust all the items. - os::init_random((int)os::javaTimeNanos()); - r = os::random(); - log_info(metaspace)("Randomizing compressed class space: start from %d out of %d locations", - r % len, len); + if (result == nullptr) { + // Fallback: reserve anywhere and hope the resulting block is usable. + log_debug(metaspace, map)("Trying anywhere..."); + result = os::reserve_memory_aligned(size, Metaspace::reserve_alignment(), false); } - for (int i = 0; i < len; i++) { - address a = list.at((i + r) % len); - ReservedSpace rs(size, Metaspace::reserve_alignment(), - os::vm_page_size(), (char*)a); - if (rs.is_reserved()) { - assert(a == (address)rs.base(), "Sanity"); - return rs; - } + + // Wrap resulting range in ReservedSpace + ReservedSpace rs; + if (result != nullptr) { + assert(is_aligned(result, Metaspace::reserve_alignment()), "Alignment too small for metaspace"); + rs = ReservedSpace::space_for_range(result, size, Metaspace::reserve_alignment(), + os::vm_page_size(), false, false); + } else { + rs = ReservedSpace(); } -#endif // defined(AARCH64) || defined(PPC64) - -#ifdef AARCH64 - // Note: on AARCH64, if the code above does not find any good placement, we - // have no recourse. We return an empty space and the VM will exit. - return ReservedSpace(); -#else - // Default implementation: Just reserve anywhere. - return ReservedSpace(size, Metaspace::reserve_alignment(), os::vm_page_size(), (char*)nullptr); -#endif // AARCH64 + return rs; } - #endif // _LP64 size_t Metaspace::reserve_alignment_words() { @@ -781,14 +767,13 @@ void Metaspace::global_initialize() { // case (b) (No CDS) ReservedSpace rs; const size_t size = align_up(CompressedClassSpaceSize, Metaspace::reserve_alignment()); - address base = nullptr; // If CompressedClassSpaceBaseAddress is set, we attempt to force-map class space to // the given address. This is a debug-only feature aiding tests. Due to the ASLR lottery // this may fail, in which case the VM will exit after printing an appropriate message. // Tests using this switch should cope with that. if (CompressedClassSpaceBaseAddress != 0) { - base = (address)CompressedClassSpaceBaseAddress; + const address base = (address)CompressedClassSpaceBaseAddress; if (!is_aligned(base, Metaspace::reserve_alignment())) { vm_exit_during_initialization( err_msg("CompressedClassSpaceBaseAddress=" PTR_FORMAT " invalid " @@ -806,27 +791,9 @@ void Metaspace::global_initialize() { } } - if (!rs.is_reserved()) { - // If UseCompressedOops=1 and the java heap has been placed in coops-friendly - // territory, i.e. its base is under 32G, then we attempt to place ccs - // right above the java heap. - // Otherwise the lower 32G are still free. We try to place ccs at the lowest - // allowed mapping address. - base = (UseCompressedOops && (uint64_t)CompressedOops::base() < OopEncodingHeapMax) ? - CompressedOops::end() : (address)HeapBaseMinAddress; - base = align_up(base, Metaspace::reserve_alignment()); - - if (base != nullptr) { - if (CompressedKlassPointers::is_valid_base(base)) { - rs = ReservedSpace(size, Metaspace::reserve_alignment(), - os::vm_page_size(), (char*)base); - } - } - } - // ...failing that, reserve anywhere, but let platform do optimized placement: if (!rs.is_reserved()) { - rs = Metaspace::reserve_address_space_for_compressed_classes(size); + rs = Metaspace::reserve_address_space_for_compressed_classes(size, true); } // ...failing that, give up. diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index 1efdf980ac8..652a2be35d9 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -74,13 +74,9 @@ class Metaspace : public AllStatic { #ifdef _LP64 - // Reserve a range of memory at an address suitable for en/decoding narrow - // Klass pointers (see: CompressedClassPointers::is_valid_base()). - // The returned address shall both be suitable as a compressed class pointers - // base, and aligned to Metaspace::reserve_alignment (which is equal to or a - // multiple of allocation granularity). - // On error, returns an unreserved space. - static ReservedSpace reserve_address_space_for_compressed_classes(size_t size); + // Reserve a range of memory that is to contain narrow Klass IDs. If "try_in_low_address_ranges" + // is true, we will attempt to reserve memory suitable for zero-based encoding. + static ReservedSpace reserve_address_space_for_compressed_classes(size_t size, bool try_in_low_address_ranges); // Given a prereserved space, use that to set up the compressed class space list. static void initialize_class_space(ReservedSpace rs); diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index dbbf5a3dd5f..1a99b967436 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -355,6 +355,17 @@ void ReservedSpace::release() { } } +// Put a ReservedSpace over an existing range +ReservedSpace ReservedSpace::space_for_range(char* base, size_t size, size_t alignment, + size_t page_size, bool special, bool executable) { + assert(is_aligned(base, os::vm_allocation_granularity()), "Unaligned base"); + assert(is_aligned(size, os::vm_page_size()), "Unaligned size"); + assert(os::page_sizes().contains(page_size), "Invalid pagesize"); + ReservedSpace space; + space.initialize_members(base, size, alignment, page_size, special, executable); + return space; +} + static size_t noaccess_prefix_size(size_t alignment) { return lcm(os::vm_page_size(), alignment); } @@ -546,17 +557,7 @@ void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t ali } // zerobased: Attempt to allocate in the lower 32G. - // But leave room for the compressed class pointers, which is allocated above - // the heap. char *zerobased_max = (char *)OopEncodingHeapMax; - const size_t class_space = align_up(CompressedClassSpaceSize, alignment); - // For small heaps, save some space for compressed class pointer - // space so it can be decoded with no base. - if (UseCompressedClassPointers && !UseSharedSpaces && !DumpSharedSpaces && - OopEncodingHeapMax <= KlassEncodingMetaspaceMax && - (uint64_t)(aligned_heap_base_min_address + size + class_space) <= KlassEncodingMetaspaceMax) { - zerobased_max = (char *)OopEncodingHeapMax - class_space; - } // Give it several tries from top of range to bottom. if (aligned_heap_base_min_address + size <= zerobased_max && // Zerobased theoretical possible. diff --git a/src/hotspot/share/memory/virtualspace.hpp b/src/hotspot/share/memory/virtualspace.hpp index 65650db4f69..264ed0d9749 100644 --- a/src/hotspot/share/memory/virtualspace.hpp +++ b/src/hotspot/share/memory/virtualspace.hpp @@ -107,6 +107,10 @@ class ReservedSpace { bool contains(const void* p) const { return (base() <= ((char*)p)) && (((char*)p) < (base() + size())); } + + // Put a ReservedSpace over an existing range + static ReservedSpace space_for_range(char* base, size_t size, size_t alignment, + size_t page_size, bool special, bool executable); }; ReservedSpace diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index 3821e967af9..f9750c1b7c0 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -62,7 +62,6 @@ void CompressedKlassPointers::initialize_for_given_encoding(address addr, size_t // will encounter (and the implicit promise that there will be no Klass // structures outside this range). void CompressedKlassPointers::initialize(address addr, size_t len) { - assert(is_valid_base(addr), "Address must be a valid encoding base"); address const end = addr + len; address base; @@ -90,6 +89,8 @@ void CompressedKlassPointers::initialize(address addr, size_t len) { set_base(base); set_shift(shift); set_range(range); + + assert(is_valid_base(_base), "Address must be a valid encoding base"); } // Given an address p, return true if p can be used as an encoding base. diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index b61ff2bdaaa..52a4af0aee8 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1419,6 +1419,9 @@ const int ObjectAlignmentInBytes = 8; "Force the class space to be allocated at this address or " \ "fails VM initialization (requires -Xshare=off.") \ \ + develop(bool, RandomizeClassSpaceLocation, true, \ + "Randomize location of class space.") \ + \ product(bool, PrintMetaspaceStatisticsAtExit, false, DIAGNOSTIC, \ "Print metaspace statistics upon VM exit.") \ \ diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index c698a48ffb2..30573591a54 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -74,6 +74,7 @@ #include "utilities/count_trailing_zeros.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" +#include "utilities/fastrand.hpp" #include "utilities/powerOfTwo.hpp" #ifndef _WINDOWS @@ -1811,11 +1812,204 @@ char* os::attempt_reserve_memory_at(char* addr, size_t bytes, bool executable) { char* result = pd_attempt_reserve_memory_at(addr, bytes, executable); if (result != nullptr) { MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + log_debug(os)("Reserved memory at " INTPTR_FORMAT " for " SIZE_FORMAT " bytes.", p2i(addr), bytes); } else { log_debug(os)("Attempt to reserve memory at " INTPTR_FORMAT " for " SIZE_FORMAT " bytes failed, errno %d", p2i(addr), bytes, get_last_error()); } + + return result; +} + +#ifdef ASSERT +static void print_points(const char* s, unsigned* points, unsigned num) { + stringStream ss; + for (unsigned i = 0; i < num; i ++) { + ss.print("%u ", points[i]); + } + log_trace(os, map)("%s, %u Points: %s", s, num, ss.base()); +} +#endif + +// Helper for os::attempt_reserve_memory_between +// Given an array of things, shuffle them (Fisher-Yates) +template +static void shuffle_fisher_yates(T* arr, unsigned num, FastRandom& frand) { + for (unsigned i = num - 1; i >= 1; i--) { + unsigned j = frand.next() % i; + swap(arr[i], arr[j]); + } +} + +// Helper for os::attempt_reserve_memory_between +// Given an array of things, do a hemisphere split such that the resulting +// order is: [first, last, first + 1, last - 1, ...] +template +static void hemi_split(T* arr, unsigned num) { + T* tmp = (T*)::alloca(sizeof(T) * num); + for (unsigned i = 0; i < num; i++) { + tmp[i] = arr[i]; + } + for (unsigned i = 0; i < num; i++) { + arr[i] = is_even(i) ? tmp[i / 2] : tmp[num - (i / 2) - 1]; + } +} + +// Given an address range [min, max), attempts to reserve memory within this area, with the given alignment. +// If randomize is true, the location will be randomized. +char* os::attempt_reserve_memory_between(char* min, char* max, size_t bytes, size_t alignment, bool randomize) { + + // Please keep the following constants in sync with the companion gtests: + + // Number of mmap attemts we will undertake. + constexpr unsigned max_attempts = 32; + + // In randomization mode: We require a minimum number of possible attach points for + // randomness. Below that we refuse to reserve anything. + constexpr unsigned min_random_value_range = 16; + + // In randomization mode: If the possible value range is below this threshold, we + // use a total shuffle without regard for address space fragmentation, otherwise + // we attempt to minimize fragmentation. + constexpr unsigned total_shuffle_threshold = 1024; + +#define ARGSFMT " range [" PTR_FORMAT "-" PTR_FORMAT "), size " SIZE_FORMAT_X ", alignment " SIZE_FORMAT_X ", randomize: %d" +#define ARGSFMTARGS p2i(min), p2i(max), bytes, alignment, randomize + + log_trace(os, map) ("reserve_between (" ARGSFMT ")", ARGSFMTARGS); + + assert(is_power_of_2(alignment), "alignment invalid (" ARGSFMT ")", ARGSFMTARGS); + assert(alignment < SIZE_MAX / 2, "alignment too large (" ARGSFMT ")", ARGSFMTARGS); + assert(is_aligned(bytes, os::vm_page_size()), "size not page aligned (" ARGSFMT ")", ARGSFMTARGS); + assert(max >= min, "invalid range (" ARGSFMT ")", ARGSFMTARGS); + + char* const absolute_max = (char*)(NOT_LP64(G * 3) LP64_ONLY(G * 128 * 1024)); + char* const absolute_min = (char*) os::vm_min_address(); + + const size_t alignment_adjusted = MAX2(alignment, os::vm_allocation_granularity()); + + // Calculate first and last possible attach points: + char* const lo_att = align_up(MAX2(absolute_min, min), alignment_adjusted); + if (lo_att == nullptr) { + return nullptr; // overflow + } + + char* const hi_att = align_down(MIN2(max, absolute_max) - bytes, alignment_adjusted); + if (hi_att > max) { + return nullptr; // overflow + } + + // no possible attach points + if (hi_att < lo_att) { + return nullptr; + } + + char* result = nullptr; + + const size_t num_attach_points = (size_t)((hi_att - lo_att) / alignment_adjusted) + 1; + assert(num_attach_points > 0, "Sanity"); + + // If this fires, the input range is too large for the given alignment (we work + // with int below to keep things simple). Since alignment is bound to page size, + // and the lowest page size is 4K, this gives us a minimum of 4K*4G=8TB address + // range. + assert(num_attach_points <= UINT_MAX, + "Too many possible attach points - range too large or alignment too small (" ARGSFMT ")", ARGSFMTARGS); + + const unsigned num_attempts = MIN2((unsigned)num_attach_points, max_attempts); + unsigned points[max_attempts]; + + if (randomize) { + FastRandom frand; + + if (num_attach_points < min_random_value_range) { + return nullptr; + } + + // We pre-calc the attach points: + // 1 We divide the attach range into equidistant sections and calculate an attach + // point within each section. + // 2 We wiggle those attach points around within their section (depends on attach + // point granularity) + // 3 Should that not be enough to get effective randomization, shuffle all + // attach points + // 4 Otherwise, re-order them to get an optimized probing sequence. + const unsigned stepsize = (unsigned)num_attach_points / num_attempts; + const unsigned half = num_attempts / 2; + + // 1+2: pre-calc points + for (unsigned i = 0; i < num_attempts; i++) { + const unsigned deviation = stepsize > 1 ? (frand.next() % stepsize) : 0; + points[i] = (i * stepsize) + deviation; + } + + if (num_attach_points < total_shuffle_threshold) { + // 3: + // The numeber of possible attach points is too low for the "wiggle" from + // point 2 to be enough to provide randomization. In that case, shuffle + // all attach points at the cost of possible fragmentation (e.g. if we + // end up mapping into the middle of the range). + shuffle_fisher_yates(points, num_attempts, frand); + } else { + // 4 + // We have a large enough number of attach points to satisfy the randomness + // goal without. In that case, we optimize probing by sorting the attach + // points: We attempt outermost points first, then work ourselves up to + // the middle. That reduces address space fragmentation. We also alternate + // hemispheres, which increases the chance of successfull mappings if the + // previous mapping had been blocked by large maps. + hemi_split(points, num_attempts); + } + } // end: randomized + else + { + // Non-randomized. We just attempt to reserve by probing sequentially. We + // alternate between hemispheres, working ourselves up to the middle. + const int stepsize = (unsigned)num_attach_points / num_attempts; + for (unsigned i = 0; i < num_attempts; i++) { + points[i] = (i * stepsize); + } + hemi_split(points, num_attempts); + } + +#ifdef ASSERT + // Print + check all pre-calculated attach points + print_points("before reserve", points, num_attempts); + for (unsigned i = 0; i < num_attempts; i++) { + assert(points[i] < num_attach_points, "Candidate attach point %d out of range (%u, num_attach_points: %zu) " ARGSFMT, + i, points[i], num_attach_points, ARGSFMTARGS); + } +#endif + + // Now reserve + for (unsigned i = 0; result == nullptr && i < num_attempts; i++) { + const unsigned candidate_offset = points[i]; + char* const candidate = lo_att + candidate_offset * alignment_adjusted; + assert(candidate <= hi_att, "Invalid offset %u (" ARGSFMT ")", candidate_offset, ARGSFMTARGS); + result = os::pd_attempt_reserve_memory_at(candidate, bytes, false); + if (!result) { + log_trace(os, map)("Failed to attach at " PTR_FORMAT, p2i(candidate)); + } + } + + // Sanity checks, logging, NMT stuff: + if (result != nullptr) { +#define ERRFMT "result: " PTR_FORMAT " " ARGSFMT +#define ERRFMTARGS p2i(result), ARGSFMTARGS + assert(result >= min, "OOB min (" ERRFMT ")", ERRFMTARGS); + assert((result + bytes) <= max, "OOB max (" ERRFMT ")", ERRFMTARGS); + assert(result >= (char*)os::vm_min_address(), "OOB vm.map min (" ERRFMT ")", ERRFMTARGS); + assert((result + bytes) <= absolute_max, "OOB vm.map max (" ERRFMT ")", ERRFMTARGS); + assert(is_aligned(result, alignment), "alignment invalid (" ERRFMT ")", ERRFMTARGS); + log_trace(os, map)(ERRFMT, ERRFMTARGS); + log_debug(os, map)("successfully attached at " PTR_FORMAT, p2i(result)); + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + } return result; +#undef ARGSFMT +#undef ERRFMT +#undef ARGSFMTARGS +#undef ERRFMTARGS } static void assert_nonempty_range(const char* addr, size_t bytes) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index e13ce72e886..7069a4705a9 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -190,6 +190,11 @@ class os: AllStatic { static OSThread* _starting_thread; static PageSizes _page_sizes; + // The default value for os::vm_min_address() unless the platform knows better. This value + // is chosen to give us reasonable protection against NULL pointer dereferences while being + // low enough to leave most of the valuable low-4gb address space open. + static constexpr size_t _vm_min_address_default = 16 * M; + static char* pd_reserve_memory(size_t bytes, bool executable); static char* pd_attempt_reserve_memory_at(char* addr, size_t bytes, bool executable); @@ -420,6 +425,9 @@ class os: AllStatic { static size_t vm_allocation_granularity() { return OSInfo::vm_allocation_granularity(); } + // Returns the lowest address the process is allowed to map against. + static size_t vm_min_address(); + inline static size_t cds_core_region_alignment(); // Reserves virtual memory. @@ -432,6 +440,10 @@ class os: AllStatic { // Does not overwrite existing mappings. static char* attempt_reserve_memory_at(char* addr, size_t bytes, bool executable = false); + // Given an address range [min, max), attempts to reserve memory within this area, with the given alignment. + // If randomize is true, the location will be randomized. + static char* attempt_reserve_memory_between(char* min, char* max, size_t bytes, size_t alignment, bool randomize); + static bool commit_memory(char* addr, size_t bytes, bool executable); static bool commit_memory(char* addr, size_t size, size_t alignment_hint, bool executable); diff --git a/src/hotspot/share/utilities/fastrand.hpp b/src/hotspot/share/utilities/fastrand.hpp new file mode 100644 index 00000000000..30626963fef --- /dev/null +++ b/src/hotspot/share/utilities/fastrand.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_UTILITIES_FASTRAND_HPP +#define SHARE_UTILITIES_FASTRAND_HPP + +#include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" + +// Simple utility class to generate random numbers for use in a single-threaded +// context. Since os::random() needs to update the global seed, this is faster +// when used on within a single thread. +// Seed initialization happens, similar to os::init_random(), via os::javaTimeNanos()); + +class FastRandom { + unsigned _seed; + public: + FastRandom () : _seed((unsigned) os::javaTimeNanos()) {} + unsigned next() { + _seed = os::next_random(_seed); + return _seed; + } +}; + +#endif // SHARE_UTILITIES_FASTRAND_HPP diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index bcd532d1bcf..9956956423c 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -947,3 +947,14 @@ TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_largepages) { tty->print_cr("Skipped."); } } + +TEST_VM(os, vm_min_address) { + size_t s = os::vm_min_address(); + ASSERT_GE(s, M); + // Test upper limit. On Linux, its adjustable, so we just test for absurd values to prevent errors + // with high vm.mmap_min_addr settings. +#if defined(_LP64) + ASSERT_LE(s, NOT_LINUX(G * 4) LINUX_ONLY(G * 1024)); +#endif +} + diff --git a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp new file mode 100644 index 00000000000..a6e1ed1f239 --- /dev/null +++ b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "logging/log.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/os.hpp" +#include "utilities/align.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#include "utilities/resourceHash.hpp" + +#define LOG_PLEASE +#include "testutils.hpp" +#include "unittest.hpp" + +// On AIX, these tests make no sense as long as JDK-8315321 remains unfixed since the attach +// addresses are not predictable. +#ifndef AIX + +// Must be the same as in os::attempt_reserve_memory_between() +struct ARMB_constants { + static constexpr uintptr_t absolute_max = NOT_LP64(G * 3) LP64_ONLY(G * 128 * 1024); + static constexpr unsigned max_attempts = 32; + static constexpr unsigned min_random_value_range = 16; + static constexpr unsigned total_shuffle_threshold = 1024; +}; + +// Testing os::attempt_reserve_memory_between() + +static void release_if_needed(char* p, size_t s) { + if (p != nullptr) { + os::release_memory(p, s); + } +} + +#define ERRINFO "addr: " << ((void*)addr) << " min: " << ((void*)min) << " max: " << ((void*)max) \ + << " bytes: " << bytes << " alignment: " << alignment << " randomized: " << randomized + +static char* call_attempt_reserve_memory_between(char* min, char* max, size_t bytes, size_t alignment, bool randomized) { + char* const addr = os::attempt_reserve_memory_between(min, max, bytes, alignment, randomized); + if (addr != nullptr) { + EXPECT_TRUE(is_aligned(addr, alignment)) << ERRINFO; + EXPECT_TRUE(is_aligned(addr, os::vm_allocation_granularity())) << ERRINFO; + EXPECT_LE(addr, max - bytes) << ERRINFO; + EXPECT_LE(addr, (char*)ARMB_constants::absolute_max - bytes) << ERRINFO; + EXPECT_GE(addr, min) << ERRINFO; + EXPECT_GE(addr, (char*)os::vm_min_address()) << ERRINFO; + } + return addr; +} + +class Expect { + const bool _expect_success; + const bool _expect_failure; + const char* const _expected_result; // if _expect_success +public: + Expect(bool expect_success, bool expect_failure, char* expected_result) + : _expect_success(expect_success), _expect_failure(expect_failure), _expected_result(expected_result) + { + assert(!expect_success || !expect_failure, "make up your mind"); + } + bool check_reality(char* result) const { + if (_expect_failure) { + return result == nullptr; + } + if (_expect_success) { + return (_expected_result == nullptr) ? result != nullptr : result == _expected_result; + } + return true; + } + static Expect failure() { return Expect(false, true, nullptr); } + static Expect success_any() { return Expect(true, false, nullptr); } + static Expect success(char* addr) { return Expect(true, false, addr); } + static Expect dontcare() { return Expect(false, false, nullptr); } +}; + +static void test_attempt_reserve_memory_between(char* min, char* max, size_t bytes, size_t alignment, bool randomized, + Expect expectation, int line = -1) { + char* const addr = call_attempt_reserve_memory_between(min, max, bytes, alignment, randomized); + EXPECT_TRUE(expectation.check_reality(addr)) << ERRINFO << " L" << line; + release_if_needed(addr, bytes); +} +#undef ERRINFO + +// Helper for attempt_reserve_memory_between tests to +// reserve an area with a hole in the middle +struct SpaceWithHole { + char* _base; + const size_t _len; + const size_t _hole_offset; + const size_t _hole_size; + + + static constexpr size_t _p1_offset = 0; + const size_t _p1_size; + const size_t _p2_offset; + const size_t _p2_size; + + char* _p1; + char* _p2; + + size_t p1size() const { return hole_offset(); } + size_t p2size() const { return _len - hole_size() - hole_offset(); } + +public: + + char* base() const { return _base; } + char* end() const { return _base + _len; } + char* hole() const { return _base + hole_offset(); } + char* hole_end() const { return hole() + hole_size(); } + + size_t hole_size() const { return _hole_size; } + size_t hole_offset() const { return _hole_offset; } + + SpaceWithHole(size_t total_size, size_t hole_offset, size_t hole_size) : + _base(nullptr), _len(total_size), _hole_offset(hole_offset), _hole_size(hole_size), + _p1_size(hole_offset), _p2_offset(hole_offset + hole_size), _p2_size(total_size - hole_offset - hole_size), + _p1(nullptr), _p2(nullptr) + { + assert(_p1_size > 0 && _p2_size > 0, "Cannot have holes at the border"); + } + + bool reserve() { + // We cannot create a hole by punching, since NMT cannot cope with releases + // crossing reservation boundaries. Therefore we first reserve the total, + // release it again, reserve the parts. + for (int i = 56; _base == nullptr && i > 32; i--) { + // We reserve at weird outlier addresses, in order to minimize the chance of concurrent mmaps grabbing + // the hole. + const uintptr_t candidate = nth_bit(i); + if ((candidate + _len) <= ARMB_constants::absolute_max) { + _base = os::attempt_reserve_memory_at((char*)candidate, _len); + } + } + if (_base == nullptr) { + return false; + } + // Release total mapping, remap the individual non-holy parts + os::release_memory(_base, _len); + _p1 = os::attempt_reserve_memory_at(_base + _p1_offset, _p1_size); + _p2 = os::attempt_reserve_memory_at(_base + _p2_offset, _p2_size); + if (_p1 == nullptr || _p2 == nullptr) { + return false; + } + LOG_HERE("SpaceWithHole: [" PTR_FORMAT " ... [" PTR_FORMAT " ... " PTR_FORMAT ") ... " PTR_FORMAT ")", + p2i(base()), p2i(hole()), p2i(hole_end()), p2i(end())); + return true; + } + + ~SpaceWithHole() { + release_if_needed(_p1, _p1_size); + release_if_needed(_p2, _p2_size); + } +}; + +// Test that, when reserving in a range randomly, we get random results +static void test_attempt_reserve_memory_between_random_distribution(unsigned num_possible_attach_points) { + + const size_t ag = os::vm_allocation_granularity(); + + // Create a space that is mostly a hole bordered by two small stripes of reserved memory, with + // as many attach points as we need. + SpaceWithHole space((2 + num_possible_attach_points) * ag, ag, num_possible_attach_points * ag); + if (!space.reserve()) { + tty->print_cr("Failed to reserve holed space, skipping."); + return; + } + + const size_t bytes = ag; + const size_t alignment = ag; + + // Below this threshold the API should never return memory since the randomness is too weak. + const bool expect_failure = (num_possible_attach_points < ARMB_constants::min_random_value_range); + + // Below this threshold we expect values to be completely random, otherwise they randomized but still ordered. + const bool total_shuffled = (num_possible_attach_points < ARMB_constants::total_shuffle_threshold); + + // Allocate n times within that hole (with subsequent deletions) and remember unique addresses returned. + constexpr unsigned num_tries_per_attach_point = 100; + ResourceMark rm; + ResourceHashtable ht; + const unsigned num_tries = expect_failure ? 3 : (num_possible_attach_points * num_tries_per_attach_point); + unsigned num_uniq = 0; // Number of uniq addresses returned + + // In "total shuffle" mode, all possible attach points are randomized; outside that mode, the API + // attempts to limit fragmentation by favouring the ends of the ranges. + const unsigned expected_variance = + total_shuffled ? num_possible_attach_points : (num_possible_attach_points / ARMB_constants::max_attempts); + + // Its not easy to find a good threshold for automated tests to test randomness + // that rules out intermittent errors. We apply a generous fudge factor. + constexpr double fudge_factor = 0.25f; + const unsigned expected_variance_with_fudge = MAX2(2u, (unsigned)((double)expected_variance * fudge_factor)); + +#define ERRINFO " num_possible_attach_points: " << num_possible_attach_points << " total_shuffle? " << total_shuffled \ + << " expected variance: " << expected_variance << " with fudge: " << expected_variance_with_fudge \ + << " alignment: " << alignment << " bytes: " << bytes; + + for (unsigned i = 0; i < num_tries && + num_uniq < expected_variance_with_fudge; // Stop early if we confirmed enough variance. + i ++) { + char* p = call_attempt_reserve_memory_between(space.base(), space.end(), bytes, alignment, true); + if (p != nullptr) { + ASSERT_GE(p, space.hole()) << ERRINFO; + ASSERT_LE(p + bytes, space.hole_end()) << ERRINFO; + release_if_needed(p, bytes); + bool created = false; + unsigned* num = ht.put_if_absent(p, 0, &created); + (*num) ++; + num_uniq = (unsigned)ht.number_of_entries(); + } + } + + ASSERT_LE(num_uniq, num_possible_attach_points) << num_uniq << ERRINFO; + + if (!expect_failure) { + ASSERT_GE(num_uniq, expected_variance_with_fudge) << ERRINFO; + } +#undef ERRINFO +} + +#define RANDOMIZED_RANGE_TEST(num) \ + TEST_VM(os, attempt_reserve_memory_between_random_distribution_ ## num ## _attach_points) { \ + test_attempt_reserve_memory_between_random_distribution(num); \ +} + +RANDOMIZED_RANGE_TEST(2) +RANDOMIZED_RANGE_TEST(15) +RANDOMIZED_RANGE_TEST(16) +RANDOMIZED_RANGE_TEST(712) +RANDOMIZED_RANGE_TEST(12000) + +// Test that, given a smallish range - not many attach points - with a hole, we attach within that hole. +TEST_VM(os, attempt_reserve_memory_randomization_threshold) { + + constexpr int threshold = ARMB_constants::min_random_value_range; + const size_t ps = os::vm_page_size(); + const size_t ag = os::vm_allocation_granularity(); + + SpaceWithHole space(ag * (threshold + 2), ag, ag * threshold); + if (!space.reserve()) { + tty->print_cr("Failed to reserve holed space, skipping."); + return; + } + + // Test with a range that only allows for (threshold - 1) reservations + test_attempt_reserve_memory_between(space.hole(), space.hole_end() - ag, ps, ag, true, Expect::failure()); + + // Test with a range just above the threshold. Should succeed. + test_attempt_reserve_memory_between(space.hole(), space.hole_end(), ps, ag, true, Expect::success_any()); +} + +// Test all possible combos +TEST_VM(os, attempt_reserve_memory_between_combos) { + const size_t large_end = NOT_LP64(G) LP64_ONLY(64 * G); + for (size_t range_size = os::vm_allocation_granularity(); range_size <= large_end; range_size *= 2) { + for (size_t start_offset = 0; start_offset <= large_end; start_offset += (large_end / 2)) { + char* const min = (char*)(uintptr_t)start_offset; + char* const max = min + range_size; + for (size_t bytes = os::vm_page_size(); bytes < large_end; bytes *= 2) { + for (size_t alignment = os::vm_allocation_granularity(); alignment < large_end; alignment *= 2) { + test_attempt_reserve_memory_between(min, max, bytes, alignment, true, Expect::dontcare(), __LINE__); + test_attempt_reserve_memory_between(min, max, bytes, alignment, false, Expect::dontcare(), __LINE__); + } + } + } + } +} + +TEST_VM(os, attempt_reserve_memory_randomization_cornercases) { + const size_t ps = os::vm_page_size(); + const size_t ag = os::vm_allocation_granularity(); + constexpr size_t quarter_address_space = NOT_LP64(nth_bit(30)) LP64_ONLY(nth_bit(62)); + + // Zero-sized range + test_attempt_reserve_memory_between(nullptr, nullptr, ps, ag, false, Expect::failure()); + test_attempt_reserve_memory_between((char*)(3 * G), (char*)(3 * G), ps, ag, false, Expect::dontcare(), __LINE__); + test_attempt_reserve_memory_between((char*)SIZE_MAX, (char*)SIZE_MAX, ps, ag, false, Expect::failure(), __LINE__); + + test_attempt_reserve_memory_between(nullptr, nullptr, ps, ag, true, Expect::failure()); + test_attempt_reserve_memory_between((char*)(3 * G), (char*)(3 * G), ps, ag, true, Expect::dontcare(), __LINE__); + test_attempt_reserve_memory_between((char*)(3 * G), (char*)(3 * G), ps, ag, true, Expect::dontcare(), __LINE__); + test_attempt_reserve_memory_between((char*)SIZE_MAX, (char*)SIZE_MAX, ps, ag, true, Expect::failure(), __LINE__); + + // Full size + // Note: paradoxically, success is not guaranteed here, since a significant portion of the attach points + // could be located in un-allocatable territory. + test_attempt_reserve_memory_between(nullptr, (char*)SIZE_MAX, ps, quarter_address_space / 8, false, Expect::dontcare(), __LINE__); + test_attempt_reserve_memory_between(nullptr, (char*)SIZE_MAX, ps, quarter_address_space / 8, true, Expect::dontcare(), __LINE__); + + // Very small range at start + test_attempt_reserve_memory_between(nullptr, (char*)ag, ps, ag, false, Expect::dontcare(), __LINE__); + test_attempt_reserve_memory_between(nullptr, (char*)ag, ps, ag, true, Expect::dontcare(), __LINE__); + + // Very small range at end + test_attempt_reserve_memory_between((char*)(SIZE_MAX - (ag * 2)), (char*)(SIZE_MAX), ps, ag, false, Expect::dontcare(), __LINE__); + test_attempt_reserve_memory_between((char*)(SIZE_MAX - (ag * 2)), (char*)(SIZE_MAX), ps, ag, true, Expect::dontcare(), __LINE__); + + // At start, high alignment, check if we run into neg. overflow problems + test_attempt_reserve_memory_between(nullptr, (char*)G, ps, G, false, Expect::dontcare(), __LINE__); + test_attempt_reserve_memory_between(nullptr, (char*)G, ps, G, true, Expect::dontcare(), __LINE__); + + // At start, very high alignment, check if we run into neg. overflow problems + test_attempt_reserve_memory_between((char*)quarter_address_space, (char*)SIZE_MAX, ps, quarter_address_space, false, Expect::dontcare(), __LINE__); + test_attempt_reserve_memory_between((char*)quarter_address_space, (char*)SIZE_MAX, ps, quarter_address_space, true, Expect::dontcare(), __LINE__); +} + +// Test that, regardless where the hole is in the [min, max) range, if we probe nonrandomly, we will fill that hole +// as long as the range size is smaller than the number of probe attempts +TEST_VM(os, attempt_reserve_memory_between_small_range_fill_hole) { + const size_t ps = os::vm_page_size(); + const size_t ag = os::vm_allocation_granularity(); + constexpr int num = ARMB_constants::max_attempts; + for (int i = 0; i < num; i ++) { + SpaceWithHole space(ag * (num + 2), ag * (i + 1), ag); + if (!space.reserve()) { + tty->print_cr("Failed to reserve holed space, skipping."); + } else { + test_attempt_reserve_memory_between(space.base() + ag, space.end() - ag, space.hole_size(), space.hole_size(), false, Expect::success(space.hole()), __LINE__); + } + } +} + +#endif // AIX diff --git a/test/hotspot/gtest/testutils.hpp b/test/hotspot/gtest/testutils.hpp index 6b3d42f1127..c4c093fff23 100644 --- a/test/hotspot/gtest/testutils.hpp +++ b/test/hotspot/gtest/testutils.hpp @@ -68,4 +68,7 @@ class GtestUtils : public AllStatic { #define LOG_HERE(s, ...) #endif +// handy for error analysis +#define PING { printf("%s:%d\n", __FILE__, __LINE__); fflush(stdout); } + #endif // TESTUTILS_HPP From c90cd2c0608d250434bff7013360b8388d9854b3 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Wed, 30 Aug 2023 18:28:43 +0000 Subject: [PATCH 10/86] 8286789: Test forceEarlyReturn002.java timed out Reviewed-by: lmesnik, sspitsyn --- test/hotspot/jtreg/ProblemList-Virtual.txt | 6 ---- .../forceEarlyReturn002.java | 7 +++-- .../forceEarlyReturn002a.java | 10 +++++- .../libforceEarlyReturn002a.cpp | 31 ++++++++++++++++--- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index 2ae24945ee7..8f044dfaeca 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -56,12 +56,6 @@ vmTestbase/nsk/jvmti/unit/GetLocalVariable/getlocal003/TestDescription.java 8300 ## Test fails because it expects to find vthreads in GetAllThreads vmTestbase/nsk/jvmti/scenarios/allocation/AP11/ap11t001/TestDescription.java 8300712 generic-all -#### -## NSK JDWP Tests failing with wrapper - -vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java 8286789 generic-all - - ########## ## NSK JDB Tests failing with wrapper diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java index 420dd065053..f8ac891b9ff 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ * When test thread has finish execution debugger suspends thread and call command for this thread, INVALID_THREAD * error is expected, then, debugger resumes test thread and call command again, INVALID_THREAD error should * be returned in reply. - * - debuggee starts test thread which executes infinite loop in native method, debugger calls command for + * - debuggee starts test thread which executes loop in native method, debugger calls command for * this thread(without suspending) and expects THREAD_NOT_SUSPENDED error. Then, debugger suspends this thread * and calls command again, OPAQUE_FRAME error is expected. * - debugger creates ThreadStartEventRequest with suspend policy 'JDWP.SuspendPolicy.ALL' and forces debuggee start new thread. @@ -227,6 +227,9 @@ public void doTest() { // suspended thread in native, expect OPAQUE_FRAME error sendCommand(threadID, value, true, JDWP.Error.OPAQUE_FRAME); + // signal native method to exit; the thread will be actually suspended + pipe.println(forceEarlyReturn002a.COMMAND_EXIT_THREAD_IN_NATIVE); + // create request for ThreadStart event int requestID = createThreadStartEventRequest(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java index 131ab11e8f8..c6af1dd7811 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/forceEarlyReturn002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,8 @@ public class forceEarlyReturn002a extends AbstractJDWPDebuggee { public final static String COMMAND_STOP_THREAD_IN_NATIVE = "stopInNative"; + public final static String COMMAND_EXIT_THREAD_IN_NATIVE = "exitInNative"; + public final static String COMMAND_START_NEW_THREAD = "startNewThread"; public boolean parseCommand(String command) { @@ -49,6 +51,10 @@ public boolean parseCommand(String command) { if (command.equals(COMMAND_STOP_THREAD_IN_NATIVE)) { stopThreadInNative(); + return true; + } else if (command.equals(COMMAND_EXIT_THREAD_IN_NATIVE)) { + exitThreadInNative(); + return true; } else if (command.equals(COMMAND_START_NEW_THREAD)) { Thread thread = new Thread(new Runnable() { @@ -87,6 +93,8 @@ public void run() { private static native int nativeMethod(Object object); + private static native void exitThreadInNative(); + public static void main(String args[]) { new forceEarlyReturn002a().doTest(args); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/libforceEarlyReturn002a.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/libforceEarlyReturn002a.cpp index 79d46c3095e..c287de9056b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/libforceEarlyReturn002a.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn002/libforceEarlyReturn002a.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,23 +23,46 @@ #include "jni.h" +#if defined(_WIN32) +#include +#else +#include +#endif + +#include + extern "C" { +static std::atomic wait_in_native(true); + +static void delay(int seconds) { +#if defined(_WIN32) + Sleep(1000L * seconds); +#else + sleep(seconds); +#endif +} JNIEXPORT jint JNICALL Java_nsk_jdwp_ThreadReference_ForceEarlyReturn_forceEarlyReturn002_forceEarlyReturn002a_nativeMethod(JNIEnv *env, jobject classObject, jobject object) { - static volatile int dummy_counter = 0; // notify another thread that thread in native method jclass klass = env->GetObjectClass(object); jfieldID field = env->GetFieldID(klass, "threadInNative", "Z"); env->SetBooleanField(object, field, 1); // execute infinite loop to be sure that thread in native method - while (dummy_counter == 0) {} + while (wait_in_native) { + delay(1); + } - // Should not reach here return 0; } +JNIEXPORT void JNICALL +Java_nsk_jdwp_ThreadReference_ForceEarlyReturn_forceEarlyReturn002_forceEarlyReturn002a_exitThreadInNative(JNIEnv *env, jobject classObject) +{ + wait_in_native = false; +} + } From 8419a53bf1b21dca7c9fe5202487031c1a278db1 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 30 Aug 2023 19:51:23 +0000 Subject: [PATCH 11/86] 8315072: Remove unneeded AdaptivePaddedAverage::operator new Reviewed-by: tschatzl, iwalulya --- .../gc/parallel/psAdaptiveSizePolicy.cpp | 2 +- .../share/gc/shared/adaptiveSizePolicy.cpp | 2 +- src/hotspot/share/gc/shared/gcStats.cpp | 2 +- src/hotspot/share/gc/shared/gcUtil.hpp | 5 --- src/hotspot/share/gc/shared/gcUtil.inline.hpp | 36 ------------------- 5 files changed, 3 insertions(+), 44 deletions(-) delete mode 100644 src/hotspot/share/gc/shared/gcUtil.inline.hpp diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp index 41b6022565e..34d6621c820 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp @@ -28,7 +28,7 @@ #include "gc/parallel/psGCAdaptivePolicyCounters.hpp" #include "gc/parallel/psScavenge.hpp" #include "gc/shared/gcCause.hpp" -#include "gc/shared/gcUtil.inline.hpp" +#include "gc/shared/gcUtil.hpp" #include "gc/shared/gcPolicyCounters.hpp" #include "logging/log.hpp" #include "runtime/timer.hpp" diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp index ea94d13a1a5..3a0b3188a9a 100644 --- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/adaptiveSizePolicy.hpp" #include "gc/shared/gcCause.hpp" -#include "gc/shared/gcUtil.inline.hpp" +#include "gc/shared/gcUtil.hpp" #include "logging/log.hpp" #include "runtime/timer.hpp" diff --git a/src/hotspot/share/gc/shared/gcStats.cpp b/src/hotspot/share/gc/shared/gcStats.cpp index a90f0f01a5c..42307e974d2 100644 --- a/src/hotspot/share/gc/shared/gcStats.cpp +++ b/src/hotspot/share/gc/shared/gcStats.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/gcStats.hpp" -#include "gc/shared/gcUtil.inline.hpp" +#include "gc/shared/gcUtil.hpp" #include "gc/shared/gc_globals.hpp" GCStats::GCStats() : _avg_promoted(new AdaptivePaddedNoZeroDevAverage(AdaptiveSizePolicyWeight, PromotedPadding)) {} diff --git a/src/hotspot/share/gc/shared/gcUtil.hpp b/src/hotspot/share/gc/shared/gcUtil.hpp index 8da6b31af21..8b6ef8d5b0c 100644 --- a/src/hotspot/share/gc/shared/gcUtil.hpp +++ b/src/hotspot/share/gc/shared/gcUtil.hpp @@ -143,11 +143,6 @@ class AdaptivePaddedAverage : public AdaptiveWeightedAverage { AdaptiveWeightedAverage(weight), _padded_avg(0.0), _deviation(0.0), _padding(padding) {} - // Placement support - void* operator new(size_t ignored, void* p) throw() { return p; } - // Allocator - void* operator new(size_t size) throw(); - // Accessor float padded_average() const { return _padded_avg; } float deviation() const { return _deviation; } diff --git a/src/hotspot/share/gc/shared/gcUtil.inline.hpp b/src/hotspot/share/gc/shared/gcUtil.inline.hpp deleted file mode 100644 index 5c0a8547e32..00000000000 --- a/src/hotspot/share/gc/shared/gcUtil.inline.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_SHARED_GCUTIL_INLINE_HPP -#define SHARE_GC_SHARED_GCUTIL_INLINE_HPP - -#include "gc/shared/gcUtil.hpp" - -#include "memory/allocation.inline.hpp" - -inline void* AdaptivePaddedAverage::operator new(size_t size) throw() { - return CHeapObj::operator new(size); -} - -#endif // SHARE_GC_SHARED_GCUTIL_INLINE_HPP From 3eac8905aee6edecbebcc12a41300d3ce176fbff Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 30 Aug 2023 20:20:17 +0000 Subject: [PATCH 12/86] 8315061: Make LockingMode a product flag Reviewed-by: ccheung --- src/hotspot/share/runtime/globals.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 52a4af0aee8..725ded4bd7a 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1982,7 +1982,7 @@ const int ObjectAlignmentInBytes = 8; "Mark all threads after a safepoint, and clear on a modify " \ "fence. Add cleanliness checks.") \ \ - product(int, LockingMode, LM_LEGACY, EXPERIMENTAL, \ + product(int, LockingMode, LM_LEGACY, \ "Select locking mode: " \ "0: monitors only (LM_MONITOR), " \ "1: monitors & legacy stack-locking (LM_LEGACY, default), " \ From df5e6e5d482e70b33612639b3c1c04eaa1ed361e Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Wed, 30 Aug 2023 21:52:31 +0000 Subject: [PATCH 13/86] 8315248: AssertionError in Name.compareTo Reviewed-by: vromero --- .../sun/tools/javac/util/Utf8NameTable.java | 38 +++--- .../tools/javac/nametable/TestNameTables.java | 127 ++++++++++++++++++ 2 files changed, 149 insertions(+), 16 deletions(-) create mode 100644 test/langtools/tools/javac/nametable/TestNameTables.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Utf8NameTable.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Utf8NameTable.java index c9fdd7df939..46d8a295efa 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Utf8NameTable.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Utf8NameTable.java @@ -25,10 +25,6 @@ package com.sun.tools.javac.util; -import java.lang.ref.SoftReference; - -import com.sun.tools.javac.util.DefinedBy.Api; - /** * Support superclass for {@link Name.Table} implementations that store * names as Modified UTF-8 data in {@code byte[]} arrays. @@ -51,7 +47,7 @@ protected Utf8NameTable(Names names) { /** Generate a hash value for a subarray. */ - protected static int hashValue(byte buf[], int off, int len) { + protected static int hashValue(byte[] buf, int off, int len) { int hash = 0; while (len-- > 0) hash = (hash << 5) - hash + buf[off++]; @@ -100,6 +96,11 @@ protected abstract static class NameImpl extends Name { */ protected abstract int getNameIndex(); + @Override + protected boolean nameEquals(Name that) { + return ((NameImpl)that).getNameIndex() == getNameIndex(); + } + // CharSequence @Override @@ -112,17 +113,12 @@ public String toString() { try { return Convert.utf2string(getByteData(), getByteOffset(), getByteLength(), Convert.Validation.NONE); } catch (InvalidUtfException e) { - throw new AssertionError(); + throw new AssertionError("invalid UTF8 data", e); } } // javax.lang.model.element.Name - @Override - protected boolean nameEquals(Name that) { - return ((NameImpl)that).getNameIndex() == getNameIndex(); - } - @Override public int hashCode() { return getNameIndex(); @@ -132,8 +128,18 @@ public int hashCode() { @Override public int compareTo(Name name0) { - NameImpl name = (NameImpl)name0; - Assert.check(name.table == table); + // While most operations on Name that take a Name as an argument expect the argument + // to come from the same table, in many cases, including here, that is not strictly + // required. Moreover, javac.util.Name implements javax.lang.model.element.Name, + // which extends CharSequence, which provides + // static int compare(CharSequence cs1, CharSequence cs2) + // which ends up calling to this method via the Comparable interface + // and a bridge method when the two arguments have the same class. + // Therefore, for this method, we relax "same table", and delegate to the more + // general super method if necessary. + if (!(name0 instanceof NameImpl name)) { + return super.compareTo(name0); + } byte[] buf1 = getByteData(); byte[] buf2 = name.getByteData(); int off1 = getByteOffset(); @@ -180,7 +186,7 @@ public Name append(Name name0) { try { return table.fromUtf(result, 0, result.length, Convert.Validation.NONE); } catch (InvalidUtfException e) { - throw new AssertionError(); + throw new AssertionError("invalid UTF8 data", e); } } @@ -202,7 +208,7 @@ public Name append(char ch, Name name0) { try { return table.fromUtf(result, 0, result.length, Convert.Validation.NONE); } catch (InvalidUtfException e) { - throw new AssertionError(); + throw new AssertionError("invalid UTF8 data", e); } } @@ -252,7 +258,7 @@ public int getUtf8Length() { } @Override - public void getUtf8Bytes(byte buf[], int off) { + public void getUtf8Bytes(byte[] buf, int off) { System.arraycopy(getByteData(), getByteOffset(), buf, off, getByteLength()); } } diff --git a/test/langtools/tools/javac/nametable/TestNameTables.java b/test/langtools/tools/javac/nametable/TestNameTables.java new file mode 100644 index 00000000000..18a5c2f485b --- /dev/null +++ b/test/langtools/tools/javac/nametable/TestNameTables.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8315248 + * @summary AssertionError in Name.compareTo + * @modules jdk.compiler/com.sun.tools.javac.util + * + * @run main TestNameTables + */ + +import java.io.PrintStream; +import java.util.List; +import java.util.Objects; + +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Names; +import com.sun.tools.javac.util.Options; + +/** + * Tests that CharSequence.compareTo works on CharSequence objects that may + * come from different name tables. + * + * While the java.util.Name class generally specifies that operations involving + * multiple Name objects should use names from the same table, that restriction + * is harder to specify when the names are widened CharSequence objects. + * + * The test can be extended if necessary to cover other methods on Name, + * if the restrictions on Name are relaxed to permit more mix-and-match usages. + */ +public class TestNameTables { + public static void main(String... args) { + new TestNameTables().run(); + } + + public static final String USE_SHARED_TABLE = "useSharedTable"; + public static final String USE_UNSHARED_TABLE = "useUnsharedTable"; + public static final String USE_STRING_TABLE = "useStringTable"; + + public final List ALL_TABLES = List.of(USE_SHARED_TABLE, USE_UNSHARED_TABLE, USE_STRING_TABLE); + + private final PrintStream out = System.err; + + void run() { + for (var s : ALL_TABLES) { + test(createNameTable(s)); + } + + for (var s1 : ALL_TABLES) { + for (var s2 : ALL_TABLES) { + test(createNameTable(s1), createNameTable(s2)); + } + } + } + + Name.Table createNameTable(String option) { + Context c = new Context(); + Options o = Options.instance(c); + o.put(option, "true"); + Names n = new Names(c); + return n.table; + } + + /** + * Tests operations using a single name table. + * + * @param table the name table + */ + void test(Name.Table table) { + test(table, table); + } + + /** + * Tests operations using distinct name tables, of either the same + * or different impl types. + * + * @param table1 the first name table + * @param table2 the second name table + */ + void test(Name.Table table1, Name.Table table2) { + if (table1 == table2) { + out.println("Testing " + table1); + } else { + out.println("Testing " + table1 + " : " + table2); + } + + // tests are primarily that there are no issues manipulating names from + // distinct name tables + testCharSequenceCompare(table1, table2); + } + + void testCharSequenceCompare(Name.Table table1, Name.Table table2) { + Name n1 = table1.fromString("abc"); + Name n2 = table2.fromString("abc"); + checkEquals(CharSequence.compare(n1, n2), 0, "CharSequence.compare"); + } + + void checkEquals(Object found, Object expect, String op) { + if (!Objects.equals(found, expect)) { + out.println("Failed: " + op); + out.println(" found: " + found); + out.println(" expect: " + expect); + } + } +} \ No newline at end of file From 3c8a6678feac8e3225bc1c44593a78d9e7c4d77c Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 30 Aug 2023 23:40:34 +0000 Subject: [PATCH 14/86] 8314611: Provide more explicative error message parsing Currencies Reviewed-by: naoto --- .../share/classes/java/util/Currency.java | 18 ++++++---- test/jdk/java/util/Currency/CurrencyTest.java | 36 +++++++++++++++---- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/java.base/share/classes/java/util/Currency.java b/src/java.base/share/classes/java/util/Currency.java index b1bde1a73c6..14d1cf4351d 100644 --- a/src/java.base/share/classes/java/util/Currency.java +++ b/src/java.base/share/classes/java/util/Currency.java @@ -319,7 +319,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi // or in the list of other currencies. boolean found = false; if (currencyCode.length() != 3) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("The input currency code must " + + "have a length of 3 characters"); } char char1 = currencyCode.charAt(0); char char2 = currencyCode.charAt(1); @@ -342,7 +343,8 @@ private static Currency getInstance(String currencyCode, int defaultFractionDigi if (!found) { OtherCurrencyEntry ocEntry = OtherCurrencyEntry.findEntry(currencyCode); if (ocEntry == null) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("The input currency code" + + " is not a valid ISO 4217 code"); } defaultFractionDigits = ocEntry.fraction; numericCode = ocEntry.numericCode; @@ -397,7 +399,8 @@ public static Currency getInstance(Locale locale) { String country = CalendarDataUtility.findRegionOverride(locale).getCountry(); if (country == null || !country.matches("^[a-zA-Z]{2}$")) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("The country of the input locale" + + " is not a valid ISO 3166 country code"); } char char1 = country.charAt(0); @@ -414,7 +417,8 @@ public static Currency getInstance(Locale locale) { } else { // special cases if (tableEntry == INVALID_COUNTRY_ENTRY) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("The country of the input locale" + + " is not a valid ISO 3166 country code"); } if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) { return null; @@ -679,7 +683,8 @@ private Object readResolve() { */ private static int getMainTableEntry(char char1, char char2) { if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("The country code is not a " + + "valid ISO 3166 code"); } return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')]; } @@ -690,7 +695,8 @@ private static int getMainTableEntry(char char1, char char2) { */ private static void setMainTableEntry(char char1, char char2, int entry) { if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') { - throw new IllegalArgumentException(); + throw new IllegalArgumentException("The country code is not a " + + "valid ISO 3166 code"); } mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry; } diff --git a/test/jdk/java/util/Currency/CurrencyTest.java b/test/jdk/java/util/Currency/CurrencyTest.java index 0561b502730..495de30e821 100644 --- a/test/jdk/java/util/Currency/CurrencyTest.java +++ b/test/jdk/java/util/Currency/CurrencyTest.java @@ -80,14 +80,31 @@ private static Stream validCurrencies() { // Calling getInstance() with an invalid currency code should throw an IAE @ParameterizedTest - @MethodSource("invalidCurrencies") + @MethodSource("non4217Currencies") public void invalidCurrencyTest(String currencyCode) { - assertThrows(IllegalArgumentException.class, () -> + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(currencyCode), "getInstance() did not throw IAE"); + assertEquals("The input currency code is not a" + + " valid ISO 4217 code", ex.getMessage()); } - private static Stream invalidCurrencies() { - return Stream.of("AQD", "US$", "\u20AC"); + private static Stream non4217Currencies() { + return Stream.of("AQD", "US$"); + } + + // Calling getInstance() with a currency code not 3 characters long should throw + // an IAE + @ParameterizedTest + @MethodSource("invalidLengthCurrencies") + public void invalidCurrencyLengthTest(String currencyCode) { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + Currency.getInstance(currencyCode), "getInstance() did not throw IAE"); + assertEquals("The input currency code must have a length of 3" + + " characters", ex.getMessage()); + } + + private static Stream invalidLengthCurrencies() { + return Stream.of("\u20AC", "", "12345"); } } @@ -144,7 +161,10 @@ public void localeMappingTest() { ctryLength == 3 || // UN M.49 code ctryCode.matches("AA|Q[M-Z]|X[A-JL-Z]|ZZ" + // user defined codes, excluding "XK" (Kosovo) "AC|CP|DG|EA|EU|FX|IC|SU|TA|UK")) { // exceptional reservation codes - assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(locale), "Did not throw IAE"); + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, + () -> Currency.getInstance(locale), "Did not throw IAE"); + assertEquals("The country of the input locale is not a" + + " valid ISO 3166 country code", ex.getMessage()); } else { goodCountries++; Currency currency = Currency.getInstance(locale); @@ -163,8 +183,10 @@ public void localeMappingTest() { // Check an invalid country code @Test public void invalidCountryTest() { - assertThrows(IllegalArgumentException.class, ()-> - Currency.getInstance(Locale.of("", "EU")), "Did not throw IAE"); + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, + ()-> Currency.getInstance(Locale.of("", "EU")), "Did not throw IAE"); + assertEquals("The country of the input locale is not a valid" + + " ISO 3166 country code", ex.getMessage()); } // Ensure a selection of countries have the expected currency From 218829e0a2a3ae5599b81733df53557966392033 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Thu, 31 Aug 2023 02:33:38 +0000 Subject: [PATCH 15/86] 8315421: [BACKOUT] 8314834 serviceability/jdwp/AllModulesCommandTest.java ignores VM flags Reviewed-by: dholmes --- .../serviceability/jdwp/DebuggeeLauncher.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java b/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java index 8c939833edb..5c3d01ec2dc 100644 --- a/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java +++ b/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ import jdk.test.lib.JDKToolFinder; import jdk.test.lib.JDWP; import static jdk.test.lib.Asserts.assertFalse; -import jdk.test.lib.process.ProcessTools; /** * Launches the debuggee with the necessary JDWP options and handles the output @@ -55,9 +54,8 @@ public interface Listener { } private int jdwpPort = -1; + private static final String CLS_DIR = System.getProperty("test.classes", "").trim(); private static final String DEBUGGEE = "AllModulesCommandTestDebuggee"; - private static final String JDWP_OPT = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0"; - private Process p; private final Listener listener; private StreamHandler inputHandler; @@ -78,7 +76,7 @@ public DebuggeeLauncher(Listener listener) { */ public void launchDebuggee() throws Throwable { - ProcessBuilder pb = ProcessTools.createTestJvm(JDWP_OPT, DEBUGGEE); + ProcessBuilder pb = new ProcessBuilder(getCommand()); p = pb.start(); inputHandler = new StreamHandler(p.getInputStream(), this); errorHandler = new StreamHandler(p.getErrorStream(), this); @@ -86,6 +84,22 @@ public void launchDebuggee() throws Throwable { errorHandler.start(); } + /** + * Command to start the debuggee with the JDWP options and using the JDK + * under test + * + * @return the command + */ + private String[] getCommand() { + return new String[]{ + JDKToolFinder.getTestJDKTool("java"), + getJdwpOptions(), + "-cp", + CLS_DIR, + DEBUGGEE + }; + } + /** * Terminates the debuggee */ @@ -95,6 +109,15 @@ public void terminateDebuggee() { } } + /** + * Debuggee JDWP options + * + * @return the JDWP options to start the debuggee with + */ + private static String getJdwpOptions() { + return "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0"; + } + /** * Gets JDWP port debuggee is listening on. * From 47aa6f3a65559d8143511561ac9d18cfb133263e Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Thu, 31 Aug 2023 08:04:47 +0000 Subject: [PATCH 16/86] 8315219: G1: Improve allocator pathological case where it keeps doing direct allocations instead of retiring a PLAB Reviewed-by: tschatzl, ayang, mli --- src/hotspot/share/gc/g1/g1Allocator.cpp | 17 +++++++++-------- .../jtreg/gc/g1/plab/TestPLABPromotion.java | 15 ++++++++------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index a8520d78a64..4d626d9af2d 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -358,14 +358,18 @@ G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) : } } -bool G1PLABAllocator::may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const { - return (allocation_word_sz * 100 < buffer_size * ParallelGCBufferWastePct); +bool G1PLABAllocator::may_throw_away_buffer(size_t const words_remaining, size_t const buffer_size) const { + return (words_remaining * 100 < buffer_size * ParallelGCBufferWastePct); } HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest, size_t word_sz, bool* plab_refill_failed, uint node_index) { + PLAB* alloc_buf = alloc_buffer(dest, node_index); + size_t words_remaining = alloc_buf->words_remaining(); + assert(words_remaining < word_sz, "precondition"); + size_t plab_word_size = plab_size(dest.type()); size_t next_plab_word_size = plab_word_size; @@ -378,13 +382,10 @@ HeapWord* G1PLABAllocator::allocate_direct_or_new_plab(G1HeapRegionAttr dest, size_t required_in_plab = PLAB::size_required_for_allocation(word_sz); // Only get a new PLAB if the allocation fits into the to-be-allocated PLAB and - // it would not waste more than ParallelGCBufferWastePct in the current PLAB. - // Boosting the PLAB also increasingly allows more waste to occur. + // retiring the current PLAB would not waste more than ParallelGCBufferWastePct + // in the current PLAB. Boosting the PLAB also increasingly allows more waste to occur. if ((required_in_plab <= next_plab_word_size) && - may_throw_away_buffer(required_in_plab, plab_word_size)) { - - PLAB* alloc_buf = alloc_buffer(dest, node_index); - guarantee(alloc_buf->words_remaining() <= required_in_plab, "must be"); + may_throw_away_buffer(words_remaining, plab_word_size)) { alloc_buf->retire(); diff --git a/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java b/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java index add5f3ec16f..785e07f8df5 100644 --- a/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java +++ b/test/hotspot/jtreg/gc/g1/plab/TestPLABPromotion.java @@ -45,6 +45,7 @@ import gc.g1.plab.lib.PLABUtils; import gc.g1.plab.lib.PlabInfo; +import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -62,17 +63,18 @@ public class TestPLABPromotion { private final static String PLAB_DIRECT_ALLOCATED_FIELD_NAME = "direct allocated"; private final static List FIELDS_TO_EXTRACT = Arrays.asList(PLAB_USED_FIELD_NAME, PLAB_DIRECT_ALLOCATED_FIELD_NAME); + private static final int HEAP_WORD_SIZE = Platform.is32bit() ? 4 : 8; + private static String output; // Allowable difference for memory consumption (percentage) private final static long MEM_DIFFERENCE_PCT = 5; - private static final int PLAB_SIZE_SMALL = 1024; private static final int PLAB_SIZE_MEDIUM = 4096; private static final int PLAB_SIZE_HIGH = 65536; - private static final int OBJECT_SIZE_SMALL = 10; - private static final int OBJECT_SIZE_MEDIUM = 100; - private static final int OBJECT_SIZE_HIGH = 3250; + private static final int OBJECT_SIZE_SMALL = 10 * HEAP_WORD_SIZE; + private static final int OBJECT_SIZE_MEDIUM = 128 * HEAP_WORD_SIZE; + private static final int OBJECT_SIZE_HIGH = 3072 * HEAP_WORD_SIZE; private static final int GC_NUM_SMALL = 1; private static final int GC_NUM_MEDIUM = 3; private static final int GC_NUM_HIGH = 7; @@ -94,7 +96,8 @@ public class TestPLABPromotion { new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_SMALL, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_FIXED, true, false), new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, true, true), new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, true, true), - new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_FIXED, true, true), + new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_FIXED, true, false), + new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_FIXED, true, true), new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_SMALL, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, true, true), new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, true, true), new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_SMALL, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_HIGH, PLAB_FIXED, true, false), @@ -104,8 +107,6 @@ public class TestPLABPromotion { new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true), new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true), new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, false), - new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true), - new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true), new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true) }; From 39f181337b652c1b36b131a8582e8cf78b77178b Mon Sep 17 00:00:00 2001 From: shiker <32234876+shiker1996@users.noreply.github.com> Date: Thu, 31 Aug 2023 08:28:11 +0000 Subject: [PATCH 17/86] 8315318: Typo in comment on sun.nio.ch.Net.unblock4 Reviewed-by: mbaesken, vtewari --- src/java.base/share/classes/sun/nio/ch/Net.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/sun/nio/ch/Net.java b/src/java.base/share/classes/sun/nio/ch/Net.java index d6f22bbcca7..49814ae6bf2 100644 --- a/src/java.base/share/classes/sun/nio/ch/Net.java +++ b/src/java.base/share/classes/sun/nio/ch/Net.java @@ -730,7 +730,7 @@ static int block4(FileDescriptor fd, int group, int interf, int source) } /** - * Unblock IPv6 source + * Unblock IPv4 source */ static void unblock4(FileDescriptor fd, int group, int interf, int source) throws IOException From b594f01fe4872d255f0f2fd2b1a908660e39f426 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Thu, 31 Aug 2023 08:31:31 +0000 Subject: [PATCH 18/86] 8314748: 1-10% regressions on Crypto micros Reviewed-by: chagedorn, adinn, kvn, sviswanathan --- src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 2 +- .../cpu/x86/stubGenerator_x86_64_aes.cpp | 58 ++++++++++--------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index d65d8e871c3..8657080b8f7 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -365,7 +365,7 @@ class StubGenerator: public StubCodeGenerator { // Utility routine for increase 128bit counter (iv in CTR mode) void inc_counter(Register reg, XMMRegister xmmdst, int inc_delta, Label& next_block); void ev_add128(XMMRegister xmmdst, XMMRegister xmmsrc1, XMMRegister xmmsrc2, - int vector_len, KRegister ktmp, Register rscratch = noreg); + int vector_len, KRegister ktmp, XMMRegister ones); void generate_aes_stubs(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index 7b1fb54853e..c7ca8e38356 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -1637,12 +1637,12 @@ void StubGenerator::ev_load_key(XMMRegister xmmdst, Register key, int offset, Re // Clobber ktmp and rscratch. // Used by aesctr_encrypt. void StubGenerator::ev_add128(XMMRegister xmmdst, XMMRegister xmmsrc1, XMMRegister xmmsrc2, - int vector_len, KRegister ktmp, Register rscratch) { + int vector_len, KRegister ktmp, XMMRegister ones) { __ vpaddq(xmmdst, xmmsrc1, xmmsrc2, vector_len); - __ evpcmpuq(ktmp, xmmdst, xmmsrc2, __ lt, vector_len); - __ kshiftlbl(ktmp, ktmp, 1); - __ evpaddq(xmmdst, ktmp, xmmdst, ExternalAddress(counter_mask_ones_addr()), /*merge*/true, - vector_len, rscratch); + __ evpcmpuq(ktmp, xmmdst, xmmsrc2, __ lt, vector_len); // set mask[0/1] bit if addq to dst[0/1] wraps + __ kshiftlbl(ktmp, ktmp, 1); // mask[1] <- mask[0], mask[0] <- 0, etc + + __ evpaddq(xmmdst, ktmp, xmmdst, ones, /*merge*/true, vector_len); // dst[1]++ if mask[1] set } // AES-ECB Encrypt Operation @@ -2125,16 +2125,20 @@ void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Regist // each zmm register has 4 counter values as its MSB // the counters are incremented in parallel + const XMMRegister ones = xmm17; + // Vector value to propagate carries + __ evmovdquq(ones, ExternalAddress(counter_mask_ones_addr()), Assembler::AVX_512bit, r15); + __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc0_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); - ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); - __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); - ev_add128(xmm9, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); - ev_add128(xmm10, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); - ev_add128(xmm11, xmm10, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); - ev_add128(xmm12, xmm11, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); - ev_add128(xmm13, xmm12, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); - ev_add128(xmm14, xmm13, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); - ev_add128(xmm15, xmm14, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); + __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit); + ev_add128(xmm9, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); + ev_add128(xmm10, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); + ev_add128(xmm11, xmm10, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); + ev_add128(xmm12, xmm11, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); + ev_add128(xmm13, xmm12, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); + ev_add128(xmm14, xmm13, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); + ev_add128(xmm15, xmm14, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); // load linc32 mask in zmm register.linc32 increments counter by 32 __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc32_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); @@ -2182,21 +2186,21 @@ void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Regist // This is followed by incrementing counter values in zmm8-zmm15. // Since we will be processing 32 blocks at a time, the counter is incremented by 32. roundEnc(xmm21, 7); - ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); roundEnc(xmm22, 7); - ev_add128(xmm9, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm9, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); roundEnc(xmm23, 7); - ev_add128(xmm10, xmm10, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm10, xmm10, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); roundEnc(xmm24, 7); - ev_add128(xmm11, xmm11, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm11, xmm11, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); roundEnc(xmm25, 7); - ev_add128(xmm12, xmm12, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm12, xmm12, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); roundEnc(xmm26, 7); - ev_add128(xmm13, xmm13, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm13, xmm13, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); roundEnc(xmm27, 7); - ev_add128(xmm14, xmm14, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm14, xmm14, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); roundEnc(xmm28, 7); - ev_add128(xmm15, xmm15, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm15, xmm15, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); roundEnc(xmm29, 7); __ cmpl(rounds, 52); @@ -2274,8 +2278,8 @@ void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Regist __ vpshufb(xmm3, xmm11, xmm16, Assembler::AVX_512bit); __ evpxorq(xmm3, xmm3, xmm20, Assembler::AVX_512bit); // Increment counter values by 16 - ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); - ev_add128(xmm9, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); + ev_add128(xmm9, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); // AES encode rounds roundEnc(xmm21, 3); roundEnc(xmm22, 3); @@ -2342,7 +2346,7 @@ void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Regist __ vpshufb(xmm1, xmm9, xmm16, Assembler::AVX_512bit); __ evpxorq(xmm1, xmm1, xmm20, Assembler::AVX_512bit); // increment counter by 8 - ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); // AES encode roundEnc(xmm21, 1); roundEnc(xmm22, 1); @@ -2401,7 +2405,7 @@ void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Regist __ evpxorq(xmm0, xmm0, xmm20, Assembler::AVX_512bit); // Increment counter - ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); __ vaesenc(xmm0, xmm0, xmm21, Assembler::AVX_512bit); __ vaesenc(xmm0, xmm0, xmm22, Assembler::AVX_512bit); __ vaesenc(xmm0, xmm0, xmm23, Assembler::AVX_512bit); @@ -2451,7 +2455,7 @@ void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Regist __ evpxorq(xmm0, xmm0, xmm20, Assembler::AVX_128bit); __ vaesenc(xmm0, xmm0, xmm21, Assembler::AVX_128bit); // Increment counter by 1 - ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_128bit, /*ktmp*/k1, r15 /*rscratch*/); + ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_128bit, /*ktmp*/k1, ones); __ vaesenc(xmm0, xmm0, xmm22, Assembler::AVX_128bit); __ vaesenc(xmm0, xmm0, xmm23, Assembler::AVX_128bit); __ vaesenc(xmm0, xmm0, xmm24, Assembler::AVX_128bit); From b0353addf2bb649f98db7194a110c2152c0ed58b Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 31 Aug 2023 09:49:16 +0000 Subject: [PATCH 19/86] 8315242: G1: Fix -Wconversion warnings around GCDrainStackTargetSize Reviewed-by: tschatzl, mli --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 4 ++-- src/hotspot/share/gc/parallel/psPromotionManager.cpp | 6 ++---- src/hotspot/share/gc/shared/gc_globals.hpp | 4 ++-- src/hotspot/share/utilities/globalDefinitions.hpp | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 70badde7307..7dd6ee759be 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -2317,9 +2317,9 @@ void G1CMTask::drain_local_queue(bool partially) { // Decide what the target size is, depending whether we're going to // drain it partially (so that other tasks can steal if they run out // of things to do) or totally (at the very end). - size_t target_size; + uint target_size; if (partially) { - target_size = MIN2((size_t)_task_queue->max_elems()/3, GCDrainStackTargetSize); + target_size = MIN2(_task_queue->max_elems() / 3, GCDrainStackTargetSize); } else { target_size = 0; } diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index 20ee8ec1f2a..4f0b0973e76 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -178,15 +178,13 @@ PSPromotionManager::PSPromotionManager() { // We set the old lab's start array. _old_lab.set_start_array(old_gen()->start_array()); - uint queue_size; - queue_size = claimed_stack_depth()->max_elems(); + uint queue_size = claimed_stack_depth()->max_elems(); if (ParallelGCThreads == 1) { _target_stack_size = 0; } else { // don't let the target stack size to be more than 1/4 of the entries - _target_stack_size = (uint) MIN2((uint) GCDrainStackTargetSize, - (uint) (queue_size / 4)); + _target_stack_size = MIN2(GCDrainStackTargetSize, (queue_size / 4)); } _array_chunk_size = ParGCArrayScanChunk; diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 1a0b1b2c265..d610bae0c18 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -684,10 +684,10 @@ develop(uintx, GCExpandToAllocateDelayMillis, 0, \ "Delay between expansion and allocation (in milliseconds)") \ \ - product(uintx, GCDrainStackTargetSize, 64, \ + product(uint, GCDrainStackTargetSize, 64, \ "Number of entries we will try to leave on the stack " \ "during parallel gc") \ - range(0, max_juint) \ + range(0, (UINT_MAX - 1) / 2) \ \ product(uint, GCCardSizeInBytes, 512, \ "Card table entry size (in bytes) for card based collectors") \ diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 719992de62c..df06622391e 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1044,7 +1044,7 @@ const int badCodeHeapFreeVal = 0xDD; // value used to zap #define badHeapWord (::badHeapWordVal) // Default TaskQueue size is 16K (32-bit) or 128K (64-bit) -const size_t TASKQUEUE_SIZE = (NOT_LP64(1<<14) LP64_ONLY(1<<17)); +const uint TASKQUEUE_SIZE = (NOT_LP64(1<<14) LP64_ONLY(1<<17)); //---------------------------------------------------------------------------------------------------- // Utility functions for bitfield manipulations From 486fa08d4b22243443d39efa34c78d7e9eb44775 Mon Sep 17 00:00:00 2001 From: Thomas Obermeier Date: Thu, 31 Aug 2023 09:51:13 +0000 Subject: [PATCH 20/86] 8313873: java/nio/channels/DatagramChannel/SendReceiveMaxSize.java fails on AIX due to small default RCVBUF size and different IPv6 Header interpretation Reviewed-by: clanger, mbaesken --- .../DatagramChannel/SendReceiveMaxSize.java | 17 +++++++------ test/lib/jdk/test/lib/net/IPSupport.java | 25 +++++++++++++++++-- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java index f86166c6849..31407ecb493 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; import static java.net.StandardSocketOptions.SO_SNDBUF; +import static java.net.StandardSocketOptions.SO_RCVBUF; import static jdk.test.lib.net.IPSupport.hasIPv4; import static jdk.test.lib.net.IPSupport.hasIPv6; import static jdk.test.lib.net.IPSupport.preferIPv4Stack; @@ -63,8 +64,6 @@ import static org.testng.Assert.assertTrue; public class SendReceiveMaxSize { - private final static int IPV4_SNDBUF = 65507; - private final static int IPV6_SNDBUF = 65527; private final static Class IOE = IOException.class; private final static Random random = RandomFactory.getRandom(); @@ -89,12 +88,12 @@ public Object[][] invariants() throws IOException { .orElse((Inet4Address) InetAddress.getByName("127.0.0.1")); testcases.add(new Object[]{ supplier(() -> DatagramChannel.open()), - IPV4_SNDBUF, + IPSupport.getMaxUDPSendBufSizeIPv4(), IPv4Addr }); testcases.add(new Object[]{ supplier(() -> DatagramChannel.open(INET)), - IPV4_SNDBUF, + IPSupport.getMaxUDPSendBufSizeIPv4(), IPv4Addr }); } @@ -105,12 +104,12 @@ public Object[][] invariants() throws IOException { .orElse((Inet6Address) InetAddress.getByName("::1")); testcases.add(new Object[]{ supplier(() -> DatagramChannel.open()), - IPV6_SNDBUF, + IPSupport.getMaxUDPSendBufSizeIPv6(), IPv6Addr }); testcases.add(new Object[]{ supplier(() -> DatagramChannel.open(INET6)), - IPV6_SNDBUF, + IPSupport.getMaxUDPSendBufSizeIPv6(), IPv6Addr }); } @@ -132,6 +131,10 @@ public void testSendReceiveMaxSize(DatagramChannelSupplier supplier, int capacit throws IOException { try (var receiver = DatagramChannel.open()) { receiver.bind(new InetSocketAddress(host, 0)); + assertTrue(receiver.getOption(SO_RCVBUF) >= capacity, + receiver.getOption(SO_RCVBUF) + + " for UDP receive buffer too small to hold capacity " + + capacity); var port = receiver.socket().getLocalPort(); var addr = new InetSocketAddress(host, port); diff --git a/test/lib/jdk/test/lib/net/IPSupport.java b/test/lib/jdk/test/lib/net/IPSupport.java index 78efba3a172..9a630ea1831 100644 --- a/test/lib/jdk/test/lib/net/IPSupport.java +++ b/test/lib/jdk/test/lib/net/IPSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ package jdk.test.lib.net; +import jdk.test.lib.Platform; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; @@ -48,6 +50,9 @@ public class IPSupport { private static final boolean hasIPv6; private static final boolean preferIPv4Stack; private static final boolean preferIPv6Addresses; + private static final int IPV4_SNDBUF = 65507; + private static final int IPV6_SNDBUF = 65527; + private static final int IPV6_SNDBUF_AIX = 65487; static { hasIPv4 = runPrivilegedAction(() -> isSupported(Inet4Address.class)); @@ -111,7 +116,6 @@ public static final boolean preferIPv6Addresses() { return preferIPv6Addresses; } - /** * Whether or not the current networking configuration is valid or not. * @@ -154,4 +158,21 @@ public static void printPlatformSupport(PrintStream out) { out.println("preferIPv6Addresses: " + preferIPv6Addresses()); } + /** + * Return current platform's maximum size for IPv4 UDP send buffer + */ + public static final int getMaxUDPSendBufSizeIPv4() { + return IPV4_SNDBUF; + } + + /** + * Return current platform's maximum size for IPv6 UDP send buffer + */ + public static final int getMaxUDPSendBufSizeIPv6() { + if (Platform.isAix()) { + return IPV6_SNDBUF_AIX; + } else { + return IPV6_SNDBUF; + } + } } From 145d8bc1a3ef4f4fe0c10385be111838e7ed9250 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 31 Aug 2023 11:15:09 +0000 Subject: [PATCH 21/86] 8315051: jdk/jfr/jvm/TestGetEventWriter.java fails with non-JVMCI GCs Reviewed-by: phh, egahlin --- test/jdk/jdk/jfr/jvm/TestGetEventWriter.java | 29 +++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/test/jdk/jdk/jfr/jvm/TestGetEventWriter.java b/test/jdk/jdk/jfr/jvm/TestGetEventWriter.java index ec68d41f66b..298114b14e1 100644 --- a/test/jdk/jdk/jfr/jvm/TestGetEventWriter.java +++ b/test/jdk/jdk/jfr/jvm/TestGetEventWriter.java @@ -38,7 +38,7 @@ import jdk.vm.ci.runtime.JVMCI; /** - * @test TestGetEventWriter + * @test id=default * @key jfr * @requires vm.hasJFR * @library /test/lib @@ -57,9 +57,6 @@ * * @run main/othervm jdk.jfr.jvm.TestGetEventWriter * - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -Dtest.jvmci=true --add-exports=jdk.jfr/jdk.jfr.internal.event=ALL-UNNAMED - * jdk.jfr.jvm.TestGetEventWriter - * * @run main/othervm/timeout=300 -Xint -XX:+UseInterpreter -Dinterpreted=true * jdk.jfr.jvm.TestGetEventWriter * @@ -72,6 +69,30 @@ * @run main/othervm/timeout=300 -Xcomp -XX:TieredStopAtLevel=4 -XX:-TieredCompilation -XX:-UseInterpreter -Dinterpreted=false * jdk.jfr.jvm.TestGetEventWriter */ + +/** + * @test id=jvmci + * @key jfr + * @requires vm.hasJFR + * @requires vm.jvmci + * @library /test/lib + * @modules jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.runtime + * + * @compile PlaceholderEventWriter.java + * @compile PlaceholderEventWriterFactory.java + * @compile E.java + * @compile NonEvent.java + * @compile RegisteredTrueEvent.java + * @compile RegisteredFalseEvent.java + * @compile MyCommitRegisteredTrueEvent.java + * @compile MyCommitRegisteredFalseEvent.java + * @compile StaticCommitEvent.java + * + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -Dtest.jvmci=true --add-exports=jdk.jfr/jdk.jfr.internal.event=ALL-UNNAMED + * jdk.jfr.jvm.TestGetEventWriter + */ + public class TestGetEventWriter { static class InitializationEvent extends Event { From 29ff1e45b910c07711c4f4c3d821712dd9a1e3ba Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Thu, 31 Aug 2023 12:51:29 +0000 Subject: [PATCH 22/86] 8315445: 8314748 causes crashes in x64 builds Reviewed-by: chagedorn, shade --- src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index c7ca8e38356..f758fcc64ec 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -2131,7 +2131,7 @@ void StubGenerator::aesctr_encrypt(Register src_addr, Register dest_addr, Regist __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc0_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); ev_add128(xmm8, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); - __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit); + __ evmovdquq(xmm19, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, r15 /*rscratch*/); ev_add128(xmm9, xmm8, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); ev_add128(xmm10, xmm9, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); ev_add128(xmm11, xmm10, xmm19, Assembler::AVX_512bit, /*ktmp*/k1, ones); From ea5aa61c8cc5caa04f7c7eac9634df28011581dc Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Thu, 31 Aug 2023 16:10:44 +0000 Subject: [PATCH 23/86] 8315383: jlink SystemModulesPlugin incorrectly parses the options Reviewed-by: mchung --- .../tools/jlink/internal/plugins/SystemModulesPlugin.java | 2 +- test/jdk/tools/jlink/JLinkDedupTestBatchSizeOne.java | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java index 77ba8c063e8..ff55f812d91 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java @@ -148,7 +148,7 @@ public void configure(Map config) { if (split.length != 2) { throw new IllegalArgumentException(getName() + ": " + arg); } - if (split[0].equals("batch-size")) { + if (!split[0].equals("batch-size")) { throw new IllegalArgumentException(getName() + ": " + arg); } this.moduleDescriptorsPerMethod = Integer.parseInt(split[1]); diff --git a/test/jdk/tools/jlink/JLinkDedupTestBatchSizeOne.java b/test/jdk/tools/jlink/JLinkDedupTestBatchSizeOne.java index a8c8010ab3e..3a52f6b32c4 100644 --- a/test/jdk/tools/jlink/JLinkDedupTestBatchSizeOne.java +++ b/test/jdk/tools/jlink/JLinkDedupTestBatchSizeOne.java @@ -21,12 +21,8 @@ * questions. */ -import jdk.test.lib.JDKToolLauncher; import jdk.test.lib.compiler.CompilerUtils; -import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.process.ProcessTools; import tests.JImageGenerator; -import tests.Result; import java.io.File; import java.nio.file.Files; @@ -94,7 +90,7 @@ public static void main(String[] args) throws Throwable { .addMods("m2") .addMods("m3") .addMods("m4") - .option("--system-modules=batchSize=1") + .option("--system-modules=batch-size=1") .call() .assertSuccess(); From c8acab1d913a6c676706fce7ad98a7f831a95682 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Thu, 31 Aug 2023 16:11:03 +0000 Subject: [PATCH 24/86] 8315413: Remove special filtering of Continuation.yield0 in StackWalker Reviewed-by: alanb --- .../classes/java/lang/StackStreamFactory.java | 26 +------------------ .../jdk/internal/vm/Continuation/Basic.java | 2 +- .../internal/vm/Continuation/BasicExt.java | 2 +- .../jdk/internal/vm/Continuation/Scoped.java | 12 ++++----- 4 files changed, 9 insertions(+), 33 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StackStreamFactory.java b/src/java.base/share/classes/java/lang/StackStreamFactory.java index 36e93d92130..8d7b77ef5ea 100644 --- a/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -543,12 +543,6 @@ StackFrameInfo nextStackFrame() { final Class at(int index) { return stackFrames[index].declaringClass(); } - - @Override - final boolean filter(int index) { - return stackFrames[index].declaringClass() == Continuation.class - && "yield0".equals(stackFrames[index].getMethodName()); - } } final Function, ? extends T> function; // callback @@ -685,10 +679,6 @@ static final class ClassBuffer extends FrameBuffer> { @Override final Class at(int index) { return classes[index];} - @Override - final boolean filter(int index) { return false; } - - // ------ subclass may override the following methods ------- /** * Resizes the buffers for VM to fill in the next batch of stack frames. @@ -820,12 +810,6 @@ LiveStackFrameInfo nextStackFrame() { final Class at(int index) { return stackFrames[index].declaringClass(); } - - @Override - final boolean filter(int index) { - return stackFrames[index].declaringClass() == Continuation.class - && "yield0".equals(stackFrames[index].getMethodName()); - } } LiveStackInfoTraverser(StackWalker walker, @@ -895,13 +879,6 @@ abstract static class FrameBuffer { */ abstract Class at(int index); - /** - * Filter out frames at the top of a batch - * @param index the position of the frame. - * @return true if the frame should be skipped - */ - abstract boolean filter(int index); - // ------ subclass may override the following methods ------- /* @@ -1007,8 +984,7 @@ final void setBatch(int depth, int startIndex, int endIndex) { this.fence = endIndex; for (int i = START_POS; i < fence; i++) { if (isDebug) System.err.format(" frame %d: %s%n", i, at(i)); - if ((depth == 0 && filterStackWalkImpl(at(i))) // filter the frames due to the stack stream implementation - || filter(i)) { + if (depth == 0 && filterStackWalkImpl(at(i))) { // filter the frames due to the stack stream implementation origin++; } else { break; diff --git a/test/jdk/jdk/internal/vm/Continuation/Basic.java b/test/jdk/jdk/internal/vm/Continuation/Basic.java index 9fd3fb06099..14a7058f2a6 100644 --- a/test/jdk/jdk/internal/vm/Continuation/Basic.java +++ b/test/jdk/jdk/internal/vm/Continuation/Basic.java @@ -92,7 +92,7 @@ public void test1() { assertEquals(cont.isPreempted(), false); List frames = cont.stackWalker().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield", "bar", "foo", "lambda$test1$0", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "bar", "foo", "lambda$test1$0", "run", "enter0", "enter")); } assertEquals(res.get(), 247); assertEquals(cont.isPreempted(), false); diff --git a/test/jdk/jdk/internal/vm/Continuation/BasicExt.java b/test/jdk/jdk/internal/vm/Continuation/BasicExt.java index 47fa2e46aec..530bcb54f34 100644 --- a/test/jdk/jdk/internal/vm/Continuation/BasicExt.java +++ b/test/jdk/jdk/internal/vm/Continuation/BasicExt.java @@ -798,7 +798,7 @@ public void checkFrames_dontjit(Continuation cont) { cont.stackWalker() .walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); assertEquals(frames, cont.isDone() ? List.of() - : Arrays.asList("yield", "ord104_testMethod_dontinline", + : Arrays.asList("yield0", "yield", "ord104_testMethod_dontinline", "ord103_testMethod_dontinline", "ord102_testMethod_dontinline", "ord101_testMethod_dontinline", diff --git a/test/jdk/jdk/internal/vm/Continuation/Scoped.java b/test/jdk/jdk/internal/vm/Continuation/Scoped.java index be9a5a425b3..0d96aecdea0 100644 --- a/test/jdk/jdk/internal/vm/Continuation/Scoped.java +++ b/test/jdk/jdk/internal/vm/Continuation/Scoped.java @@ -74,27 +74,27 @@ public void test1() { frames = cont.stackWalker().walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("No scope: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), A).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("A: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), B).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("B: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter")); frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), C).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("C: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield", "lambda$bar$14", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter")); frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), K).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("K: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); frames = cont.stackWalker(EnumSet.noneOf(StackWalker.Option.class), null).walk(fs -> fs.map(StackWalker.StackFrame::getMethodName).collect(Collectors.toList())); System.out.println("null: " + frames); - assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); + assertEquals(frames, cont.isDone() ? List.of() : Arrays.asList("yield0", "yield", "lambda$bar$14", "run", "enter0", "enter", "run", "bar", "lambda$foo$8", "run", "enter0", "enter", "yield0", "run", "foo", "lambda$test1$0", "run", "enter0", "enter")); } assertEquals(res.get(), 2); } From b38bcae1bad399d0a3ffc091835bf89140550bc2 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Thu, 31 Aug 2023 19:18:18 +0000 Subject: [PATCH 25/86] 8313656: assert(!JvmtiExport::can_support_virtual_threads()) with -XX:-DoJVMTIVirtualThreadTransitions Reviewed-by: sspitsyn, lmesnik --- src/hotspot/share/prims/jvmtiEnv.cpp | 4 +- .../share/prims/jvmtiManageCapabilities.cpp | 39 +++++++++++++++++-- .../share/prims/jvmtiManageCapabilities.hpp | 16 +++++++- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index e82e4de0f66..15472787f64 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -1009,7 +1009,7 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm jvmtiError JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list) { - if (!JvmtiExport::can_support_virtual_threads()) { + if (get_capabilities()->can_support_virtual_threads == 0) { return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; } JavaThread* current = JavaThread::current(); @@ -1127,7 +1127,7 @@ JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmt jvmtiError JvmtiEnv::ResumeAllVirtualThreads(jint except_count, const jthread* except_list) { - if (!JvmtiExport::can_support_virtual_threads()) { + if (get_capabilities()->can_support_virtual_threads == 0) { return JVMTI_ERROR_MUST_POSSESS_CAPABILITY; } jvmtiError err = JvmtiEnvBase::check_thread_list(except_count, except_list); diff --git a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp index 8bca96fc9a4..8819c07813f 100644 --- a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp +++ b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "jvmtifiles/jvmtiEnv.hpp" #include "logging/log.hpp" +#include "runtime/mutexLocker.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiManageCapabilities.hpp" @@ -55,7 +56,12 @@ jvmtiCapabilities JvmtiManageCapabilities::onload_solo_remaining_capabilities; // all capabilities ever acquired jvmtiCapabilities JvmtiManageCapabilities::acquired_capabilities; +int JvmtiManageCapabilities::_can_support_virtual_threads_count = 0; + +Mutex* JvmtiManageCapabilities::_capabilities_lock = nullptr; + void JvmtiManageCapabilities::initialize() { + _capabilities_lock = new Mutex(Mutex::nosafepoint, "Capabilities_lock"); always_capabilities = init_always_capabilities(); onload_capabilities = init_onload_capabilities(); always_solo_capabilities = init_always_solo_capabilities(); @@ -211,8 +217,14 @@ void JvmtiManageCapabilities::copy_capabilities(const jvmtiCapabilities *from, j } } +Mutex* JvmtiManageCapabilities::lock() { + if (Thread::current_or_null() == nullptr) { + return nullptr; // Detached thread, can be a call from Agent_OnLoad. + } + return _capabilities_lock; +} -void JvmtiManageCapabilities::get_potential_capabilities(const jvmtiCapabilities *current, +void JvmtiManageCapabilities::get_potential_capabilities_nolock(const jvmtiCapabilities *current, const jvmtiCapabilities *prohibited, jvmtiCapabilities *result) { // exclude prohibited capabilities, must be before adding current @@ -231,13 +243,22 @@ void JvmtiManageCapabilities::get_potential_capabilities(const jvmtiCapabilities } } +void JvmtiManageCapabilities::get_potential_capabilities(const jvmtiCapabilities* current, + const jvmtiCapabilities* prohibited, + jvmtiCapabilities* result) { + MutexLocker ml(lock(), Mutex::_no_safepoint_check_flag); + get_potential_capabilities_nolock(current, prohibited, result); +} + jvmtiError JvmtiManageCapabilities::add_capabilities(const jvmtiCapabilities *current, const jvmtiCapabilities *prohibited, const jvmtiCapabilities *desired, jvmtiCapabilities *result) { + MutexLocker ml(lock(), Mutex::_no_safepoint_check_flag); + // check that the capabilities being added are potential capabilities jvmtiCapabilities temp; - get_potential_capabilities(current, prohibited, &temp); + get_potential_capabilities_nolock(current, prohibited, &temp); if (has_some(exclude(desired, &temp, &temp))) { return JVMTI_ERROR_NOT_AVAILABLE; } @@ -259,6 +280,10 @@ jvmtiError JvmtiManageCapabilities::add_capabilities(const jvmtiCapabilities *cu exclude(&always_solo_remaining_capabilities, desired, &always_solo_remaining_capabilities); exclude(&onload_solo_remaining_capabilities, desired, &onload_solo_remaining_capabilities); + if (desired->can_support_virtual_threads != 0 && current->can_support_virtual_threads == 0) { + _can_support_virtual_threads_count++; + } + // return the result either(current, desired, result); @@ -271,6 +296,8 @@ jvmtiError JvmtiManageCapabilities::add_capabilities(const jvmtiCapabilities *cu void JvmtiManageCapabilities::relinquish_capabilities(const jvmtiCapabilities *current, const jvmtiCapabilities *unwanted, jvmtiCapabilities *result) { + MutexLocker ml(lock(), Mutex::_no_safepoint_check_flag); + jvmtiCapabilities to_trash; jvmtiCapabilities temp; @@ -283,6 +310,12 @@ void JvmtiManageCapabilities::relinquish_capabilities(const jvmtiCapabilities *c either(&onload_solo_remaining_capabilities, both(&onload_solo_capabilities, &to_trash, &temp), &onload_solo_remaining_capabilities); + if (to_trash.can_support_virtual_threads != 0) { + assert(current->can_support_virtual_threads != 0, "sanity check"); + assert(_can_support_virtual_threads_count > 0, "sanity check"); + _can_support_virtual_threads_count--; + } + update(); // return the result @@ -366,7 +399,7 @@ void JvmtiManageCapabilities::update() { JvmtiExport::set_can_post_frame_pop(avail.can_generate_frame_pop_events); JvmtiExport::set_can_pop_frame(avail.can_pop_frame); JvmtiExport::set_can_force_early_return(avail.can_force_early_return); - JvmtiExport::set_can_support_virtual_threads(avail.can_support_virtual_threads); + JvmtiExport::set_can_support_virtual_threads(_can_support_virtual_threads_count != 0); JvmtiExport::set_should_clean_up_heap_objects(avail.can_generate_breakpoint_events); JvmtiExport::set_can_get_owned_monitor_info(avail.can_get_owned_monitor_info || avail.can_get_owned_monitor_stack_depth_info); diff --git a/src/hotspot/share/prims/jvmtiManageCapabilities.hpp b/src/hotspot/share/prims/jvmtiManageCapabilities.hpp index e588be4fa15..545909e3c4e 100644 --- a/src/hotspot/share/prims/jvmtiManageCapabilities.hpp +++ b/src/hotspot/share/prims/jvmtiManageCapabilities.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,12 @@ class JvmtiManageCapabilities : public AllStatic { // all capabilities ever acquired static jvmtiCapabilities acquired_capabilities; + // counter for the agents possess can_support_virtual_threads capability + static int _can_support_virtual_threads_count; + + // lock to access the class data + static Mutex* _capabilities_lock; + // basic intenal operations static jvmtiCapabilities *either(const jvmtiCapabilities *a, const jvmtiCapabilities *b, jvmtiCapabilities *result); static jvmtiCapabilities *both(const jvmtiCapabilities *a, const jvmtiCapabilities *b, jvmtiCapabilities *result); @@ -61,6 +67,14 @@ class JvmtiManageCapabilities : public AllStatic { static jvmtiCapabilities init_always_solo_capabilities(); static jvmtiCapabilities init_onload_solo_capabilities(); + // returns nullptr in onload phase + static Mutex* lock(); + + // get_potential_capabilities without lock + static void get_potential_capabilities_nolock(const jvmtiCapabilities* current, + const jvmtiCapabilities* prohibited, + jvmtiCapabilities* result); + public: static void initialize(); From c12ca885cc96b510c9ee2d54b520b7d4a98a0434 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Thu, 31 Aug 2023 20:10:15 +0000 Subject: [PATCH 26/86] 8312521: Unused field LocaleProviderAdapter#defaultLocaleProviderAdapter could be removed Reviewed-by: naoto --- .../locale/provider/LocaleProviderAdapter.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 87ff39b9156..01654672abf 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -108,12 +108,6 @@ public String getTextResourcesPackage() { */ private static final Map adapterInstances = new ConcurrentHashMap<>(); - /** - * Default fallback adapter type, which should return something meaningful in any case. - * This is either CLDR or FALLBACK. - */ - static volatile LocaleProviderAdapter.Type defaultLocaleProviderAdapter; - /** * Adapter lookup cache. */ @@ -147,13 +141,11 @@ public String getTextResourcesPackage() { } } - defaultLocaleProviderAdapter = Type.CLDR; if (!typeList.isEmpty()) { // bona fide preference exists if (!(typeList.contains(Type.CLDR) || typeList.contains(Type.JRE))) { // Append FALLBACK as the last resort when no ResourceBundleBasedAdapter is available. typeList.add(Type.FALLBACK); - defaultLocaleProviderAdapter = Type.FALLBACK; } } else { // Default preference list. @@ -345,10 +337,10 @@ public static Locale[] toLocaleArray(Set tags) { public abstract BreakIteratorProvider getBreakIteratorProvider(); /** - * Returns a ollatorProvider for this LocaleProviderAdapter, or null if no - * ollatorProvider is available. + * Returns a CollatorProvider for this LocaleProviderAdapter, or null if no + * CollatorProvider is available. * - * @return a ollatorProvider + * @return a collatorProvider */ public abstract CollatorProvider getCollatorProvider(); From 351c31ea58a942d7d6d381f82216b9c1d5132876 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Thu, 31 Aug 2023 20:38:41 +0000 Subject: [PATCH 27/86] 8315378: [BACKOUT] runtime/NMT/SummarySanityCheck.java failed with "Total committed (MMMMMM) did not match the summarized committed (NNNNNN)" Reviewed-by: stuefe, ccheung --- src/hotspot/share/services/mallocTracker.cpp | 24 -------------------- src/hotspot/share/services/mallocTracker.hpp | 11 ++++++++- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/hotspot/share/services/mallocTracker.cpp b/src/hotspot/share/services/mallocTracker.cpp index 363bc2bb418..bddfcfffc08 100644 --- a/src/hotspot/share/services/mallocTracker.cpp +++ b/src/hotspot/share/services/mallocTracker.cpp @@ -70,30 +70,6 @@ size_t MallocMemorySnapshot::total_arena() const { return amount; } -void MallocMemorySnapshot::copy_to(MallocMemorySnapshot* s) { - // Need to make sure that mtChunks don't get deallocated while the - // copy is going on, because their size is adjusted using this - // buffer in make_adjustment(). - ThreadCritical tc; - size_t total_size; - size_t loop_counter = 0; - const size_t loop_limit = 100; - // It is observed that other threads can allocate during the loop of copying. - // This results in inconsistent total and sum of parts. So, the while-loop and - // the local total_size are used to find and try again a limited number of times. - // Acheiving fully consistent total and sum of parts requires to block all mallooc's during - // the copy which is a performance obstacle. - do { - total_size = 0; - s->_all_mallocs = _all_mallocs; - for (int index = 0; index < mt_number_of_types; index ++) { - s->_malloc[index] = _malloc[index]; - total_size += _malloc[index].malloc_size(); - } - } while(s->_all_mallocs.size() != total_size && ++loop_counter < loop_limit); - assert(s->_all_mallocs.size() == total_size, "Total != sum of parts"); -} - // Make adjustment by subtracting chunks used by arenas // from total chunks to get total free chunk size void MallocMemorySnapshot::make_adjustment() { diff --git a/src/hotspot/share/services/mallocTracker.hpp b/src/hotspot/share/services/mallocTracker.hpp index 84bba305043..4088abd7005 100644 --- a/src/hotspot/share/services/mallocTracker.hpp +++ b/src/hotspot/share/services/mallocTracker.hpp @@ -186,7 +186,16 @@ class MallocMemorySnapshot : public ResourceObj { return s->by_type(mtThreadStack)->malloc_count(); } - void copy_to(MallocMemorySnapshot* s); + void copy_to(MallocMemorySnapshot* s) { + // Need to make sure that mtChunks don't get deallocated while the + // copy is going on, because their size is adjusted using this + // buffer in make_adjustment(). + ThreadCritical tc; + s->_all_mallocs = _all_mallocs; + for (int index = 0; index < mt_number_of_types; index ++) { + s->_malloc[index] = _malloc[index]; + } + } // Make adjustment by subtracting chunks used by arenas // from total chunks to get total free chunk size From 2436fb010e6a11755ee0ba2dbc51a230a2cb2c7f Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Thu, 31 Aug 2023 20:40:25 +0000 Subject: [PATCH 28/86] 8312306: Add more Reference.reachabilityFence() calls to the security classes using Cleaner Reviewed-by: ascarpino --- .../com/sun/crypto/provider/DESKey.java | 67 ++++++++----- .../com/sun/crypto/provider/DESedeKey.java | 74 +++++++++----- .../com/sun/crypto/provider/KeyProtector.java | 11 +-- .../com/sun/crypto/provider/PBEKey.java | 96 ++++++++++++------- .../sun/crypto/provider/PBEKeyFactory.java | 4 +- .../KeyFactory/PBEKeyDestroyTest.java | 71 ++++++++++++++ 6 files changed, 234 insertions(+), 89 deletions(-) create mode 100644 test/jdk/com/sun/crypto/provider/KeyFactory/PBEKeyDestroyTest.java diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java index 2550556bbad..87aa1753eb5 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESKey.java @@ -89,12 +89,12 @@ final class DESKey implements SecretKey { public byte[] getEncoded() { // Return a copy of the key, rather than a reference, // so that the key data cannot be modified from outside - - // The key is zeroized by finalize() - // The reachability fence ensures finalize() isn't called early - byte[] result = key.clone(); - Reference.reachabilityFence(this); - return result; + try { + return key.clone(); + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } public String getAlgorithm() { @@ -111,25 +111,35 @@ public String getFormat() { */ @Override public int hashCode() { - return Arrays.hashCode(this.key) ^ "des".hashCode(); + try { + return Arrays.hashCode(this.key) ^ "des".hashCode(); + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } @Override public boolean equals(Object obj) { - if (this == obj) - return true; - - if (!(obj instanceof SecretKey that)) - return false; - - String thatAlg = that.getAlgorithm(); - if (!(thatAlg.equalsIgnoreCase("DES"))) - return false; - - byte[] thatKey = that.getEncoded(); - boolean ret = MessageDigest.isEqual(this.key, thatKey); - java.util.Arrays.fill(thatKey, (byte)0x00); - return ret; + try { + if (this == obj) + return true; + + if (!(obj instanceof SecretKey that)) + return false; + + String thatAlg = that.getAlgorithm(); + if (!(thatAlg.equalsIgnoreCase("DES"))) + return false; + + byte[] thatKey = that.getEncoded(); + boolean ret = MessageDigest.isEqual(this.key, thatKey); + java.util.Arrays.fill(thatKey, (byte)0x00); + return ret; + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } /** @@ -141,7 +151,13 @@ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); - key = key.clone(); + byte[] temp = key; + key = temp.clone(); + Arrays.fill(temp, (byte)0x00); + // Use the cleaner to zero the key when no longer referenced + final byte[] k = this.key; + CleanerFactory.cleaner().register(this, + () -> java.util.Arrays.fill(k, (byte)0x00)); } /** @@ -154,9 +170,14 @@ private void readObject(java.io.ObjectInputStream s) */ @java.io.Serial private Object writeReplace() throws java.io.ObjectStreamException { - return new KeyRep(KeyRep.Type.SECRET, + try { + return new KeyRep(KeyRep.Type.SECRET, getAlgorithm(), getFormat(), key); + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java index 7e075343abd..938fd217eee 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeKey.java @@ -89,11 +89,12 @@ final class DESedeKey implements SecretKey { } public byte[] getEncoded() { - // The key is zeroized by finalize() - // The reachability fence ensures finalize() isn't called early - byte[] result = key.clone(); - Reference.reachabilityFence(this); - return result; + try { + return key.clone(); + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } public String getAlgorithm() { @@ -110,26 +111,36 @@ public String getFormat() { */ @Override public int hashCode() { - return Arrays.hashCode(this.key) ^ "desede".hashCode(); + try { + return Arrays.hashCode(this.key) ^ "desede".hashCode(); + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } @Override public boolean equals(Object obj) { - if (this == obj) - return true; - - if (!(obj instanceof SecretKey that)) - return false; - - String thatAlg = that.getAlgorithm(); - if (!(thatAlg.equalsIgnoreCase("DESede")) - && !(thatAlg.equalsIgnoreCase("TripleDES"))) - return false; - - byte[] thatKey = that.getEncoded(); - boolean ret = MessageDigest.isEqual(this.key, thatKey); - java.util.Arrays.fill(thatKey, (byte)0x00); - return ret; + try { + if (this == obj) + return true; + + if (!(obj instanceof SecretKey that)) + return false; + + String thatAlg = that.getAlgorithm(); + if (!(thatAlg.equalsIgnoreCase("DESede")) + && !(thatAlg.equalsIgnoreCase("TripleDES"))) + return false; + + byte[] thatKey = that.getEncoded(); + boolean ret = MessageDigest.isEqual(this.key, thatKey); + java.util.Arrays.fill(thatKey, (byte)0x00); + return ret; + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } /** @@ -141,7 +152,13 @@ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); - key = key.clone(); + byte[] temp = key; + this.key = temp.clone(); + java.util.Arrays.fill(temp, (byte)0x00); + // Use the cleaner to zero the key when no longer referenced + final byte[] k = this.key; + CleanerFactory.cleaner().register(this, + () -> java.util.Arrays.fill(k, (byte)0x00)); } /** @@ -154,9 +171,14 @@ private void readObject(java.io.ObjectInputStream s) */ @java.io.Serial private Object writeReplace() throws java.io.ObjectStreamException { - return new KeyRep(KeyRep.Type.SECRET, - getAlgorithm(), - getFormat(), - key); + try { + return new KeyRep(KeyRep.Type.SECRET, + getAlgorithm(), + getFormat(), + key); + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java b/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java index e396f937a13..44c7a1f6432 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/KeyProtector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,7 +129,7 @@ byte[] protect(PrivateKey key) SecretKey sKey = null; PBEWithMD5AndTripleDESCipher cipher; try { - sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES", false); + sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); // encrypt private key cipher = new PBEWithMD5AndTripleDESCipher(); cipher.engineInit(Cipher.ENCRYPT_MODE, sKey, pbeSpec, null); @@ -193,7 +193,7 @@ Key recover(EncryptedPrivateKeyInfo encrInfo) // create PBE key from password PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); - sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES", false); + sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); pbeKeySpec.clearPassword(); // decrypt private key @@ -339,7 +339,7 @@ SealedObject seal(Key key) SecretKey sKey = null; Cipher cipher; try { - sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES", false); + sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); pbeKeySpec.clearPassword(); // seal key @@ -366,8 +366,7 @@ Key unseal(SealedObject so, int maxLength) try { // create PBE key from password PBEKeySpec pbeKeySpec = new PBEKeySpec(this.password); - sKey = new PBEKey(pbeKeySpec, - "PBEWithMD5AndTripleDES", false); + sKey = new PBEKey(pbeKeySpec, "PBEWithMD5AndTripleDES"); pbeKeySpec.clearPassword(); SealedObjectForKeyProtector soForKeyProtector = null; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java index dba3cccf193..71efeb535aa 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEKey.java @@ -26,6 +26,7 @@ package com.sun.crypto.provider; import java.lang.ref.Reference; +import java.lang.ref.Cleaner.Cleanable; import java.security.MessageDigest; import java.security.KeyRep; import java.security.spec.InvalidKeySpecException; @@ -51,13 +52,14 @@ final class PBEKey implements SecretKey { private String type; + private transient Cleanable cleanable; + /** * Creates a PBE key from a given PBE key specification. * * @param keytype the given PBE key specification */ - PBEKey(PBEKeySpec keySpec, String keytype, boolean useCleaner) - throws InvalidKeySpecException { + PBEKey(PBEKeySpec keySpec, String keytype) throws InvalidKeySpecException { char[] passwd = keySpec.getPassword(); if (passwd == null) { // Should allow an empty password. @@ -78,19 +80,18 @@ final class PBEKey implements SecretKey { type = keytype; // Use the cleaner to zero the key when no longer referenced - if (useCleaner) { - final byte[] k = this.key; - CleanerFactory.cleaner().register(this, - () -> Arrays.fill(k, (byte) 0x00)); - } + final byte[] k = this.key; + cleanable = CleanerFactory.cleaner().register(this, + () -> java.util.Arrays.fill(k, (byte)0x00)); } public byte[] getEncoded() { - // The key is zeroized by finalize() - // The reachability fence ensures finalize() isn't called early - byte[] result = key.clone(); - Reference.reachabilityFence(this); - return result; + try { + return key.clone(); + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } public String getAlgorithm() { @@ -107,25 +108,40 @@ public String getFormat() { */ @Override public int hashCode() { - return Arrays.hashCode(this.key) - ^ getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode(); + try { + return Arrays.hashCode(this.key) + ^ getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode(); + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } @Override public boolean equals(Object obj) { - if (obj == this) - return true; + try { + if (obj == this) + return true; + + if (!(obj instanceof SecretKey that)) + return false; - if (!(obj instanceof SecretKey that)) - return false; + // destroyed keys are considered different + if (isDestroyed() || that.isDestroyed()) { + return false; + } - if (!(that.getAlgorithm().equalsIgnoreCase(type))) - return false; + if (!(that.getAlgorithm().equalsIgnoreCase(type))) + return false; - byte[] thatEncoded = that.getEncoded(); - boolean ret = MessageDigest.isEqual(this.key, thatEncoded); - Arrays.fill(thatEncoded, (byte)0x00); - return ret; + byte[] thatEncoded = that.getEncoded(); + boolean ret = MessageDigest.isEqual(this.key, thatEncoded); + Arrays.fill(thatEncoded, (byte)0x00); + return ret; + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } /** @@ -134,12 +150,17 @@ public boolean equals(Object obj) { */ @Override public void destroy() { - if (key != null) { - Arrays.fill(key, (byte) 0x00); - key = null; + if (cleanable != null) { + cleanable.clean(); + cleanable = null; } } + @Override + public boolean isDestroyed() { + return (cleanable == null); + } + /** * readObject is called to restore the state of this key from * a stream. @@ -149,7 +170,13 @@ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); - key = key.clone(); + byte[] temp = key; + key = temp.clone(); + Arrays.fill(temp, (byte)0x00); + // Use cleaner to zero the key when no longer referenced + final byte[] k = this.key; + cleanable = CleanerFactory.cleaner().register(this, + () -> java.util.Arrays.fill(k, (byte)0x00)); } @@ -163,9 +190,14 @@ private void readObject(java.io.ObjectInputStream s) */ @java.io.Serial private Object writeReplace() throws java.io.ObjectStreamException { - return new KeyRep(KeyRep.Type.SECRET, - getAlgorithm(), - getFormat(), - key); + try { + return new KeyRep(KeyRep.Type.SECRET, + getAlgorithm(), + getFormat(), + key); + } finally { + // prevent this from being cleaned for the above block + Reference.reachabilityFence(this); + } } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java index 98f4e3923a8..66c0e6904c3 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,7 +239,7 @@ protected SecretKey engineGenerateSecret(KeySpec keySpec) if (!(keySpec instanceof PBEKeySpec)) { throw new InvalidKeySpecException("Invalid key spec"); } - return new PBEKey((PBEKeySpec)keySpec, type, true); + return new PBEKey((PBEKeySpec)keySpec, type); } /** diff --git a/test/jdk/com/sun/crypto/provider/KeyFactory/PBEKeyDestroyTest.java b/test/jdk/com/sun/crypto/provider/KeyFactory/PBEKeyDestroyTest.java new file mode 100644 index 00000000000..da266c147fb --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/KeyFactory/PBEKeyDestroyTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8312306 + * @summary Check the destroy()/isDestroyed() of the PBEKey impl from SunJCE + * @library /test/lib + * @run testng/othervm PBEKeyDestroyTest + */ +import javax.crypto.*; +import javax.crypto.spec.*; +import java.nio.charset.StandardCharsets; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class PBEKeyDestroyTest { + + @Test + public void test() throws Exception { + PBEKeySpec keySpec = new PBEKeySpec("12345678".toCharArray(), + "abcdefgh".getBytes(StandardCharsets.UTF_8), 100000, 128 >> 3); + + SecretKeyFactory skf = SecretKeyFactory.getInstance + ("PBEWithHmacSHA1AndAES_128", "SunJCE"); + + SecretKey key1 = skf.generateSecret(keySpec); + SecretKey key2 = skf.generateSecret(keySpec); + + // should be equal + Assert.assertFalse(key1.isDestroyed()); + Assert.assertFalse(key2.isDestroyed()); + Assert.assertTrue(key1.equals(key2)); + Assert.assertTrue(key2.equals(key1)); + + // destroy key1 + key1.destroy(); + Assert.assertTrue(key1.isDestroyed()); + Assert.assertFalse(key1.equals(key2)); + Assert.assertFalse(key2.equals(key1)); + + // also destroy key2 + key2.destroy(); + Assert.assertTrue(key2.isDestroyed()); + Assert.assertFalse(key1.equals(key2)); + Assert.assertFalse(key2.equals(key1)); + + // call destroy again to make sure no unexpected exceptions + key2.destroy(); + } +} From 63f561fac2eb6ec57f860af71cd6deebb9027aaf Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 31 Aug 2023 21:14:22 +0000 Subject: [PATCH 29/86] 8306882: (fs) Path.toRealPath(LinkOption.NOFOLLOW_LINKS) fails when "../../" follows a link Reviewed-by: alanb --- .../unix/classes/sun/nio/fs/UnixPath.java | 16 ++++-- test/jdk/ProblemList.txt | 6 ++- test/jdk/java/nio/file/Path/ToRealPath.java | 52 ++++++++++++++++++- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index a9c63dac923..5e3a80b6063 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -888,8 +888,15 @@ public Path toRealPath(LinkOption... options) throws IOException { } // if not resolving links then eliminate "." and also ".." - // where the previous element is not a link. + // where the previous element is neither a link nor "..". + // if there is a preceding "..", then it might have followed + // a link or a link followed by a sequence of two or more "..". + // if for example one has the path "link/../../file", + // then if a preceding ".." were eliminated, then the result + // would be "/link/file" instead of the correct + // "/link/../../file". UnixPath result = fs.rootDirectory(); + boolean parentIsDotDot = false; for (int i = 0; i < absolute.getNameCount(); i++) { UnixPath element = absolute.getName(i); @@ -898,7 +905,7 @@ public Path toRealPath(LinkOption... options) throws IOException { (element.asByteArray()[0] == '.')) continue; - // cannot eliminate ".." if previous element is a link + // cannot eliminate ".." if previous element is a link or ".." if ((element.asByteArray().length == 2) && (element.asByteArray()[0] == '.') && (element.asByteArray()[1] == '.')) @@ -909,13 +916,16 @@ public Path toRealPath(LinkOption... options) throws IOException { } catch (UnixException x) { x.rethrowAsIOException(result); } - if (!attrs.isSymbolicLink()) { + if (!attrs.isSymbolicLink() && !parentIsDotDot) { result = result.getParent(); if (result == null) { result = fs.rootDirectory(); } continue; } + parentIsDotDot = true; + } else { + parentIsDotDot = false; } result = result.resolve(element); } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 31546524178..5bf9284e3bb 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -543,13 +543,15 @@ java/net/MulticastSocket/SetOutgoingIf.java 8308807 aix-ppc6 java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc64 +java/nio/channels/DatagramChannel/AfterDisconnect.java 8308807 aix-ppc64 + java/nio/channels/DatagramChannel/ManySourcesAndTargets.java 8264385 macosx-aarch64 java/nio/channels/DatagramChannel/Unref.java 8233437 generic-all -jdk/nio/zipfs/TestLocOffsetFromZip64EF.java 8301183 linux-all +java/nio/file/Path/ToRealPath.java 8315273 windows-all -java/nio/channels/DatagramChannel/AfterDisconnect.java 8308807 aix-ppc64 +jdk/nio/zipfs/TestLocOffsetFromZip64EF.java 8301183 linux-all ############################################################################ diff --git a/test/jdk/java/nio/file/Path/ToRealPath.java b/test/jdk/java/nio/file/Path/ToRealPath.java index bbf7973b4ff..46e267e956a 100644 --- a/test/jdk/java/nio/file/Path/ToRealPath.java +++ b/test/jdk/java/nio/file/Path/ToRealPath.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 8295753 + * @bug 8295753 8306882 * @summary Verify correct operation of Path.toRealPath * @library .. /test/lib * @build ToRealPath jdk.test.lib.Platform @@ -142,6 +142,52 @@ public void eliminateDotsNoFollow() throws IOException { DIR.toRealPath(NOFOLLOW_LINKS)); } + @Test + @EnabledIf("supportsLinks") + public void noCollapseDots1() throws IOException { + Path subPath = DIR.resolve(Path.of("dir", "subdir")); + Path sub = Files.createDirectories(subPath); + System.out.println("sub: " + sub); + Files.createSymbolicLink(LINK, sub); + System.out.println("LINK: " + LINK + " -> " + sub); + Path p = Path.of("..", "..", FILE.getFileName().toString()); + System.out.println("p: " + p); + Path path = LINK.resolve(p); + System.out.println("path: " + path); + System.out.println("no follow: " + path.toRealPath(NOFOLLOW_LINKS)); + assertEquals(path.toRealPath(NOFOLLOW_LINKS), path); + + Files.delete(sub); + Files.delete(sub.getParent()); + Files.delete(LINK); + } + + @Test + @EnabledIf("supportsLinks") + public void noCollapseDots2() throws IOException { + Path subPath = DIR.resolve(Path.of("dir", "subdir")); + Path sub = Files.createDirectories(subPath); + Path out = Files.createFile(DIR.resolve(Path.of("out.txt"))); + Path aaa = DIR.resolve(Path.of("aaa")); + Files.createSymbolicLink(aaa, sub); + System.out.println("aaa: " + aaa + " -> " + sub); + Path bbb = DIR.resolve(Path.of("bbb")); + Files.createSymbolicLink(bbb, sub); + System.out.println("bbb: " + bbb + " -> " + sub); + Path p = Path.of("aaa", "..", "..", "bbb", "..", "..", "out.txt"); + Path path = DIR.resolve(p); + System.out.println("path: " + path); + System.out.println("no follow: " + path.toRealPath(NOFOLLOW_LINKS)); + assertEquals(path.toRealPath(NOFOLLOW_LINKS), path); + System.out.println(path.toRealPath()); + + Files.delete(sub); + Files.delete(sub.getParent()); + Files.delete(out); + Files.delete(aaa); + Files.delete(bbb); + } + @Test @EnabledOnOs(OS.MAC) public final void macOSTests() throws IOException { @@ -180,12 +226,14 @@ public final void macOSTests() throws IOException { assertEquals(noFollow.getName(nc - 4), Path.of("theLink")); assertEquals(noFollow.getName(nc - 1), Path.of("theTarget")); + Files.delete(theLink); Files.delete(theTarget); } @AfterAll public static void cleanup() throws IOException { - Files.delete(SUBDIR); Files.delete(FILE); + Files.delete(SUBDIR); + Files.delete(DIR); } } From d5973bdb986a1dd823b6a761ff719de005c549f6 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 31 Aug 2023 21:43:09 +0000 Subject: [PATCH 30/86] 6333341: [BI] Doc: java.text.BreakIterator class specification is unclear Reviewed-by: naoto --- src/java.base/share/classes/java/text/BreakIterator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/text/BreakIterator.java b/src/java.base/share/classes/java/text/BreakIterator.java index 965d9a4e2c1..132fc978c41 100644 --- a/src/java.base/share/classes/java/text/BreakIterator.java +++ b/src/java.base/share/classes/java/text/BreakIterator.java @@ -105,7 +105,10 @@ * * Grapheme Cluster Boundaries section in the Unicode Standard Annex #29. * - *

+ * @implNote The default implementations of {@code BreakIterator} will perform the equivalent + * of calling {@code setText("")} if the text hasn't been set by either + * {@link #setText(String)} or {@link #setText(CharacterIterator)} + * and a boundary searching operation is called by the {@code BreakIterator} instance. * The {@code BreakIterator} instances returned by the factory methods * of this class are intended for use with natural languages only, not for * programming language text. It is however possible to define subclasses From 2264667bba2311b568257a933813fa76a9e75313 Mon Sep 17 00:00:00 2001 From: John Jiang Date: Thu, 31 Aug 2023 22:26:48 +0000 Subject: [PATCH 31/86] 8315422: getSoTimeout() would be in try block in SSLSocketImpl Reviewed-by: jnimeh --- .../sun/security/ssl/SSLSocketImpl.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index 2dbfdcdca41..9f22a5bb455 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1782,21 +1782,24 @@ private void closeSocket(boolean selfInitiated) throws IOException { if (conContext.inputRecord instanceof SSLSocketInputRecord inputRecord && isConnected) { if (appInput.readLock.tryLock()) { - int soTimeout = getSoTimeout(); try { - // deplete could hang on the skip operation - // in case of infinite socket read timeout. - // Change read timeout to avoid deadlock. - // This workaround could be replaced later - // with the right synchronization - if (soTimeout == 0) - setSoTimeout(DEFAULT_SKIP_TIMEOUT); - inputRecord.deplete(false); - } catch (java.net.SocketTimeoutException stEx) { - // skip timeout exception during deplete + int soTimeout = getSoTimeout(); + try { + // deplete could hang on the skip operation + // in case of infinite socket read timeout. + // Change read timeout to avoid deadlock. + // This workaround could be replaced later + // with the right synchronization + if (soTimeout == 0) + setSoTimeout(DEFAULT_SKIP_TIMEOUT); + inputRecord.deplete(false); + } catch (java.net.SocketTimeoutException stEx) { + // skip timeout exception during deplete + } finally { + if (soTimeout == 0) + setSoTimeout(soTimeout); + } } finally { - if (soTimeout == 0) - setSoTimeout(soTimeout); appInput.readLock.unlock(); } } From 7754ac05062c698b8601048ae447849d982c8dbe Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 31 Aug 2023 23:02:26 +0000 Subject: [PATCH 32/86] 8314925: ChoiceFormat does not specify IllegalArgumentExceptions Reviewed-by: naoto --- .../share/classes/java/text/ChoiceFormat.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/text/ChoiceFormat.java b/src/java.base/share/classes/java/text/ChoiceFormat.java index 84a3e4ef7ad..c080bc897ab 100644 --- a/src/java.base/share/classes/java/text/ChoiceFormat.java +++ b/src/java.base/share/classes/java/text/ChoiceFormat.java @@ -176,6 +176,8 @@ public class ChoiceFormat extends NumberFormat { * @param newPattern See the class description. * @throws NullPointerException if {@code newPattern} * is {@code null} + * @throws IllegalArgumentException if {@code newPattern} + * is invalid */ public void applyPattern(String newPattern) { StringBuilder[] segments = new StringBuilder[2]; @@ -315,6 +317,8 @@ public String toPattern() { * @param newPattern the new pattern string * @throws NullPointerException if {@code newPattern} is * {@code null} + * @throws IllegalArgumentException if {@code newPattern} + * is invalid * @see #applyPattern */ public ChoiceFormat(String newPattern) { @@ -328,6 +332,8 @@ public ChoiceFormat(String newPattern) { * @param formats corresponding format strings * @throws NullPointerException if {@code limits} or {@code formats} * is {@code null} + * @throws IllegalArgumentException if the length of {@code limits} + * and {@code formats} are not equal * @see #setChoices */ public ChoiceFormat(double[] limits, String[] formats) { @@ -345,11 +351,13 @@ public ChoiceFormat(double[] limits, String[] formats) { * @param formats are the formats you want to use for each limit. * @throws NullPointerException if {@code limits} or * {@code formats} is {@code null} + * @throws IllegalArgumentException if the length of {@code limits} + * and {@code formats} are not equal */ public void setChoices(double[] limits, String[] formats) { if (limits.length != formats.length) { throw new IllegalArgumentException( - "Array and limit arrays must be of the same length."); + "Input arrays must be of the same length."); } choiceLimits = Arrays.copyOf(limits, limits.length); choiceFormats = Arrays.copyOf(formats, formats.length); From 764f65c8b442697dfd46ee7a4c97971b28eb887b Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Fri, 1 Sep 2023 06:06:35 +0000 Subject: [PATCH 33/86] 8315278: Patch 'print-targets' target to print targets separated by new line Reviewed-by: erikj, ksakata --- make/Main.gmk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/make/Main.gmk b/make/Main.gmk index 506634126fb..22efccb8d7e 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -1431,13 +1431,13 @@ ALL_TARGETS += $(addsuffix -only, $(filter-out dist-clean clean%, $(ALL_TARGETS) # are internal only, to support Init.gmk. print-targets: - @$(ECHO) $(sort $(ALL_TARGETS)) + $(info $(subst $(SPACE),$(NEWLINE),$(sort $(ALL_TARGETS)))) print-modules: - @$(ECHO) $(sort $(ALL_MODULES)) + $(info $(subst $(SPACE),$(NEWLINE),$(sort $(ALL_MODULES)))) print-tests: - @$(ECHO) $(sort $(ALL_NAMED_TESTS)) + $(info $(subst $(SPACE),$(NEWLINE),$(sort $(ALL_NAMED_TESTS)))) create-main-targets-include: $(call LogInfo, Generating main target list) From 81b5d2211eb2616f497c17114f0a475174ad3bef Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Fri, 1 Sep 2023 08:01:39 +0000 Subject: [PATCH 34/86] 8315459: Print G1 reserved and committed sizes as separate items in VM.info and hs_err Reviewed-by: ayang, tschatzl --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index a28c3de9bb8..fc3af65bf70 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2199,8 +2199,8 @@ void G1CollectedHeap::print_heap_regions() const { void G1CollectedHeap::print_on(outputStream* st) const { size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked(); st->print(" %-20s", "garbage-first heap"); - st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", - capacity()/K, heap_used/K); + st->print(" total reserved %zuK, committed %zuK, used %zuK", + _hrm.reserved().byte_size()/K, capacity()/K, heap_used/K); st->print(" [" PTR_FORMAT ", " PTR_FORMAT ")", p2i(_hrm.reserved().start()), p2i(_hrm.reserved().end())); From c2e01eba5a537acd573b7d2e6d41811c415c3f68 Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Fri, 1 Sep 2023 08:33:33 +0000 Subject: [PATCH 35/86] 8313983: jmod create --target-platform should replace existing ModuleTarget attribute Reviewed-by: alanb, mchung --- .../share/classes/jdk/internal/classfile/Attributes.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/Attributes.java b/src/java.base/share/classes/jdk/internal/classfile/Attributes.java index c53386eaace..2a816e5df1b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Attributes.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Attributes.java @@ -461,7 +461,7 @@ protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) { /** Attribute mapper for the {@code ModuleResolution} attribute */ public static final AttributeMapper - MODULE_RESOLUTION = new AbstractAttributeMapper<>(NAME_MODULE_RESOLUTION, true, Classfile.JAVA_9_VERSION) { + MODULE_RESOLUTION = new AbstractAttributeMapper<>(NAME_MODULE_RESOLUTION, Classfile.JAVA_9_VERSION) { @Override public ModuleResolutionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { return new BoundAttribute.BoundModuleResolutionAttribute(cf, this, p); @@ -475,7 +475,7 @@ protected void writeBody(BufWriter buf, ModuleResolutionAttribute attr) { /** Attribute mapper for the {@code ModuleTarget} attribute */ public static final AttributeMapper - MODULE_TARGET = new AbstractAttributeMapper<>(NAME_MODULE_TARGET, true, Classfile.JAVA_9_VERSION) { + MODULE_TARGET = new AbstractAttributeMapper<>(NAME_MODULE_TARGET, Classfile.JAVA_9_VERSION) { @Override public ModuleTargetAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { return new BoundAttribute.BoundModuleTargetAttribute(cf, this, p); From 033f311abccc45567230c69c6e0f6d1746f3c7e4 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Fri, 1 Sep 2023 08:35:49 +0000 Subject: [PATCH 36/86] 8315069: Relativize extended_sp in interpreter frames Reviewed-by: haosun, aph, fyang --- .../continuationFreezeThaw_aarch64.inline.hpp | 9 +++++++-- src/hotspot/cpu/aarch64/frame_aarch64.cpp | 4 +++- src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp | 2 ++ .../aarch64/templateInterpreterGenerator_aarch64.cpp | 11 ++++++++--- src/hotspot/cpu/aarch64/templateTable_aarch64.cpp | 3 ++- .../riscv/continuationFreezeThaw_riscv.inline.hpp | 9 +++++++-- src/hotspot/cpu/riscv/frame_riscv.cpp | 4 +++- src/hotspot/cpu/riscv/interp_masm_riscv.hpp | 2 ++ .../cpu/riscv/templateInterpreterGenerator_riscv.cpp | 12 +++++++++--- src/hotspot/cpu/riscv/templateTable_riscv.cpp | 4 +++- 10 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp index 23a5ad71025..eca3cc33bfe 100644 --- a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp @@ -153,11 +153,14 @@ inline void FreezeBase::relativize_interpreted_frame_metadata(const frame& f, co assert((intptr_t*)hf.at_relative(frame::interpreter_frame_last_sp_offset) == hf.unextended_sp(), ""); relativize_one(vfp, hfp, frame::interpreter_frame_initial_sp_offset); // == block_top == block_bottom - relativize_one(vfp, hfp, frame::interpreter_frame_extended_sp_offset); + + // extended_sp is already relativized by TemplateInterpreterGenerator::generate_normal_entry or + // AbstractInterpreter::layout_activation assert((hf.fp() - hf.unextended_sp()) == (f.fp() - f.unextended_sp()), ""); assert(hf.unextended_sp() == (intptr_t*)hf.at(frame::interpreter_frame_last_sp_offset), ""); assert(hf.unextended_sp() <= (intptr_t*)hf.at(frame::interpreter_frame_initial_sp_offset), ""); + assert(hf.unextended_sp() > (intptr_t*)hf.at(frame::interpreter_frame_extended_sp_offset), ""); assert(hf.fp() > (intptr_t*)hf.at(frame::interpreter_frame_initial_sp_offset), ""); assert(hf.fp() <= (intptr_t*)hf.at(frame::interpreter_frame_locals_offset), ""); } @@ -294,7 +297,9 @@ inline void ThawBase::derelativize_interpreted_frame_metadata(const frame& hf, c assert((intptr_t*)f.at_relative(frame::interpreter_frame_last_sp_offset) == f.unextended_sp(), ""); derelativize_one(vfp, frame::interpreter_frame_initial_sp_offset); - derelativize_one(vfp, frame::interpreter_frame_extended_sp_offset); + + // Make sure that extended_sp is kept relativized. + assert((intptr_t*)f.at_relative(frame::interpreter_frame_extended_sp_offset) < f.unextended_sp(), ""); } #endif // CPU_AARCH64_CONTINUATIONFREEZETHAW_AARCH64_INLINE_HPP diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index 4ceae831e66..24a710de21f 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -362,7 +362,9 @@ void frame::interpreter_frame_set_last_sp(intptr_t* sp) { // Used by template based interpreter deoptimization void frame::interpreter_frame_set_extended_sp(intptr_t* sp) { - *((intptr_t**)addr_at(interpreter_frame_extended_sp_offset)) = sp; + assert(is_interpreted_frame(), "interpreted frame expected"); + // set relativized extended_sp + ptr_at_put(interpreter_frame_extended_sp_offset, (sp - fp())); } frame frame::sender_for_entry_frame(RegisterMap* map) const { diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp index 70822b6c424..5eb917f41a7 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp @@ -86,6 +86,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void restore_sp_after_call() { Label L; ldr(rscratch1, Address(rfp, frame::interpreter_frame_extended_sp_offset * wordSize)); + lea(rscratch1, Address(rfp, rscratch1, Address::lsl(LogBytesPerWord))); #ifdef ASSERT cbnz(rscratch1, L); stop("SP is null"); @@ -98,6 +99,7 @@ class InterpreterMacroAssembler: public MacroAssembler { #ifdef ASSERT Label L; ldr(rscratch1, Address(rfp, frame::interpreter_frame_extended_sp_offset * wordSize)); + lea(rscratch1, Address(rfp, rscratch1, Address::lsl(LogBytesPerWord))); cmp(sp, rscratch1); br(EQ, L); stop(msg); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index cafd61cff40..4f6e5a01b62 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -812,7 +812,8 @@ void TemplateInterpreterGenerator::lock_method() { __ check_extended_sp(); __ sub(sp, sp, entry_size); // add space for a monitor entry __ sub(esp, esp, entry_size); - __ mov(rscratch1, sp); + __ sub(rscratch1, sp, rfp); + __ asr(rscratch1, rscratch1, Interpreter::logStackElementSize); __ str(rscratch1, Address(rfp, frame::interpreter_frame_extended_sp_offset * wordSize)); __ str(esp, monitor_block_top); // set new monitor block top // store object @@ -880,15 +881,19 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ add(rscratch1, rscratch1, MAX2(3, Method::extra_stack_entries())); __ sub(rscratch1, sp, rscratch1, ext::uxtw, 3); __ andr(rscratch1, rscratch1, -16); + __ sub(rscratch2, rscratch1, rfp); + __ asr(rscratch2, rscratch2, Interpreter::logStackElementSize); // Store extended SP and mirror - __ stp(r10, rscratch1, Address(sp, 4 * wordSize)); + __ stp(r10, rscratch2, Address(sp, 4 * wordSize)); // Move SP out of the way __ mov(sp, rscratch1); } else { // Make sure there is room for the exception oop pushed in case method throws // an exception (see TemplateInterpreterGenerator::generate_throw_exception()) __ sub(rscratch1, sp, 2 * wordSize); - __ stp(r10, rscratch1, Address(sp, 4 * wordSize)); + __ sub(rscratch2, rscratch1, rfp); + __ asr(rscratch2, rscratch2, Interpreter::logStackElementSize); + __ stp(r10, rscratch2, Address(sp, 4 * wordSize)); __ mov(sp, rscratch1); } } diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index 3fed9c33033..d1cdbe4fd43 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -3910,7 +3910,8 @@ void TemplateTable::monitorenter() __ check_extended_sp(); __ sub(sp, sp, entry_size); // make room for the monitor - __ mov(rscratch1, sp); + __ sub(rscratch1, sp, rfp); + __ asr(rscratch1, rscratch1, Interpreter::logStackElementSize); __ str(rscratch1, Address(rfp, frame::interpreter_frame_extended_sp_offset * wordSize)); __ ldr(c_rarg1, monitor_block_bot); // c_rarg1: old expression stack bottom diff --git a/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp b/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp index c581871fd8e..042b43bca7d 100644 --- a/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp @@ -151,11 +151,14 @@ inline void FreezeBase::relativize_interpreted_frame_metadata(const frame& f, co assert((intptr_t*)hf.at_relative(frame::interpreter_frame_last_sp_offset) == hf.unextended_sp(), ""); relativize_one(vfp, hfp, frame::interpreter_frame_initial_sp_offset); // == block_top == block_bottom - relativize_one(vfp, hfp, frame::interpreter_frame_extended_sp_offset); + + // extended_sp is already relativized by TemplateInterpreterGenerator::generate_normal_entry or + // AbstractInterpreter::layout_activation assert((hf.fp() - hf.unextended_sp()) == (f.fp() - f.unextended_sp()), ""); assert(hf.unextended_sp() == (intptr_t*)hf.at(frame::interpreter_frame_last_sp_offset), ""); assert(hf.unextended_sp() <= (intptr_t*)hf.at(frame::interpreter_frame_initial_sp_offset), ""); + assert(hf.unextended_sp() > (intptr_t*)hf.at(frame::interpreter_frame_extended_sp_offset), ""); assert(hf.fp() > (intptr_t*)hf.at(frame::interpreter_frame_initial_sp_offset), ""); #ifdef ASSERT if (f.interpreter_frame_method()->max_locals() > 0) { @@ -296,7 +299,9 @@ inline void ThawBase::derelativize_interpreted_frame_metadata(const frame& hf, c assert((intptr_t*)f.at_relative(frame::interpreter_frame_last_sp_offset) == f.unextended_sp(), ""); derelativize_one(vfp, frame::interpreter_frame_initial_sp_offset); - derelativize_one(vfp, frame::interpreter_frame_extended_sp_offset); + + // Make sure that extended_sp is kept relativized. + assert((intptr_t*)f.at_relative(frame::interpreter_frame_extended_sp_offset) < f.unextended_sp(), ""); } #endif // CPU_RISCV_CONTINUATIONFREEZETHAW_RISCV_INLINE_HPP diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp index e91b722bd02..a1738eb4517 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.cpp +++ b/src/hotspot/cpu/riscv/frame_riscv.cpp @@ -337,7 +337,9 @@ void frame::interpreter_frame_set_last_sp(intptr_t* last_sp) { } void frame::interpreter_frame_set_extended_sp(intptr_t* sp) { - *((intptr_t**)addr_at(interpreter_frame_extended_sp_offset)) = sp; + assert(is_interpreted_frame(), "interpreted frame expected"); + // set relativized extended_sp + ptr_at_put(interpreter_frame_extended_sp_offset, (sp - fp())); } frame frame::sender_for_entry_frame(RegisterMap* map) const { diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp index 9b004cb081b..8926d608bfb 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp @@ -85,6 +85,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void restore_sp_after_call() { Label L; ld(t0, Address(fp, frame::interpreter_frame_extended_sp_offset * wordSize)); + shadd(t0, t0, fp, t0, LogBytesPerWord); #ifdef ASSERT bnez(t0, L); stop("SP is null"); @@ -97,6 +98,7 @@ class InterpreterMacroAssembler: public MacroAssembler { #ifdef ASSERT Label L; ld(t0, Address(fp, frame::interpreter_frame_extended_sp_offset * wordSize)); + shadd(t0, t0, fp, t0, LogBytesPerWord); beq(sp, t0, L); stop(msg); bind(L); diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 1e4730e4275..f7c7fbfb07b 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -710,7 +710,9 @@ void TemplateInterpreterGenerator::lock_method() { __ check_extended_sp(); __ add(sp, sp, - entry_size); // add space for a monitor entry __ add(esp, esp, - entry_size); - __ sd(sp, Address(fp, frame::interpreter_frame_extended_sp_offset * wordSize)); + __ sub(t0, sp, fp); + __ srai(t0, t0, Interpreter::logStackElementSize); + __ sd(t0, Address(fp, frame::interpreter_frame_extended_sp_offset * wordSize)); __ sd(esp, monitor_block_top); // set new monitor block top // store object __ sd(x10, Address(esp, BasicObjectLock::obj_offset())); @@ -785,15 +787,19 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ slli(t0, t0, 3); __ sub(t0, sp, t0); __ andi(t0, t0, -16); + __ sub(t1, t0, fp); + __ srai(t1, t1, Interpreter::logStackElementSize); // Store extended SP - __ sd(t0, Address(sp, 5 * wordSize)); + __ sd(t1, Address(sp, 5 * wordSize)); // Move SP out of the way __ mv(sp, t0); } else { // Make sure there is room for the exception oop pushed in case method throws // an exception (see TemplateInterpreterGenerator::generate_throw_exception()) __ sub(t0, sp, 2 * wordSize); - __ sd(t0, Address(sp, 5 * wordSize)); + __ sub(t1, t0, fp); + __ srai(t1, t1, Interpreter::logStackElementSize); + __ sd(t1, Address(sp, 5 * wordSize)); __ mv(sp, t0); } } diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index c2ab9cc1d6d..c2c826b6c32 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -3844,7 +3844,9 @@ void TemplateTable::monitorenter() { __ check_extended_sp(); __ sub(sp, sp, entry_size); // make room for the monitor - __ sd(sp, Address(fp, frame::interpreter_frame_extended_sp_offset * wordSize)); + __ sub(t0, sp, fp); + __ srai(t0, t0, Interpreter::logStackElementSize); + __ sd(t0, Address(fp, frame::interpreter_frame_extended_sp_offset * wordSize)); __ ld(c_rarg1, monitor_block_bot); // c_rarg1: old expression stack bottom __ sub(esp, esp, entry_size); // move expression stack top From 42f5b9e7aacd69cad8b104ed49337cc64fc7ce7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Fri, 1 Sep 2023 10:19:53 +0000 Subject: [PATCH 37/86] 8315436: HttpsServer does not send TLS alerts Reviewed-by: dfuchs, michaelm --- .../sun/net/httpserver/SSLStreams.java | 3 +- .../simpleserver/HttpsServerAlertTest.java | 110 ++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/HttpsServerAlertTest.java diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java index 045d2251636..b740189b3e7 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -286,7 +286,6 @@ WrapperResult wrapAndSendX(ByteBuffer src, boolean ignoreClose) throws IOExcepti } while (status == Status.BUFFER_OVERFLOW); if (status == Status.CLOSED && !ignoreClose) { closed = true; - return r; } if (r.result.bytesProduced() > 0) { wrap_dst.flip(); diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/HttpsServerAlertTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/HttpsServerAlertTest.java new file mode 100644 index 00000000000..2ba54d61ada --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/HttpsServerAlertTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8315436 + * @summary Test if HttpsServer sends the TLS alerts produced + * @library /test/lib + * @build jdk.test.lib.net.SimpleSSLContext + * @run testng/othervm HttpsServerAlertTest + */ + +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; +import com.sun.net.httpserver.HttpsServer; +import jdk.test.lib.net.SimpleSSLContext; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import java.io.EOFException; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.testng.Assert.fail; + +public class HttpsServerAlertTest { + + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + static final boolean ENABLE_LOGGING = true; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + SSLContext sslContext; + + @BeforeTest + public void setup() throws IOException { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + sslContext = new SimpleSSLContext().get(); + SSLContext.setDefault(sslContext); + } + + @Test + public void testProtocolMismatch() throws Exception { + SSLSocketFactory sf = sslContext.getSocketFactory(); + var server = HttpsServer.create(LOOPBACK_ADDR, 0); + server.setHttpsConfigurator(new Configurator(sslContext)); + server.start(); + try (SSLSocket s = (SSLSocket) sf.createSocket()) { + // server only accepts TLS 1.3 + s.setEnabledProtocols(new String[]{"TLSv1.2"}); + s.connect(server.getAddress()); + s.startHandshake(); + fail("Expected a handshake failure"); + } catch (SSLHandshakeException e) { + System.out.println("Got exception: " + e); + if (e.getCause() instanceof EOFException || + !e.getMessage().contains("protocol_version")) + throw e; + } finally { + server.stop(0); + } + } + + private static class Configurator extends HttpsConfigurator { + public Configurator(SSLContext sslContext) { + super(sslContext); + } + + @Override + public void configure(HttpsParameters params) { + SSLParameters sslParams = getSSLContext().getDefaultSSLParameters(); + sslParams.setProtocols(new String[]{"TLSv1.3"}); + params.setSSLParameters(sslParams); + } + } +} From c32e340d94524de018c7c72e162ae3fee4953d06 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Fri, 1 Sep 2023 11:05:34 +0000 Subject: [PATCH 38/86] 8315321: [aix] os::attempt_reserve_memory_at must map at the requested address or fail Reviewed-by: mdoerr --- src/hotspot/os/aix/os_aix.cpp | 11 +++++++---- test/hotspot/gtest/runtime/test_os.cpp | 13 +++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index e0a403b26f8..641a1652bbd 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1590,10 +1590,13 @@ static char* reserve_shmated_memory (size_t bytes, char* requested_addr) { } // Now attach the shared segment. - // Note that I attach with SHM_RND - which means that the requested address is rounded down, if - // needed, to the next lowest segment boundary. Otherwise the attach would fail if the address - // were not a segment boundary. - char* const addr = (char*) shmat(shmid, requested_addr, SHM_RND); + // Note that we deliberately *don't* pass SHM_RND. The contract of os::attempt_reserve_memory_at() - + // which invokes this function with a request address != NULL - is to map at the specified address + // excactly, or to fail. If the caller passed us an address that is not usable (aka not a valid segment + // boundary), shmat should not round down the address, or think up a completely new one. + // (In places where this matters, e.g. when reserving the heap, we take care of passing segment-aligned + // addresses on Aix. See, e.g., ReservedHeapSpace. + char* const addr = (char*) shmat(shmid, requested_addr, 0); const int errno_shmat = errno; // (A) Right after shmat and before handing shmat errors delete the shm segment. diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 9956956423c..be6e22f5f4e 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -25,6 +25,7 @@ #include "memory/allocation.hpp" #include "memory/resourceArea.hpp" #include "runtime/frame.inline.hpp" +#include "runtime/globals.hpp" #include "runtime/os.inline.hpp" #include "runtime/thread.hpp" #include "runtime/threads.hpp" @@ -948,6 +949,18 @@ TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_largepages) { } } +#ifdef AIX +// On Aix, we should fail attach attempts not aligned to segment boundaries (256m) +TEST_VM(os, aix_reserve_at_non_shmlba_aligned_address) { + if (Use64KPages && Use64KPagesThreshold == 0) { + char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M); + ASSERT_EQ(p, nullptr); // should have failed + p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M); + ASSERT_EQ(p, nullptr); // should have failed + } +} +#endif // AIX + TEST_VM(os, vm_min_address) { size_t s = os::vm_min_address(); ASSERT_GE(s, M); From cf02cf31da88a5f2934e7195ae5f8a2670f659e3 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Fri, 1 Sep 2023 11:18:05 +0000 Subject: [PATCH 39/86] 8315098: Improve URLEncodeDecode microbenchmark Reviewed-by: ecaspole, dfuchs --- .../bench/java/net/URLEncodeDecode.java | 119 +++++++++++++----- 1 file changed, 91 insertions(+), 28 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/net/URLEncodeDecode.java b/test/micro/org/openjdk/bench/java/net/URLEncodeDecode.java index 1bd98f9ed52..a599a68f924 100644 --- a/test/micro/org/openjdk/bench/java/net/URLEncodeDecode.java +++ b/test/micro/org/openjdk/bench/java/net/URLEncodeDecode.java @@ -37,6 +37,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.Random; import java.util.concurrent.TimeUnit; @@ -51,78 +52,140 @@ @Fork(value = 3) public class URLEncodeDecode { - @Param("1024") - public int count; + private static final int COUNT = 1024; @Param("1024") public int maxLength; - @Param("3") - public long mySeed; + /** + * Percentage of strings that will remain unchanged by an encoding/decoding (0-100) + */ + @Param({"0", "75", "100"}) + public int unchanged; + + /** + * Percentage of chars in changed strings that cause encoding/decoding to happen (0-100) + */ + @Param({"6"}) + public int encodeChars; public String[] testStringsEncode; public String[] testStringsDecode; public String[] toStrings; - @Setup + @Setup() public void setupStrings() { - char[] tokens = new char[((int) 'Z' - (int) 'A' + 1) + ((int) 'z' - (int) 'a' + 1) + ((int) '9' - (int) '1' + 1) + 5]; + char[] encodeTokens = new char[] { '[', '(', ' ', '\u00E4', '\u00E5', '\u00F6', ')', '='}; + char[] tokens = new char[('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1) + 4]; int n = 0; - tokens[n++] = '0'; - for (int i = (int) '1'; i <= (int) '9'; i++) { - tokens[n++] = (char) i; + for (char c = '0'; c <= '9'; c++) { + tokens[n++] = c; } - for (int i = (int) 'A'; i <= (int) 'Z'; i++) { - tokens[n++] = (char) i; + for (char c = 'A'; c <= 'Z'; c++) { + tokens[n++] = c; } - for (int i = (int) 'a'; i <= (int) '<'; i++) { - tokens[n++] = (char) i; + for (char c = 'a'; c <= 'z'; c++) { + tokens[n++] = c; } tokens[n++] = '-'; tokens[n++] = '_'; tokens[n++] = '.'; - tokens[n++] = '*'; + tokens[n] = '*'; - Random r = new Random(mySeed); - testStringsEncode = new String[count]; - testStringsDecode = new String[count]; - toStrings = new String[count]; - for (int i = 0; i < count; i++) { + Random r = new Random(3); + testStringsEncode = new String[COUNT]; + testStringsDecode = new String[COUNT]; + toStrings = new String[COUNT]; + for (int i = 0; i < COUNT; i++) { int l = r.nextInt(maxLength); + boolean needEncoding = r.nextInt(100) >= unchanged; StringBuilder sb = new StringBuilder(); + boolean hasEncoded = false; for (int j = 0; j < l; j++) { - int c = r.nextInt(tokens.length); - sb.append(tokens[c]); + if (needEncoding && r.nextInt(100) < encodeChars) { + addToken(encodeTokens, r, sb); + hasEncoded = true; + } else { + addToken(tokens, r, sb); + } + } + if (needEncoding && !hasEncoded) { + addToken(encodeTokens, r, sb); } testStringsEncode[i] = sb.toString(); } + int countUnchanged = 0; + for (String s : testStringsEncode) { + if (s.equals(java.net.URLEncoder.encode(s, StandardCharsets.UTF_8))) { + countUnchanged++; + } else { + if (unchanged == 100) { + System.out.println("Unexpectedly needs encoding action: "); + System.out.println("\t" + s); + System.out.println("\t" + java.net.URLEncoder.encode(s, StandardCharsets.UTF_8)); + } + } + } + System.out.println(); + System.out.println("Generated " + testStringsEncode.length + " encodable strings, " + countUnchanged + " of which does not need encoding action"); - for (int i = 0; i < count; i++) { + for (int i = 0; i < COUNT; i++) { int l = r.nextInt(maxLength); + boolean needDecoding = r.nextInt(100) >= unchanged; StringBuilder sb = new StringBuilder(); + boolean hasDecoded = false; for (int j = 0; j < l; j++) { - int c = r.nextInt(tokens.length + 5); - if (c >= tokens.length) { - sb.append("%").append(tokens[r.nextInt(16)]).append(tokens[r.nextInt(16)]); + if (needDecoding && r.nextInt(100) < encodeChars) { + addDecodableChar(tokens, r, sb); + hasDecoded = true; } else { - sb.append(tokens[c]); + addToken(tokens, r, sb); } } + if (needDecoding && !hasDecoded) { + addDecodableChar(tokens, r, sb); + } testStringsDecode[i] = sb.toString(); } + countUnchanged = 0; + for (String s : testStringsDecode) { + if (s.equals(java.net.URLDecoder.decode(s, StandardCharsets.UTF_8))) { + countUnchanged++; + } else { + if (unchanged == 100) { + System.out.println("Unexpectedly needs encoding action: "); + System.out.println("\t" + s); + System.out.println("\t" + java.net.URLDecoder.decode(s, StandardCharsets.UTF_8)); + } + } + } + System.out.println("Generated " + testStringsDecode.length + " decodable strings, " + countUnchanged + " of which does not need decoding action"); + } + + private static void addToken(char[] tokens, Random r, StringBuilder sb) { + int c = r.nextInt(tokens.length); + sb.append(tokens[c]); + } + + private static void addDecodableChar(char[] tokens, Random r, StringBuilder sb) { + if (r.nextInt(100) < 15) { + sb.append('+'); // exercise '+' -> ' ' decoding paths. + } else { + sb.append("%").append(tokens[r.nextInt(16)]).append(tokens[r.nextInt(16)]); + } } @Benchmark public void testEncodeUTF8(Blackhole bh) throws UnsupportedEncodingException { for (String s : testStringsEncode) { - bh.consume(java.net.URLEncoder.encode(s, "UTF-8")); + bh.consume(java.net.URLEncoder.encode(s, StandardCharsets.UTF_8)); } } @Benchmark public void testDecodeUTF8(Blackhole bh) throws UnsupportedEncodingException { for (String s : testStringsDecode) { - bh.consume(URLDecoder.decode(s, "UTF-8")); + bh.consume(URLDecoder.decode(s, StandardCharsets.UTF_8)); } } From b4f7069c5b60335fb51d7a3f15c61edce7f158d1 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 1 Sep 2023 13:46:41 +0000 Subject: [PATCH 40/86] 8315446: G1: Remove unused G1AllocRegion::attempt_allocation Reviewed-by: iwalulya, tschatzl --- src/hotspot/share/gc/g1/g1AllocRegion.hpp | 4 ---- src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp | 5 ----- 2 files changed, 9 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.hpp index 83accb1ba38..600d1551259 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.hpp @@ -151,10 +151,6 @@ class G1AllocRegion : public CHeapObj { // The following two are the building blocks for the allocation method. - // First-level allocation: Should be called without holding a - // lock. It will try to allocate lock-free out of the active region, - // or return null if it was unable to. - inline HeapWord* attempt_allocation(size_t word_size); // Perform an allocation out of the current allocation region, with the given // minimum and desired size. Returns the actual size allocated (between // minimum and desired size) in actual_word_size if the allocation has been diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp index 4ab202bf285..33c402b0087 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp @@ -63,11 +63,6 @@ inline HeapWord* G1AllocRegion::par_allocate(HeapRegion* alloc_region, return alloc_region->par_allocate(min_word_size, desired_word_size, actual_word_size); } -inline HeapWord* G1AllocRegion::attempt_allocation(size_t word_size) { - size_t temp; - return attempt_allocation(word_size, word_size, &temp); -} - inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { From 0d4cadb82468655f4ad3887a14d47e59af620490 Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Fri, 1 Sep 2023 14:40:29 +0000 Subject: [PATCH 41/86] 8315195: RISC-V: Update hwprobe query for new extensions Reviewed-by: fyang, fjiang, luhenry --- src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp | 16 ++++++++++++++++ .../linux_riscv/vm_version_linux_riscv.cpp | 10 +--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index f8e42a13207..243c4b850ee 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -45,6 +45,10 @@ #define RISCV_HWPROBE_KEY_IMA_EXT_0 4 #define RISCV_HWPROBE_IMA_FD (1 << 0) #define RISCV_HWPROBE_IMA_C (1 << 1) +#define RISCV_HWPROBE_IMA_V (1 << 2) +#define RISCV_HWPROBE_EXT_ZBA (1 << 3) +#define RISCV_HWPROBE_EXT_ZBB (1 << 4) +#define RISCV_HWPROBE_EXT_ZBS (1 << 5) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) @@ -129,6 +133,18 @@ void RiscvHwprobe::add_features_from_query_result() { if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_C)) { VM_Version::ext_C.enable_feature(); } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_IMA_V)) { + VM_Version::ext_V.enable_feature(); + } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBA)) { + VM_Version::ext_Zba.enable_feature(); + } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBB)) { + VM_Version::ext_Zbb.enable_feature(); + } + if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZBS)) { + VM_Version::ext_Zbs.enable_feature(); + } if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) { VM_Version::unaligned_access.enable_feature( query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK); diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index 54c8ae13bfa..c3544a4d9fc 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -224,19 +224,11 @@ void VM_Version::vendor_features() { void VM_Version::rivos_features() { // Enable common features not dependent on marchid/mimpid. - ext_I.enable_feature(); - ext_M.enable_feature(); - ext_A.enable_feature(); - ext_F.enable_feature(); - ext_D.enable_feature(); - ext_C.enable_feature(); - ext_H.enable_feature(); - ext_V.enable_feature(); - ext_Zicbom.enable_feature(); ext_Zicboz.enable_feature(); ext_Zicbop.enable_feature(); + // If we running on a pre-6.5 kernel ext_Zba.enable_feature(); ext_Zbb.enable_feature(); ext_Zbs.enable_feature(); From 56b8db11c35c0ef04fdc7e3bdcb0f360ae2b2e4b Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 1 Sep 2023 15:26:25 +0000 Subject: [PATCH 42/86] 8258970: Disabled JPasswordField foreground color is wrong with GTK LAF Reviewed-by: tr, dnguyen, psadhukhan --- .../native/libawt_xawt/awt/gtk3_interface.c | 9 +- ...tDisabledPasswordFieldForegroundColor.java | 180 ++++++++++++++++++ 2 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/swing/JPasswordField/TestDisabledPasswordFieldForegroundColor.java diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c index 4c690db2e67..900f2ccd3ee 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c @@ -2401,9 +2401,12 @@ static gint gtk3_get_color_for_state(JNIEnv *env, WidgetType widget_type, init_containers(); if (gtk3_version_3_20) { - if ((widget_type == TEXT_FIELD || widget_type == PASSWORD_FIELD || widget_type == SPINNER_TEXT_FIELD || - widget_type == FORMATTED_TEXT_FIELD) && state_type == GTK_STATE_SELECTED && color_type == TEXT_BACKGROUND) { - widget_type = TEXT_AREA; + if (widget_type == TEXT_FIELD || widget_type == PASSWORD_FIELD + || widget_type == SPINNER_TEXT_FIELD || widget_type == FORMATTED_TEXT_FIELD) { + if ((state_type == GTK_STATE_SELECTED && color_type == TEXT_BACKGROUND) + || (state_type == GTK_STATE_INSENSITIVE && color_type == TEXT_FOREGROUND)) { + widget_type = TEXT_AREA; + } } else if (widget_type == MENU_BAR && state_type == GTK_STATE_INSENSITIVE && color_type == FOREGROUND) { widget_type = MENU; diff --git a/test/jdk/javax/swing/JPasswordField/TestDisabledPasswordFieldForegroundColor.java b/test/jdk/javax/swing/JPasswordField/TestDisabledPasswordFieldForegroundColor.java new file mode 100644 index 00000000000..199bfb4dc7d --- /dev/null +++ b/test/jdk/javax/swing/JPasswordField/TestDisabledPasswordFieldForegroundColor.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8258970 + * @key headful + * @requires (os.family == "linux") + * @summary Verifies if disabled password field foreground color grayed out + * @run main TestDisabledPasswordFieldForegroundColor + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JFormattedTextField; +import javax.swing.JPasswordField; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import java.lang.Math; + +public class TestDisabledPasswordFieldForegroundColor { + + private static JFrame frame; + private static JPasswordField passwordField; + private static JTextField textField; + private static JFormattedTextField formattedTextField; + private static JSpinner spinner; + private static Robot robot; + private static BufferedImage enabledImg; + private static BufferedImage disabledImg; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + boolean testFail = false; + robot = new Robot(); + robot.setAutoDelay(100); + try { + SwingUtilities.invokeAndWait( + TestDisabledPasswordFieldForegroundColor::createAndShowUI); + + robot.waitForIdle(); + robot.delay(1000); + + if (!testComponent(passwordField, 20, 10)) { + System.out.println("Disabled JPasswordField foreground color not grayed out"); + ImageIO.write(enabledImg, "png", new File("JPasswordFieldEnabledImg.png")); + ImageIO.write(disabledImg, "png", new File("JPasswordFieldDisabledImg.png")); + testFail = true; + } + + if (!testComponent(textField, 20, 10)) { + System.out.println("Disabled JTextField foreground color not grayed out"); + ImageIO.write(enabledImg, "png", new File("JTextFieldEnabledImg.png")); + ImageIO.write(disabledImg, "png", new File("JTextFieldDisabledImg.png")); + testFail = true; + } + + if (!testComponent(formattedTextField, 20, 10)) { + System.out.println("Disabled JFormattedTextField foreground color not grayed out"); + ImageIO.write(enabledImg, "png", new File("JFormattedTextFieldEnabledImg.png")); + ImageIO.write(disabledImg, "png", new File("JFormattedTextFieldDisabledImg.png")); + testFail = true; + } + + if (!testComponent(spinner, 10, 5)) { + System.out.println("Disabled JSpinner foreground color not grayed out"); + ImageIO.write(enabledImg, "png", new File("JSpinnerTextFieldEnabledImg.png")); + ImageIO.write(disabledImg, "png", new File("JSpinnerTextFieldDisabledImg.png")); + testFail = true; + } + + if (testFail) { + throw new RuntimeException("Disabled Component foreground color not grayed out"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new JFrame("Test Disabled Component Foreground Color"); + frame.getContentPane().setLayout(new FlowLayout(FlowLayout.CENTER,5,5)); + passwordField = new JPasswordField("passwordpassword"); + passwordField.setEnabled(true); + textField = new JTextField("TextField"); + textField.setEnabled(true); + formattedTextField = new JFormattedTextField("FormattedTextField"); + formattedTextField.setEnabled(true); + SpinnerNumberModel model = new SpinnerNumberModel(5, 0, 10, 1); + spinner = new JSpinner(model); + spinner.setEnabled(true); + + frame.getContentPane().add(passwordField); + frame.getContentPane().add(textField); + frame.getContentPane().add(formattedTextField); + frame.getContentPane().add(spinner); + frame.pack(); + frame.setSize(500, 150); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + } + + private static boolean testComponent(JComponent c, int xOffset, int yOffset) + throws Exception { + Point pt = c.getLocationOnScreen(); + enabledImg = robot.createScreenCapture(new Rectangle(pt.x, pt.y, + c.getWidth(), c.getHeight())); + c.setEnabled(false); + robot.waitForIdle(); + robot.delay(500); + disabledImg = robot.createScreenCapture(new Rectangle(pt.x, pt.y, + c.getWidth(), c.getHeight())); + return compareImage(enabledImg, disabledImg, xOffset, yOffset); + } + + /* + * Compare enabled and disabled state image and if both images + * width and height are equal but pixel's RGB values are not equal, + * method returns true; false otherwise. + */ + + private static boolean compareImage(BufferedImage img1, BufferedImage img2, + int xOffset, int yOffset) { + int tolerance = 5; + if (img1.getWidth() == img2.getWidth() + && img1.getHeight() == img2.getHeight()) { + for (int x = xOffset; x < img1.getWidth() / 2; ++x) { + for (int y = yOffset; y < img1.getHeight() - 5; ++y) { + Color c1 = new Color(img1.getRGB(x, y)); + Color c2 = new Color(img2.getRGB(x, y)); + + if (Math.abs(c1.getRed() - c2.getRed()) > tolerance || + Math.abs(c1.getGreen() - c2.getGreen()) > tolerance || + Math.abs(c1.getBlue() - c2.getBlue()) > tolerance) { + return true; + } + } + } + return false; + } else { + return false; + } + } +} From e9e0c5699b8d0fbd1bd3a6caa3e0182a2e5bdda3 Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Fri, 1 Sep 2023 16:54:55 +0000 Subject: [PATCH 43/86] 8314319: LogCompilation doesn't reset lateInlining when it encounters a failure. Reviewed-by: ecaspole, kvn --- .../sun/hotspot/tools/compiler/LogParser.java | 1 + .../tools/compiler/TestPrebuiltLogs.java | 87 +++ .../src/test/resources/8314319.xml | 526 ++++++++++++++++++ 3 files changed, 614 insertions(+) create mode 100644 src/utils/LogCompilation/src/test/java/com/sun/hotspot/tools/compiler/TestPrebuiltLogs.java create mode 100644 src/utils/LogCompilation/src/test/resources/8314319.xml diff --git a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java index 09a852d05c7..e1e305abe10 100644 --- a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java +++ b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java @@ -1082,6 +1082,7 @@ public void startElement(String uri, String localName, String qname, Attributes site.setReason("succeed: " + search(atts, "reason")); } else if (qname.equals("failure")) { failureReason = search(atts, "reason"); + lateInlining = false; } else if (qname.equals("task_done")) { compile.setEnd(Double.parseDouble(search(atts, "stamp"))); if (Integer.parseInt(search(atts, "success")) == 0) { diff --git a/src/utils/LogCompilation/src/test/java/com/sun/hotspot/tools/compiler/TestPrebuiltLogs.java b/src/utils/LogCompilation/src/test/java/com/sun/hotspot/tools/compiler/TestPrebuiltLogs.java new file mode 100644 index 00000000000..b7c587b98f9 --- /dev/null +++ b/src/utils/LogCompilation/src/test/java/com/sun/hotspot/tools/compiler/TestPrebuiltLogs.java @@ -0,0 +1,87 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +package com.sun.hotspot.tools.compiler; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@RunWith(value = Parameterized.class) +public class TestPrebuiltLogs { + private String logFile; + static List tests = new ArrayList(); + + // BeforeClass is invoked after @Parameters, so we use static block to evaluate tests first. + static { + File file = new File("src/test/resources"); + File[] testData = file.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".xml"); + } + }); + + for (File f: testData) { + tests.add(f.toString()); + } + } + + @Parameters + public static Collection data() { + return tests; + } + + public TestPrebuiltLogs(String logFile) { + this.logFile = logFile; + } + + void doItOrFail(String[] args) { + try { + LogCompilation.main(args); + } catch (Throwable e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + @Test + public void testDashi() throws Exception { + String[] args = {"-i", logFile}; + doItOrFail(args); + } + + @Test + public void testNone() throws Exception { + String[] args = {logFile}; + doItOrFail(args); + } +} diff --git a/src/utils/LogCompilation/src/test/resources/8314319.xml b/src/utils/LogCompilation/src/test/resources/8314319.xml new file mode 100644 index 00000000000..789025c790e --- /dev/null +++ b/src/utils/LogCompilation/src/test/resources/8314319.xml @@ -0,0 +1,526 @@ + + + + +OpenJDK 64-Bit Server VM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2f7c65ec48dc35d75eed8af411d482ba40de70dc Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 1 Sep 2023 17:12:56 +0000 Subject: [PATCH 44/86] 8303427: Fixpath confused if unix root contains "/jdk" Reviewed-by: mikael --- make/scripts/fixpath.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/make/scripts/fixpath.sh b/make/scripts/fixpath.sh index 255b41a8680..9c8db7383f2 100644 --- a/make/scripts/fixpath.sh +++ b/make/scripts/fixpath.sh @@ -326,7 +326,9 @@ function convert_path() { suffix="${BASH_REMATCH[6]}" # We only believe this is a path if the first part is an existing directory - if [[ -d "/$firstdir" ]]; then + # and the prefix is not a subdirectory in the current working directory. Remove + # any part leading up to a : or = in the prefix before checking. + if [[ -d "/$firstdir" && ! -d "${prefix##*:}" && ! -d "${prefix##*=}" ]]; then if [[ $ENVROOT == "" ]]; then if [[ $QUIET != true ]]; then echo fixpath: failure: Path "'"$pathmatch"'" cannot be converted to Windows path >&2 From 2a11bc41baec20cf670393ff29689043ed2d2114 Mon Sep 17 00:00:00 2001 From: Yi-Fan Tsai Date: Fri, 1 Sep 2023 20:41:45 +0000 Subject: [PATCH 45/86] 8314837: 5 compiled/codecache tests ignore VM flags Reviewed-by: kvn, lmesnik --- .../jtreg/compiler/codecache/CheckCodeCacheInfo.java | 10 ++++------ .../compiler/codecache/CodeCacheFullCountTest.java | 3 ++- .../codecache/cli/TestSegmentedCodeCacheOption.java | 1 + .../cli/codeheapsize/TestCodeHeapSizeOptions.java | 1 + .../cli/printcodecache/TestPrintCodeCacheOption.java | 1 + 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/compiler/codecache/CheckCodeCacheInfo.java b/test/hotspot/jtreg/compiler/codecache/CheckCodeCacheInfo.java index 9b2c9b316ac..53d555ee139 100644 --- a/test/hotspot/jtreg/compiler/codecache/CheckCodeCacheInfo.java +++ b/test/hotspot/jtreg/compiler/codecache/CheckCodeCacheInfo.java @@ -28,9 +28,7 @@ * @library /test/lib * @requires vm.debug * - * @run driver jdk.test.lib.helpers.ClassFileInstaller - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * compiler.codecache.CheckCodeCacheInfo + * @run driver compiler.codecache.CheckCodeCacheInfo */ package compiler.codecache; @@ -68,9 +66,9 @@ public class CheckCodeCacheInfo { public static void main(String[] args) throws Exception { ProcessBuilder pb; - pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintCodeCache", - "-XX:+Verbose", - "-version"); + pb = ProcessTools.createTestJvm("-XX:+PrintCodeCache", + "-XX:+Verbose", + "-version"); OutputAnalyzer out = new OutputAnalyzer(pb.start()); out.shouldHaveExitValue(0); out.stdoutShouldMatch(VERBOSE_REGEXP); diff --git a/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java index 9b1a5e89071..ee6866c396d 100644 --- a/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java +++ b/test/hotspot/jtreg/compiler/codecache/CodeCacheFullCountTest.java @@ -33,6 +33,7 @@ * @test * @bug 8276036 8277213 8277441 * @summary test for the value of full_count in the message of insufficient codecache + * @requires vm.compMode != "Xint" * @library /test/lib */ public class CodeCacheFullCountTest { @@ -54,7 +55,7 @@ public static void wasteCodeCache() throws Exception { } public static void runTest() throws Throwable { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + ProcessBuilder pb = ProcessTools.createTestJvm( "-XX:ReservedCodeCacheSize=2496k", "-XX:-UseCodeCacheFlushing", "-XX:-MethodFlushing", "CodeCacheFullCountTest", "WasteCodeCache"); OutputAnalyzer oa = ProcessTools.executeProcess(pb); // Ignore adapter creation failures diff --git a/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java b/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java index 2a810abdd48..a5068b47454 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/TestSegmentedCodeCacheOption.java @@ -25,6 +25,7 @@ * @test * @bug 8015774 * @summary Verify SegmentedCodeCache option's processing + * @requires vm.flagless * @library /test/lib / * @modules java.base/jdk.internal.misc * java.compiler diff --git a/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java b/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java index 7ae62407ece..4d52f470645 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java @@ -26,6 +26,7 @@ * @key randomness * @bug 8015774 * @summary Verify processing of options related to code heaps sizing. + * @requires vm.flagless * @library /test/lib / * @modules java.base/jdk.internal.misc * java.compiler diff --git a/test/hotspot/jtreg/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java b/test/hotspot/jtreg/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java index 223d683fc24..c0d826e59ec 100644 --- a/test/hotspot/jtreg/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java +++ b/test/hotspot/jtreg/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java @@ -25,6 +25,7 @@ * @test * @bug 8015774 * @summary Verify that PrintCodeCache option print correct information. + * @requires vm.flagless * @library /test/lib / * @modules java.base/jdk.internal.misc * java.compiler From 4f90abaf17716493bad740dcef76d49f16d69379 Mon Sep 17 00:00:00 2001 From: Rajat Mahajan Date: Fri, 1 Sep 2023 21:49:49 +0000 Subject: [PATCH 46/86] 8311585: Add JRadioButtonMenuItem to bug8031573.java Reviewed-by: honkar, aivanov --- .../swing/JMenuItem/8031573/bug8031573.java | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/test/jdk/javax/swing/JMenuItem/8031573/bug8031573.java b/test/jdk/javax/swing/JMenuItem/8031573/bug8031573.java index 4d3f1cd6113..567989e0341 100644 --- a/test/jdk/javax/swing/JMenuItem/8031573/bug8031573.java +++ b/test/jdk/javax/swing/JMenuItem/8031573/bug8031573.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,18 +32,18 @@ import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; -import javax.swing.JMenuItem; import javax.swing.JPanel; +import javax.swing.JRadioButtonMenuItem; import javax.swing.JTextArea; -import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.text.JTextComponent; /* @test - * @bug 8031573 8040279 8143064 - * @summary [macosx] Checkmarks of JCheckBoxMenuItems aren't rendered + * @bug 8031573 8040279 8143064 8294427 + * @summary Checkmarks of JCheckBoxMenuItems aren't rendered * in high resolution on Retina + * @requires (os.family != "linux") * @run main/manual bug8031573 */ @@ -54,14 +54,21 @@ public class bug8031573 { private static final CountDownLatch latch = new CountDownLatch(1); public static final String INSTRUCTIONS = "INSTRUCTIONS:\n\n" - + "Verify that high resolution system icons are used for JCheckBoxMenuItem on HiDPI displays.\n" - + "If the display does not support HiDPI mode press PASS.\n" - + "1. Run the test on HiDPI Display.\n" - + "2. Open the Menu.\n" - + "3. Check that the icon on the JCheckBoxMenuItem is smooth.\n" - + " If so, press PASS, else press FAIL.\n"; + + "Verify that the check and radio-check icons are rendered smoothly\n" + + "for both JCheckBoxMenuItem and JRadioButtonMenuItem.\n" + + "1. Open the Menu.\n" + + "2. Check that the icon on the JCheckBoxMenuItem is smooth.\n" + + "3. Check that the icon on the JRadioButtonMenuItem is smooth.\n" + + "4. If you're on Windows:\n" + + " Test the markers are still crisp after changing the scale in Windows settings.\n" + + " This could be done on same monitor by changing its scale or\n" + + " by moving the window to a secondary monitor with a different scale.\n" + + " Then go to step 6.\n" + + "5. If you're on Mac OS:\n" + + " If you tested on a Retina display, go to step 6.\n" + + "6. If both icons render smoothly, press PASS, otherwise press FAIL.\n"; - public static void main(String args[]) throws Exception { + public static void main(String[] args) throws Exception { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); try { SwingUtilities.invokeAndWait(() -> createTestGUI()); @@ -88,6 +95,9 @@ private static void createTestGUI() { JCheckBoxMenuItem checkBoxMenuItem = new JCheckBoxMenuItem("JCheckBoxMenuItem"); checkBoxMenuItem.setSelected(true); menu.add(checkBoxMenuItem); + JRadioButtonMenuItem radioButtonMenuItem = new JRadioButtonMenuItem("JRadioButtonMenuItem"); + radioButtonMenuItem.setSelected(true); + menu.add(radioButtonMenuItem); bar.add(menu); frame.setJMenuBar(bar); From 75d4ac2659fb8748777458ceeea3d2e7087be40c Mon Sep 17 00:00:00 2001 From: Yi Yang Date: Mon, 4 Sep 2023 01:56:13 +0000 Subject: [PATCH 47/86] 8311775: [TEST] duplicate verifyHeapDump in several tests Reviewed-by: kevinw, amenkov, cjplummer --- .../dcmd/gc/HeapDumpAllTest.java | 6 +-- .../dcmd/gc/HeapDumpCompressedTest.java | 26 +---------- .../dcmd/gc/HeapDumpParallelTest.java | 23 +--------- .../serviceability/dcmd/gc/HeapDumpTest.java | 30 +++---------- .../sa/TestHeapDumpForInvokeDynamic.java | 36 ++------------- test/jdk/sun/tools/jmap/BasicJMapTest.java | 27 +----------- test/lib/jdk/test/lib/hprof/HprofParser.java | 44 ++++++++++++++----- 7 files changed, 49 insertions(+), 143 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpAllTest.java b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpAllTest.java index bc8bc1f1f7d..bcf301458c2 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpAllTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpAllTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,8 +21,6 @@ * questions. */ -import java.io.IOException; - import jdk.test.lib.dcmd.CommandExecutor; /* @@ -42,7 +40,7 @@ public HeapDumpAllTest() { } @Override - public void run(CommandExecutor executor, boolean overwrite) throws IOException { + public void run(CommandExecutor executor, boolean overwrite) throws Exception { // Trigger gc by hand, so the created heap dump isnt't too large and // takes too long to parse. System.gc(); diff --git a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpCompressedTest.java b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpCompressedTest.java index 7cef89f8c16..1e6d99a5048 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpCompressedTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpCompressedTest.java @@ -143,31 +143,7 @@ public static void main(String[] args) throws Exception { output = executor.execute("GC.heap_dump -gz=1 " + dump.getAbsolutePath()); output.shouldContain("Unable to create "); - verifyHeapDump(dump); + HprofParser.parseAndVerify(dump); dump.delete(); } - - private static void verifyHeapDump(File dump) throws Exception { - - Asserts.assertTrue(dump.exists() && dump.isFile(), - "Could not create dump file " + dump.getAbsolutePath()); - - try { - File out = HprofParser.parse(dump); - - Asserts.assertTrue(out != null && out.exists() && out.isFile(), - "Could not find hprof parser output file"); - List lines = Files.readAllLines(out.toPath()); - Asserts.assertTrue(lines.size() > 0, "hprof parser output file is empty"); - for (String line : lines) { - Asserts.assertFalse(line.matches(".*WARNING(?!.*Failed to resolve " + - "object.*constantPoolOop.*).*")); - } - - out.delete(); - } catch (Exception e) { - e.printStackTrace(); - Asserts.fail("Could not parse dump file " + dump.getAbsolutePath()); - } - } } diff --git a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java index 0dfdf54152d..c07e1161592 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java @@ -47,7 +47,7 @@ public class HeapDumpParallelTest { - private static void checkAndVerify(OutputAnalyzer dcmdOut, LingeredApp app, File heapDumpFile, boolean expectSerial) throws IOException { + private static void checkAndVerify(OutputAnalyzer dcmdOut, LingeredApp app, File heapDumpFile, boolean expectSerial) throws Exception { dcmdOut.shouldHaveExitValue(0); dcmdOut.shouldContain("Heap dump file created"); OutputAnalyzer appOut = new OutputAnalyzer(app.getProcessStdout()); @@ -64,7 +64,7 @@ private static void checkAndVerify(OutputAnalyzer dcmdOut, LingeredApp app, File appOut.shouldNotContain("Dump heap objects in parallel"); appOut.shouldNotContain("Merge heap files complete"); } - verifyHeapDump(heapDumpFile); + HprofParser.parseAndVerify(heapDumpFile); if (heapDumpFile.exists()) { heapDumpFile.delete(); } @@ -125,23 +125,4 @@ private static OutputAnalyzer attachJcmdHeapDump(File heapDumpFile, long lingere PidJcmdExecutor executor = new PidJcmdExecutor("" + lingeredAppPid); return executor.execute("GC.heap_dump " + arg + " " + heapDumpFile.getAbsolutePath()); } - - private static void verifyHeapDump(File dump) { - Asserts.assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath()); - try { - File out = HprofParser.parse(dump); - - Asserts.assertTrue(out != null && out.exists() && out.isFile(), "Could not find hprof parser output file"); - List lines = Files.readAllLines(out.toPath()); - Asserts.assertTrue(lines.size() > 0, "hprof parser output file is empty"); - for (String line : lines) { - Asserts.assertFalse(line.matches(".*WARNING(?!.*Failed to resolve object.*constantPoolOop.*).*")); - } - - out.delete(); - } catch (Exception e) { - e.printStackTrace(); - Asserts.fail("Could not parse dump file " + dump.getAbsolutePath()); - } - } } \ No newline at end of file diff --git a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpTest.java b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpTest.java index c01bfa5df98..5635e04f489 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ import java.io.File; import java.nio.file.Files; -import java.io.IOException; import java.util.List; import jdk.test.lib.hprof.HprofParser; @@ -50,7 +49,7 @@ public class HeapDumpTest { protected String heapDumpArgs = ""; - public void run(CommandExecutor executor, boolean overwrite) throws IOException { + public void run(CommandExecutor executor, boolean overwrite) throws Exception { File dump = new File("jcmd.gc.heap_dump." + System.currentTimeMillis() + ".hprof"); if (!overwrite && dump.exists()) { dump.delete(); @@ -61,37 +60,18 @@ public void run(CommandExecutor executor, boolean overwrite) throws IOException String cmd = "GC.heap_dump " + (overwrite ? "-overwrite " : "") + heapDumpArgs + " " + dump.getAbsolutePath(); executor.execute(cmd); - verifyHeapDump(dump); + HprofParser.parseAndVerify(dump); dump.delete(); } - private void verifyHeapDump(File dump) { - Assert.assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath()); - try { - File out = HprofParser.parse(dump); - - Assert.assertTrue(out != null && out.exists() && out.isFile(), "Could not find hprof parser output file"); - List lines = Files.readAllLines(out.toPath()); - Assert.assertTrue(lines.size() > 0, "hprof parser output file is empty"); - for (String line : lines) { - Assert.assertFalse(line.matches(".*WARNING(?!.*Failed to resolve object.*constantPoolOop.*).*")); - } - - out.delete(); - } catch (Exception e) { - e.printStackTrace(); - Assert.fail("Could not parse dump file " + dump.getAbsolutePath()); - } - } - /* GC.heap_dump is not available over JMX, running jcmd pid executor instead */ @Test - public void pid() throws IOException { + public void pid() throws Exception { run(new PidJcmdExecutor(), false); } @Test - public void pidRewrite() throws IOException { + public void pidRewrite() throws Exception { run(new PidJcmdExecutor(), true); } } diff --git a/test/hotspot/jtreg/serviceability/sa/TestHeapDumpForInvokeDynamic.java b/test/hotspot/jtreg/serviceability/sa/TestHeapDumpForInvokeDynamic.java index a4c3d15750a..8022d9a0090 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestHeapDumpForInvokeDynamic.java +++ b/test/hotspot/jtreg/serviceability/sa/TestHeapDumpForInvokeDynamic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,11 +22,7 @@ */ import java.io.File; -import java.io.IOException; -import java.io.BufferedInputStream; import java.util.stream.Collectors; -import java.io.FileInputStream; - import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.Asserts; @@ -35,9 +31,7 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.SA.SATestUtils; import jdk.test.lib.Utils; -import jdk.test.lib.hprof.parser.HprofReader; -import jdk.test.lib.hprof.parser.PositionDataInputStream; -import jdk.test.lib.hprof.model.Snapshot; +import jdk.test.lib.hprof.HprofParser; /** * @test @@ -55,30 +49,6 @@ public class TestHeapDumpForInvokeDynamic { private static LingeredAppWithInvokeDynamic theApp = null; - private static void verifyHeapDump(String heapFile) { - - File heapDumpFile = new File(heapFile); - Asserts.assertTrue(heapDumpFile.exists() && heapDumpFile.isFile(), - "Could not create dump file " + heapDumpFile.getAbsolutePath()); - try (PositionDataInputStream in = new PositionDataInputStream( - new BufferedInputStream(new FileInputStream(heapFile)))) { - int i = in.readInt(); - if (HprofReader.verifyMagicNumber(i)) { - Snapshot sshot; - HprofReader r = new HprofReader(heapFile, in, 0, - false, 0); - sshot = r.read(); - } else { - throw new IOException("Unrecognized magic number: " + i); - } - } catch (Exception e) { - e.printStackTrace(); - Asserts.fail("Could not read dump file " + heapFile); - } finally { - heapDumpFile.delete(); - } - } - private static void attachDumpAndVerify(String heapDumpFileName, long lingeredAppPid) throws Exception { @@ -101,7 +71,7 @@ private static void attachDumpAndVerify(String heapDumpFileName, SAOutput.shouldContain(heapDumpFileName); System.out.println(SAOutput.getOutput()); - verifyHeapDump(heapDumpFileName); + HprofParser.parseAndVerify(new File(heapDumpFileName)); } public static void main (String... args) throws Exception { diff --git a/test/jdk/sun/tools/jmap/BasicJMapTest.java b/test/jdk/sun/tools/jmap/BasicJMapTest.java index 393a02692fe..d8a24ef05fa 100644 --- a/test/jdk/sun/tools/jmap/BasicJMapTest.java +++ b/test/jdk/sun/tools/jmap/BasicJMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,7 @@ import static jdk.test.lib.Asserts.fail; import java.io.File; -import java.nio.file.Files; import java.util.Arrays; -import java.util.List; import jdk.test.lib.JDKToolLauncher; import jdk.test.lib.Utils; @@ -297,32 +295,11 @@ private static void dump(boolean live, output.shouldHaveExitValue(expExitValue); output.shouldContain(expOutput); if (expExitValue == 0) { - verifyDumpFile(file); + HprofParser.parseAndVerify(file); } file.delete(); } - private static void verifyDumpFile(File dump) { - assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath()); - try { - File out = HprofParser.parse(dump); - - assertTrue(out != null && out.exists() && out.isFile(), - "Could not find hprof parser output file"); - List lines = Files.readAllLines(out.toPath()); - assertTrue(lines.size() > 0, "hprof parser output file is empty"); - for (String line : lines) { - assertFalse(line.matches(".*WARNING(?!.*Failed to resolve " + - "object.*constantPoolOop.*).*")); - } - - out.delete(); - } catch (Exception e) { - e.printStackTrace(); - fail("Could not parse dump file " + dump.getAbsolutePath()); - } - } - private static OutputAnalyzer jmap(String... toolArgs) throws Exception { JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jmap"); launcher.addVMArgs(Utils.getTestJavaOpts()); diff --git a/test/lib/jdk/test/lib/hprof/HprofParser.java b/test/lib/jdk/test/lib/hprof/HprofParser.java index 88841f9e6d4..96b53c304b7 100644 --- a/test/lib/jdk/test/lib/hprof/HprofParser.java +++ b/test/lib/jdk/test/lib/hprof/HprofParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,13 @@ import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import jdk.test.lib.Asserts; import jdk.test.lib.hprof.model.Snapshot; import jdk.test.lib.hprof.parser.Reader; @@ -48,17 +53,24 @@ public static void main(String[] args) throws Exception { } /** - * @see #parse(File, boolean, boolean, boolean) + * @see #parse(File, boolean, boolean, boolean, boolean) + */ + public static File parseAndVerify(File dump) throws Exception { + return parse(dump, false, true, true, true); + } + + /** + * @see #parse(File, boolean, boolean, boolean, boolean) */ public static File parse(File dump) throws Exception { - return parse(dump, false, true, true); + return parse(dump, false, true, true, false); } /** - * @see #parse(File, boolean, boolean, boolean) + * @see #parse(File, boolean, boolean, boolean, boolean) */ public static File parseWithDebugInfo(File dump) throws Exception { - return parse(dump, true, true, true); + return parse(dump, true, true, true, false); } /** @@ -68,10 +80,12 @@ public static File parseWithDebugInfo(File dump) throws Exception { * @param debug Turn on/off debug file parsing * @param callStack Turn on/off tracking of object allocation call stack * @param calculateRefs Turn on/off tracking object allocation call stack + * @param verifyParse Verify output of parse process and fail if error occurred * @throws Exception * @return File containing output from the parser */ - public static File parse(File dump, boolean debug, boolean callStack, boolean calculateRefs) throws Exception { + public static File parse(File dump, boolean debug, boolean callStack, + boolean calculateRefs, boolean verifyParse) throws Exception { File out = new File("hprof." + System.currentTimeMillis() + ".out"); if (out.exists()) { out.delete(); @@ -87,11 +101,21 @@ public static File parse(File dump, boolean debug, boolean callStack, boolean ca snapshot.resolve(calculateRefs); System.out.println("Snapshot resolved."); } - } finally { - System.setOut(psSystemOut); - } - + } finally { + System.setOut(psSystemOut); + } + if (verifyParse) { + verifyParse(out); + } return out; } + private static void verifyParse(File out) throws IOException { + Asserts.assertTrue(out != null && out.exists() && out.isFile(), "Could not find hprof parser output file"); + List lines = Files.readAllLines(out.toPath()); + Asserts.assertTrue(lines.size() > 0, "hprof parser output file is empty"); + for (String line : lines) { + Asserts.assertFalse(line.matches(".*WARNING(?!.*Failed to resolve object.*constantPoolOop.*).*")); + } + } } From ba8d5c22066f5dfcb40091613a8905a513a2aee8 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Mon, 4 Sep 2023 05:25:34 +0000 Subject: [PATCH 48/86] 8315582: Exclude compiler/codecache/CodeCacheFullCountTest.java with Xcomp Reviewed-by: thartmann --- test/hotspot/jtreg/ProblemList-Xcomp.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index 39d50079e11..64cfeff4920 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -27,6 +27,8 @@ # ############################################################################# +compiler/codecache/CodeCacheFullCountTest.java 8315576 generic-all + vmTestbase/nsk/jvmti/AttachOnDemand/attach020/TestDescription.java 8287324 generic-all vmTestbase/nsk/jvmti/SetFieldAccessWatch/setfldw001/TestDescription.java 8205957 generic-all vmTestbase/nsk/jvmti/SetFieldModificationWatch/setfmodw001/TestDescription.java 8205957 linux-x64,windows-x64 From ab12c5d32fede04cbbf8c86b6461a0c71404cd69 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 4 Sep 2023 06:02:03 +0000 Subject: [PATCH 49/86] 8315549: CITime misreports code/total nmethod sizes Reviewed-by: kvn --- src/hotspot/share/compiler/compileBroker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 422607ecbb5..d5a1b31a477 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -2662,8 +2662,8 @@ void CompileBroker::print_times(bool per_compiler, bool aggregate) { uint total_bailout_count = CompileBroker::_total_bailout_count; uint total_invalidated_count = CompileBroker::_total_invalidated_count; - uint nmethods_size = CompileBroker::_sum_nmethod_code_size; - uint nmethods_code_size = CompileBroker::_sum_nmethod_size; + uint nmethods_code_size = CompileBroker::_sum_nmethod_code_size; + uint nmethods_size = CompileBroker::_sum_nmethod_size; tty->cr(); tty->print_cr("Accumulated compiler times"); From 2dc930de12720a1dc27fbbec5a1e161c3699ba79 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 4 Sep 2023 06:53:19 +0000 Subject: [PATCH 50/86] 8314997: Missing optimization opportunities due to missing try_clean_mem_phi() calls Reviewed-by: roland, kvn, thartmann --- src/hotspot/share/opto/cfgnode.cpp | 156 +++++++++++------- src/hotspot/share/opto/cfgnode.hpp | 6 +- .../c2/irTests/igvn/TestCleanMemPhi.java | 126 ++++++++++++++ 3 files changed, 230 insertions(+), 58 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/igvn/TestCleanMemPhi.java diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index c8deb75b80e..fae10177676 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -447,7 +447,7 @@ void RegionNode::verify_can_be_irreducible_entry() const { } #endif //ASSERT -bool RegionNode::try_clean_mem_phi(PhaseGVN *phase) { +void RegionNode::try_clean_mem_phis(PhaseIterGVN* igvn) { // Incremental inlining + PhaseStringOpts sometimes produce: // // cmpP with 1 top input @@ -464,32 +464,60 @@ bool RegionNode::try_clean_mem_phi(PhaseGVN *phase) { // replaced by If's control input but because there's still a Phi, // the Region stays in the graph. The top input from the cmpP is // propagated forward and a subgraph that is useful goes away. The - // code below replaces the Phi with the MergeMem so that the Region - // is simplified. - - PhiNode* phi = has_unique_phi(); - if (phi && phi->type() == Type::MEMORY && req() == 3 && phi->is_diamond_phi(true)) { - MergeMemNode* m = nullptr; - assert(phi->req() == 3, "same as region"); - for (uint i = 1; i < 3; ++i) { - Node *mem = phi->in(i); - if (mem && mem->is_MergeMem() && in(i)->outcnt() == 1) { - // Nothing is control-dependent on path #i except the region itself. - m = mem->as_MergeMem(); - uint j = 3 - i; - Node* other = phi->in(j); - if (other && other == m->base_memory()) { - // m is a successor memory to other, and is not pinned inside the diamond, so push it out. - // This will allow the diamond to collapse completely. - phase->is_IterGVN()->replace_node(phi, m); - return true; - } - } + // code in PhiNode::try_clean_memory_phi() replaces the Phi with the + // MergeMem in order to remove the Region if its last phi dies. + + if (!is_diamond()) { + return; + } + + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + Node* phi = fast_out(i); + if (phi->is_Phi() && phi->as_Phi()->try_clean_memory_phi(igvn)) { + --i; + --imax; } } - return false; } +// Does this region merge a simple diamond formed by a proper IfNode? +// +// Cmp +// / +// ctrl Bool +// \ / +// IfNode +// / \ +// IfFalse IfTrue +// \ / +// Region +bool RegionNode::is_diamond() const { + if (req() != 3) { + return false; + } + + Node* left_path = in(1); + Node* right_path = in(2); + if (left_path == nullptr || right_path == nullptr) { + return false; + } + Node* diamond_if = left_path->in(0); + if (diamond_if == nullptr || !diamond_if->is_If() || diamond_if != right_path->in(0)) { + // Not an IfNode merging a diamond or TOP. + return false; + } + + // Check for a proper bool/cmp + const Node* bol = diamond_if->in(1); + if (!bol->is_Bool()) { + return false; + } + const Node* cmp = bol->in(1); + if (!cmp->is_Cmp()) { + return false; + } + return true; +} //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Must preserve // the CFG, but we can still strip out dead paths. @@ -501,10 +529,8 @@ Node *RegionNode::Ideal(PhaseGVN *phase, bool can_reshape) { // arm of the same IF. If found, then the control-flow split is useless. bool has_phis = false; if (can_reshape) { // Need DU info to check for Phi users + try_clean_mem_phis(phase->is_IterGVN()); has_phis = (has_phi() != nullptr); // Cache result - if (has_phis && try_clean_mem_phi(phase)) { - has_phis = false; - } if (!has_phis) { // No Phi users? Nothing merging? for (uint i = 1; i < req()-1; i++) { @@ -1327,42 +1353,60 @@ const Type* PhiNode::Value(PhaseGVN* phase) const { return ft; } - -//------------------------------is_diamond_phi--------------------------------- // Does this Phi represent a simple well-shaped diamond merge? Return the // index of the true path or 0 otherwise. -// If check_control_only is true, do not inspect the If node at the -// top, and return -1 (not an edge number) on success. -int PhiNode::is_diamond_phi(bool check_control_only) const { - // Check for a 2-path merge - Node *region = in(0); - if( !region ) return 0; - if( region->req() != 3 ) return 0; - if( req() != 3 ) return 0; - // Check that both paths come from the same If - Node *ifp1 = region->in(1); - Node *ifp2 = region->in(2); - if( !ifp1 || !ifp2 ) return 0; - Node *iff = ifp1->in(0); - if( !iff || !iff->is_If() ) return 0; - if( iff != ifp2->in(0) ) return 0; - if (check_control_only) return -1; - // Check for a proper bool/cmp - const Node *b = iff->in(1); - if( !b->is_Bool() ) return 0; - const Node *cmp = b->in(1); - if( !cmp->is_Cmp() ) return 0; - - // Check for branching opposite expected - if( ifp2->Opcode() == Op_IfTrue ) { - assert( ifp1->Opcode() == Op_IfFalse, "" ); - return 2; - } else { - assert( ifp1->Opcode() == Op_IfTrue, "" ); +int PhiNode::is_diamond_phi() const { + Node* region = in(0); + assert(region != nullptr && region->is_Region(), "phi must have region"); + if (!region->as_Region()->is_diamond()) { + return 0; + } + + if (region->in(1)->is_IfTrue()) { + assert(region->in(2)->is_IfFalse(), "bad If"); return 1; + } else { + // Flipped projections. + assert(region->in(2)->is_IfTrue(), "bad If"); + return 2; } } +// Do the following transformation if we find the corresponding graph shape, remove the involved memory phi and return +// true. Otherwise, return false if the transformation cannot be applied. +// +// If If +// / \ / \ +// IfFalse IfTrue /- Some Node IfFalse IfTrue +// \ / / / \ / Some Node +// Region / /-MergeMem ===> Region | +// / \---Phi | MergeMem +// [other phis] \ [other phis] | +// use use +bool PhiNode::try_clean_memory_phi(PhaseIterGVN* igvn) { + if (_type != Type::MEMORY) { + return false; + } + assert(is_diamond_phi() > 0, "sanity"); + assert(req() == 3, "same as region"); + const Node* region = in(0); + for (uint i = 1; i < 3; i++) { + Node* phi_input = in(i); + if (phi_input != nullptr && phi_input->is_MergeMem() && region->in(i)->outcnt() == 1) { + // Nothing is control-dependent on path #i except the region itself. + MergeMemNode* merge_mem = phi_input->as_MergeMem(); + uint j = 3 - i; + Node* other_phi_input = in(j); + if (other_phi_input != nullptr && other_phi_input == merge_mem->base_memory()) { + // merge_mem is a successor memory to other_phi_input, and is not pinned inside the diamond, so push it out. + // This will allow the diamond to collapse completely if there are no other phis left. + igvn->replace_node(this, merge_mem); + return true; + } + } + } + return false; +} //----------------------------check_cmove_id----------------------------------- // Check for CMove'ing a constant after comparing against the constant. // Happens all the time now, since if we compare equality vs a constant in diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 5f8d8f0bc15..9fc68f56309 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -132,7 +132,8 @@ class RegionNode : public Node { virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); void remove_unreachable_subgraph(PhaseIterGVN* igvn); virtual const RegMask &out_RegMask() const; - bool try_clean_mem_phi(PhaseGVN* phase); + bool is_diamond() const; + void try_clean_mem_phis(PhaseIterGVN* phase); bool optimize_trichotomy(PhaseIterGVN* igvn); NOT_PRODUCT(virtual void dump_spec(outputStream* st) const;) }; @@ -233,7 +234,8 @@ class PhiNode : public TypeNode { LoopSafety simple_data_loop_check(Node *in) const; // Is it unsafe data loop? It becomes a dead loop if this phi node removed. bool is_unsafe_data_reference(Node *in) const; - int is_diamond_phi(bool check_control_only = false) const; + int is_diamond_phi() const; + bool try_clean_memory_phi(PhaseIterGVN* igvn); virtual int Opcode() const; virtual bool pinned() const { return in(0) != 0; } virtual const TypePtr *adr_type() const { verify_adr_type(true); return _adr_type; } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestCleanMemPhi.java b/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestCleanMemPhi.java new file mode 100644 index 00000000000..0c3adc6305f --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/igvn/TestCleanMemPhi.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.c2.irTests.igvn; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8314997 + * @requires vm.debug == true & vm.compiler2.enabled + * @summary Test that diamond if-region is removed due to calling try_clean_mem_phi(). + * @library /test/lib / + * @run driver compiler.c2.irTests.igvn.TestCleanMemPhi + */ +public class TestCleanMemPhi { + static boolean flag, flag2; + static int iFld; + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(0); + testFramework.addFlags("-XX:+AlwaysIncrementalInline", "-XX:-PartialPeelLoop", "-XX:-LoopUnswitching"); + testFramework.addScenarios(new Scenario(1, "-XX:-StressIGVN"), + new Scenario(2, "-XX:+StressIGVN")); + testFramework.start(); + } + + static class A { + int i; + } + + + static A a1 = new A(); + static A a2 = new A(); + + + @Test + @IR(counts = {IRNode.COUNTED_LOOP, "> 0"}) + static void testCountedLoop() { + int zero = 34; + + int limit = 2; + for (; limit < 4; limit *= 2) ; + for (int i = 2; i < limit; i++) { + zero = 0; + } + + // Loop is not converted to a counted loop because a diamond is not removed due to missing to call + // try_clean_mem_phi() again on the diamond region. + int i = 0; + do { + iFld = 34; + if (flag2) { + iFld++; + } + + int z = 34; + if (flag) { + lateInline(); // Inlined late -> leaves a MergeMem + if (zero == 34) { // False but only cleaned up after CCP + iFld = 38; + } + z = 32; // Ensures to get a diamond If-Region + } + // Region merging a proper diamond after CCP with a memory phi merging loop phi and the MergeMem from lateInline(). + // Region is not added to the IGVN worklist anymore once the second phi dies. + i++; + } while (zero == 34 || (i < 1000 && a1 == a2)); // Could be converted to a counted loop after the diamond is removed after CCP. + } + + @Test + @IR(failOn = IRNode.LOOP) + static void testRemoveLoop() { + int zero = 34; + + int limit = 2; + for (; limit < 4; limit *= 2) ; + for (int i = 2; i < limit; i++) { + zero = 0; + } + + // Loop is not converted to a counted loop and thus cannot be removed as empty loop because a diamond is not + // removed due to missing to call try_clean_mem_phi() again on the diamond region. + int i = 0; + do { + iFld = 34; + + int z = 34; + if (flag) { + lateInline(); // Inlined late -> leaves a MergeMem + if (zero == 34) { // False but only cleaned up after CCP + iFld = 38; + } + z = 32; // Ensures to get a diamond If-Region + } + // Region merging a proper diamond after CCP with a memory phi merging loop phi and the MergeMem from lateInline(). + // Region is not added to the IGVN worklist anymore once the second phi dies. + + i++; + } while (zero == 34 || (i < 21 && a1 == a2)); + } + + static void lateInline() { + } +} From adfc1d6cd29181c729030d4cbafc8ecf349abab9 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 4 Sep 2023 07:17:28 +0000 Subject: [PATCH 51/86] 8313323: javac -g on a java file which uses unnamed variable leads to ClassFormatError when launching that class Reviewed-by: vromero --- .../classes/com/sun/tools/javac/jvm/Code.java | 2 + .../unnamed/UnnamedLocalVariableTable.java | 49 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 test/langtools/tools/javac/unnamed/UnnamedLocalVariableTable.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java index 9d9dff2d703..382c47935d3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java @@ -2189,6 +2189,8 @@ void putVar(LocalVar var) { ((var.sym.owner.flags() & Flags.LAMBDA_METHOD) == 0 || (var.sym.flags() & Flags.PARAMETER) == 0); if (ignoredSyntheticVar) return; + //don't include unnamed variables: + if (var.sym.name == var.sym.name.table.names.empty) return ; if (varBuffer == null) varBuffer = new LocalVar[20]; else diff --git a/test/langtools/tools/javac/unnamed/UnnamedLocalVariableTable.java b/test/langtools/tools/javac/unnamed/UnnamedLocalVariableTable.java new file mode 100644 index 00000000000..6cfeefa140e --- /dev/null +++ b/test/langtools/tools/javac/unnamed/UnnamedLocalVariableTable.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8313323 + * @summary Verify javac does not produce incorrect LocalVariableTable + * @enablePreview + * @compile -g UnnamedLocalVariableTable.java + * @run main UnnamedLocalVariableTable + */ +public class UnnamedLocalVariableTable { + public static void main(String... args) { + try { + int _ = 0; + if (args[0] instanceof String _) { + System.err.println("1"); + } + I i = _ -> {}; + java.util.List _ = null; + } catch (Exception _) { + System.err.println("2"); + } + } + + interface I { + public void test(String s); + } +} From 0d52c82ed1fa6ecf5b431949c803abc8423336cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 4 Sep 2023 07:41:41 +0000 Subject: [PATCH 52/86] 8310220: IGV: dump graph after each IGVN step at level 4 Reviewed-by: chagedorn, tholenstein --- src/hotspot/share/opto/c2_globals.hpp | 4 ++-- src/hotspot/share/opto/output.cpp | 2 +- src/hotspot/share/opto/parse2.cpp | 2 +- src/hotspot/share/opto/phaseX.cpp | 9 ++++++++- src/hotspot/share/opto/phasetype.hpp | 3 +++ src/utils/IdealGraphVisualizer/README.md | 19 ++++++++++--------- .../lib/ir_framework/CompilePhase.java | 5 ++++- 7 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 8d5b749f3fb..d8125660ca7 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -365,10 +365,10 @@ "Level of detail of the ideal graph printout. " \ "System-wide value, -1=printing is disabled, " \ "0=print nothing except IGVPrintLevel directives, " \ - "4=all details printed. " \ + "5=all details printed. " \ "Level of detail of printouts can be set on a per-method level " \ "as well by using CompileCommand=option.") \ - range(-1, 4) \ + range(-1, 5) \ \ notproduct(intx, PrintIdealGraphPort, 4444, \ "Ideal graph printer to network port") \ diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index ef30f6297e0..9778c289167 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -260,7 +260,7 @@ void PhaseOutput::perform_mach_node_analysis() { pd_perform_mach_node_analysis(); - C->print_method(CompilerPhaseType::PHASE_MACH_ANALYSIS, 4); + C->print_method(CompilerPhaseType::PHASE_MACH_ANALYSIS, 3); } // Convert Nodes to instruction bits and pass off to the VM diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 56fe6dc8053..03bcba13346 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -2785,7 +2785,7 @@ void Parse::do_one_bytecode() { jio_snprintf(buffer, sizeof(buffer), "Bytecode %d: %s", bci(), Bytecodes::name(bc())); bool old = printer->traverse_outs(); printer->set_traverse_outs(true); - printer->print_method(buffer, 4); + printer->print_method(buffer, 5); printer->set_traverse_outs(old); } #endif diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 1e36f015117..e21b54dde26 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -891,9 +891,12 @@ void PhaseIterGVN::verify_step(Node* n) { } void PhaseIterGVN::trace_PhaseIterGVN(Node* n, Node* nn, const Type* oldtype) { + const Type* newtype = type_or_null(n); + if (nn != n || oldtype != newtype) { + C->print_method(PHASE_AFTER_ITER_GVN_STEP, 4, n); + } if (TraceIterativeGVN) { uint wlsize = _worklist.size(); - const Type* newtype = type_or_null(n); if (nn != n) { // print old node tty->print("< "); @@ -1021,6 +1024,7 @@ void PhaseIterGVN::trace_PhaseIterGVN_verbose(Node* n, int num_processed) { void PhaseIterGVN::optimize() { DEBUG_ONLY(uint num_processed = 0;) NOT_PRODUCT(init_verifyPhaseIterGVN();) + C->print_method(PHASE_BEFORE_ITER_GVN, 3); if (StressIGVN) { shuffle_worklist(); } @@ -1030,12 +1034,14 @@ void PhaseIterGVN::optimize() { // update edge info and put uses on worklist. while(_worklist.size()) { if (C->check_node_count(NodeLimitFudgeFactor * 2, "Out of nodes")) { + C->print_method(PHASE_AFTER_ITER_GVN, 3); return; } Node* n = _worklist.pop(); if (loop_count >= K * C->live_nodes()) { DEBUG_ONLY(dump_infinite_loop_info(n, "PhaseIterGVN::optimize");) C->record_method_not_compilable("infinite loop in PhaseIterGVN::optimize"); + C->print_method(PHASE_AFTER_ITER_GVN, 3); return; } DEBUG_ONLY(trace_PhaseIterGVN_verbose(n, num_processed++);) @@ -1050,6 +1056,7 @@ void PhaseIterGVN::optimize() { loop_count++; } NOT_PRODUCT(verify_PhaseIterGVN();) + C->print_method(PHASE_AFTER_ITER_GVN, 3); } #ifdef ASSERT diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index af2e584ce6a..ce27cd2a7f1 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -30,7 +30,10 @@ flags(AFTER_STRINGOPTS, "After StringOpts") \ flags(BEFORE_REMOVEUSELESS, "Before RemoveUseless") \ flags(AFTER_PARSING, "After Parsing") \ + flags(BEFORE_ITER_GVN, "Before Iter GVN") \ flags(ITER_GVN1, "Iter GVN 1") \ + flags(AFTER_ITER_GVN_STEP, "After Iter GVN Step") \ + flags(AFTER_ITER_GVN, "After Iter GVN") \ flags(INCREMENTAL_INLINE_STEP, "Incremental Inline Step") \ flags(INCREMENTAL_INLINE_CLEANUP, "Incremental Inline Cleanup") \ flags(INCREMENTAL_INLINE, "Incremental Inline") \ diff --git a/src/utils/IdealGraphVisualizer/README.md b/src/utils/IdealGraphVisualizer/README.md index 2a364dc19e2..f930ea604a4 100644 --- a/src/utils/IdealGraphVisualizer/README.md +++ b/src/utils/IdealGraphVisualizer/README.md @@ -22,15 +22,16 @@ for building and running IGV. # Usage -The JVM support is controlled by the flag `-XX:PrintIdealGraphLevel=#` where `#` -is: - -* 0: no output, the default -* 1: dumps graph after parsing, before matching, and final code (also dumps - graphs for failed compilations, if available) -* 2: more detail, including after loop opts -* 3: even more detail -* 4: prints graph after parsing every bytecode (very slow) +The JVM support is controlled by the flag `-XX:PrintIdealGraphLevel=N`, where +Ideal graphs are dumped at the following points: + +* `N=0`: no output (default) +* `N=1`: after parsing, before matching, and final code (also for failed + compilations, if available) +* `N=2`: additionally, after every major phase (including loop opts) +* `N=3`: additionally, after every minor phase +* `N=4`: additionally, after every effective IGVN step (slow) +* `N=5`: additionally, after parsing every bytecode (very slow) By default the JVM expects that it will connect to a visualizer on the local host on port 4444. This can be configured using the options diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java index 6cb889a80e4..6f5149a79ba 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/CompilePhase.java @@ -29,7 +29,7 @@ /** * This enum represents all available compile phases on which an IR matching can be done. There is a 1:1 mapping * between IGV phases as specified in phasetype.hpp. Compile phases which are normally not emitted by C2 like FAILURE - * or DEBUG are not listed. This enum should be kept in sync with phasetye.hpp. + * or DEBUG are not listed. This enum should be kept in sync with phasetype.hpp. * *

* There are two additional compile phases PRINT_IDEAL and PRINT_OPTO_ASSEMBLY. PRINT_IDEAL is the output that is printed @@ -43,7 +43,10 @@ public enum CompilePhase { AFTER_STRINGOPTS("After StringOpts"), BEFORE_REMOVEUSELESS("Before RemoveUseless"), AFTER_PARSING("After Parsing"), + BEFORE_ITER_GVN("Before Iter GVN"), ITER_GVN1("Iter GVN 1"), + AFTER_ITER_GVN_STEP("After Iter GVN Step"), + AFTER_ITER_GVN("After Iter GVN"), INCREMENTAL_INLINE_STEP("Incremental Inline Step"), INCREMENTAL_INLINE_CLEANUP("Incremental Inline Cleanup"), INCREMENTAL_INLINE("Incremental Inline"), From 3094fd1ac5153289434515d9b718bc5d6885b7dc Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 4 Sep 2023 08:36:41 +0000 Subject: [PATCH 53/86] 8314662: jshell shows duplicated signatures of javap Reviewed-by: asotona, cstein --- .../jdk/jshell/SourceCodeAnalysisImpl.java | 4 ++-- .../jdk/jshell/CompletionSuggestionTest.java | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index 84500799b77..50b9b627adc 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -1188,10 +1188,10 @@ public Scope next() { } }; @SuppressWarnings("unchecked") - List result = Util.stream(scopeIterable) + Set result = Util.stream(scopeIterable) .flatMap(this::localElements) .flatMap(el -> Util.stream((Iterable)elementConvertor.apply(el))) - .collect(toCollection(ArrayList :: new)); + .collect(toCollection(LinkedHashSet :: new)); result.addAll(listPackages(at, "")); return result; } diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index dda5e9f9f06..e932464481e 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466 8197439 8221759 8234896 8240658 8278039 8286206 8296789 + * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466 8197439 8221759 8234896 8240658 8278039 8286206 8296789 8314662 * @summary Test Completion and Documentation * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -48,13 +48,16 @@ import java.util.function.Function; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; +import jdk.jshell.MethodSnippet; import jdk.jshell.Snippet; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import static jdk.jshell.Snippet.Status.NONEXISTENT; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.Status.OVERWRITTEN; +import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; @Test public class CompletionSuggestionTest extends KullaTesting { @@ -797,4 +800,14 @@ public void testParentMembers() { assertEval("var sb=new StringBuilder();"); assertCompletionIncludesExcludes("sb.|", true, Set.of("capacity()", "setLength("), Set.of("maybeLatin1")); } + + //JDK-8314662 + public void testDuplicateImport() { + MethodSnippet m1 = methodKey(assertEval("void test(String s) { foo(); }", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_DEFINED, true, null))); + MethodSnippet m2 = methodKey(assertEval("void test(Integer i) { foo(); }", ste(MAIN_SNIPPET, NONEXISTENT, RECOVERABLE_DEFINED, true, null))); + assertEval("void foo() { }", ste(MAIN_SNIPPET, NONEXISTENT, VALID, true, null), + ste(m1, RECOVERABLE_DEFINED, VALID, true, MAIN_SNIPPET), + ste(m2, RECOVERABLE_DEFINED, VALID, true, MAIN_SNIPPET)); + assertSignature("test(|", "void test(String s)", "void test(Integer i)"); + } } From 84425a62904f84601affc9710eefece88665374a Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 4 Sep 2023 09:14:16 +0000 Subject: [PATCH 54/86] 8315452: Erroneous AST missing modifiers for partial input Reviewed-by: vromero --- .../sun/tools/javac/parser/JavacParser.java | 6 +- .../tools/javac/parser/JavacParserTest.java | 62 ++++++++++++++++++- 2 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index f6368c48b08..6238daf83d4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -3918,7 +3918,7 @@ public JCTree.JCCompilationUnit parseCompilationUnit() { boolean firstTypeDecl = true; // have we see a class, enum, or interface declaration yet? boolean isUnnamedClass = false; - while (token.kind != EOF) { + OUTER: while (token.kind != EOF) { if (token.pos <= endPosTable.errorEndPos) { // error recovery skip(firstTypeDecl, false, false, false); @@ -3933,6 +3933,8 @@ public JCTree.JCCompilationUnit parseCompilationUnit() { while (firstTypeDecl && mods == null && token.kind == SEMI) { semiList.append(toP(F.at(token.pos).Skip())); nextToken(); + if (token.kind == EOF) + break OUTER; } if (firstTypeDecl && mods == null && token.kind == IMPORT) { if (!semiList.isEmpty()) { @@ -3999,7 +4001,7 @@ public JCTree.JCCompilationUnit parseCompilationUnit() { checkSourceLevel(token.pos, Feature.UNNAMED_CLASSES); defs.appendList(topLevelMethodOrFieldDeclaration(mods)); isUnnamedClass = true; - } else if (token.kind != EOF) { + } else { JCTree def = typeDeclaration(mods, docComment); if (def instanceof JCExpressionStatement statement) def = statement.expr; diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index 0f4ff3cd2a5..d1bb23091aa 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -60,6 +60,8 @@ import com.sun.tools.javac.tree.JCTree; import java.io.IOException; import java.io.StringWriter; +import java.io.UncheckedIOException; +import java.io.Writer; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -70,6 +72,7 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.regex.Pattern; import javax.lang.model.element.Modifier; import javax.lang.model.type.TypeKind; @@ -88,7 +91,8 @@ import com.sun.source.util.TreePathScanner; import com.sun.tools.javac.api.JavacTaskPool; import com.sun.tools.javac.api.JavacTaskPool.Worker; -import java.util.Objects; +import com.sun.tools.javac.tree.JCTree.JCErroneous; +import com.sun.tools.javac.tree.Pretty; public class JavacParserTest extends TestCase { static final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); @@ -2486,6 +2490,28 @@ void main() { codes); } + @Test //JDK-8315452 + void testPartialTopLevelModifiers() throws IOException { + String code = """ + package test; + public + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package test; + (ERROR: public )"""); + } + void run(String[] args) throws Exception { int passed = 0, failed = 0; final Pattern p = (args != null && args.length > 0) @@ -2515,6 +2541,38 @@ void run(String[] args) throws Exception { passed + ", failed = " + failed + " ??????????"); } } + + private String toStringWithErrors(Tree tree) { + StringWriter s = new StringWriter(); + try { + new PrettyWithErrors(s, false).printExpr((JCTree) tree); + } catch (IOException e) { + // should never happen, because StringWriter is defined + // never to throw any IOExceptions + throw new AssertionError(e); + } + return s.toString(); + } + + private static final class PrettyWithErrors extends Pretty { + + public PrettyWithErrors(Writer out, boolean sourceOutput) { + super(out, sourceOutput); + } + + @Override + public void visitErroneous(JCErroneous tree) { + try { + print("(ERROR: "); + print(tree.errs); + print(")"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + } + } abstract class TestCase { From 94a74a0a450cad6080302bc1db15a1a564940bdd Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 4 Sep 2023 10:06:20 +0000 Subject: [PATCH 55/86] 8315534: Incorrect warnings about implicit annotation processing Reviewed-by: darcy --- .../sun/tools/javac/main/JavaCompiler.java | 5 +- .../options/TestNoteOnImplicitProcessing.java | 102 +++++++++++++++++- 2 files changed, 100 insertions(+), 7 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index b0ba6c81020..10f4d609c68 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -915,8 +915,6 @@ public void compile(Collection sourceFileObjects, taskListener.started(new TaskEvent(TaskEvent.Kind.COMPILATION)); } - if (processors != null && processors.iterator().hasNext()) - explicitAnnotationProcessingRequested = true; // as a JavaCompiler can only be used once, throw an exception if // it has been used before. if (hasBeenUsed) @@ -1143,6 +1141,9 @@ public List enterTrees(List roots) { public void initProcessAnnotations(Iterable processors, Collection initialFiles, Collection initialClassNames) { + if (processors != null && processors.iterator().hasNext()) + explicitAnnotationProcessingRequested = true; + // Process annotations if processing is not disabled and there // is at least one Processor available. if (options.isSet(PROC, "none")) { diff --git a/test/langtools/tools/javac/processing/options/TestNoteOnImplicitProcessing.java b/test/langtools/tools/javac/processing/options/TestNoteOnImplicitProcessing.java index 4daeb9e6260..81efbce05aa 100644 --- a/test/langtools/tools/javac/processing/options/TestNoteOnImplicitProcessing.java +++ b/test/langtools/tools/javac/processing/options/TestNoteOnImplicitProcessing.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8310061 + * @bug 8310061 8315534 * @summary Verify a note is issued for implicit annotation processing * * @library /tools/lib /tools/javac/lib @@ -34,15 +34,22 @@ * @run main TestNoteOnImplicitProcessing */ -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.Files; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.StringWriter; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import javax.annotation.processing.Processor; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; import toolbox.JavacTask; import toolbox.Task; @@ -290,4 +297,89 @@ private void checkForCompilerNote(Task.Result javacResult, boolean expectedPrese throw new RuntimeException("Expected note not printed"); } } + + @Test + public void processorsViaAPI(Path base, Path jarFile) throws Exception { + ClassLoader cl = new URLClassLoader(new URL[] {jarFile.toUri().toURL()}); + Class processorClass = Class.forName(processorName, true, cl); + StringWriter compilerOut = new StringWriter(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + JavaCompiler provider = ToolProvider.getSystemJavaCompiler(); + PrintStream oldOut = System.out; + + try (StandardJavaFileManager jfm = provider.getStandardFileManager(null, null, null)) { + System.setOut(new PrintStream(out, true, StandardCharsets.UTF_8)); + Iterable inputFile = jfm.getJavaFileObjects("HelloWorldTest.java"); + + { + List options = List.of("-classpath", jarFile.toString(), "-XDrawDiagnostics"); + CompilationTask task = provider.getTask(compilerOut, null, null, options, null, inputFile); + + task.call(); + + verifyMessages(out, compilerOut, true); + } + + { + List options = List.of("-classpath", jarFile.toString(), "-XDrawDiagnostics"); + CompilationTask task = provider.getTask(compilerOut, null, null, options, null, inputFile); + Processor processor = + (Processor) processorClass.getDeclaredConstructor().newInstance(); + + task.setProcessors(List.of(processor)); + task.call(); + + verifyMessages(out, compilerOut, false); + } + + { + List options = List.of("-classpath", jarFile.toString(), "-XDrawDiagnostics"); + com.sun.source.util.JavacTask task = + (com.sun.source.util.JavacTask) provider.getTask(compilerOut, null, null, options, null, inputFile); + + task.analyze(); + + verifyMessages(out, compilerOut, true); + } + + { + List options = List.of("-classpath", jarFile.toString(), "-XDrawDiagnostics"); + com.sun.source.util.JavacTask task = + (com.sun.source.util.JavacTask) provider.getTask(compilerOut, null, null, options, null, inputFile); + + Processor processor = + (Processor) processorClass.getDeclaredConstructor().newInstance(); + + task.setProcessors(List.of(processor)); + task.analyze(); + + verifyMessages(out, compilerOut, false); + } + } finally { + System.setOut(oldOut); + } + } + + private void verifyMessages(ByteArrayOutputStream out, StringWriter compilerOut, boolean expectedNotePresent) { + if (!out.toString(StandardCharsets.UTF_8).contains("ImplicitProcTestProc run")) { + throw new RuntimeException("Expected processor message not printed"); + } + + out.reset(); + + boolean printed = compilerOut.toString().contains("- compiler.note.implicit.annotation.processing"); + + if (!expectedNotePresent && printed) { + throw new RuntimeException("Unexpected note printed"); + } + + if (expectedNotePresent && !printed) { + throw new RuntimeException("Expected note not printed"); + } + + StringBuffer compilerOutData = compilerOut.getBuffer(); + + compilerOutData.delete(0, compilerOutData.length()); + } + } From d1cabe4f22abe96486d85bd5efc468e0e640c3e4 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 4 Sep 2023 10:17:23 +0000 Subject: [PATCH 56/86] 8315566: [JVMCI] deadlock in JVMCI startup when bad option specified Reviewed-by: thartmann, never --- .../vm/ci/hotspot/HotSpotJVMCIRuntime.java | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index 02ed11cae2a..1f2276757c5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -49,6 +49,7 @@ import java.util.Map; import java.util.Objects; import java.util.ServiceLoader; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -509,18 +510,7 @@ T get() { private final Map, JVMCIBackend> backends = new HashMap<>(); - private volatile List vmEventListeners; - - private Iterable getVmEventListeners() { - if (vmEventListeners == null) { - synchronized (this) { - if (vmEventListeners == null) { - vmEventListeners = JVMCIServiceLocator.getProviders(HotSpotVMEventListener.class); - } - } - } - return vmEventListeners; - } + private final List vmEventListeners; @SuppressWarnings("try") private HotSpotJVMCIRuntime() { @@ -580,6 +570,8 @@ private HotSpotJVMCIRuntime() { if (Option.PrintConfig.getBoolean()) { configStore.printConfig(this); } + + vmEventListeners = JVMCIServiceLocator.getProviders(HotSpotVMEventListener.class); } /** @@ -938,22 +930,21 @@ private boolean isGCSupported(int gcIdentifier) { } /** - * Guard to ensure shut down actions are performed at most once. + * Guard to ensure shut down actions are performed by at most one thread. */ - private boolean isShutdown; + private final AtomicBoolean isShutdown = new AtomicBoolean(); /** * Shuts down the runtime. */ @VMEntryPoint - private synchronized void shutdown() throws Exception { - if (!isShutdown) { - isShutdown = true; + private void shutdown() throws Exception { + if (isShutdown.compareAndSet(false, true)) { // Cleaners are normally only processed when a new Cleaner is // instantiated so process all remaining cleaners now. Cleaner.clean(); - for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { vmEventListener.notifyShutdown(); } } @@ -964,7 +955,7 @@ private synchronized void shutdown() throws Exception { */ @VMEntryPoint private void bootstrapFinished() throws Exception { - for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { vmEventListener.notifyBootstrapFinished(); } } @@ -977,7 +968,7 @@ private void bootstrapFinished() throws Exception { * @param compiledCode */ void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, InstalledCode installedCode, CompiledCode compiledCode) { - for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) { + for (HotSpotVMEventListener vmEventListener : vmEventListeners) { vmEventListener.notifyInstall(hotSpotCodeCacheProvider, installedCode, compiledCode); } } From d7e4087faf7b2e69de59e246880a10a3a1431ca9 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 4 Sep 2023 10:19:18 +0000 Subject: [PATCH 57/86] 8315369: [JVMCI] failure to attach to a libgraal isolate during shutdown should not be fatal Reviewed-by: never --- src/hotspot/share/compiler/compileBroker.cpp | 9 ++- .../share/jvmci/jniAccessMark.inline.hpp | 1 + src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 61 ++++++--------- src/hotspot/share/jvmci/jvmciEnv.cpp | 77 +++++++++++-------- src/hotspot/share/jvmci/jvmciEnv.hpp | 47 ++++++----- src/hotspot/share/jvmci/jvmciExceptions.hpp | 10 ++- src/hotspot/share/jvmci/jvmciRuntime.cpp | 36 +++++---- 7 files changed, 131 insertions(+), 110 deletions(-) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index d5a1b31a477..bdc023d0dbe 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -2203,7 +2203,14 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { compilable = ciEnv::MethodCompilable_never; } else { JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__); - failure_reason = compile_state.failure_reason(); + if (env.init_error() != JNI_OK) { + failure_reason = os::strdup(err_msg("Error attaching to libjvmci (err: %d)", env.init_error()), mtJVMCI); + bool reason_on_C_heap = true; + // In case of JNI_ENOMEM, there's a good chance a subsequent attempt to create libjvmci or attach to it + // might succeed. Other errors most likely indicate a non-recoverable error in the JVMCI runtime. + bool retryable = env.init_error() == JNI_ENOMEM; + compile_state.set_failure(retryable, failure_reason, reason_on_C_heap); + } if (failure_reason == nullptr) { if (WhiteBoxAPI && WhiteBox::compilation_locked) { // Must switch to native to block diff --git a/src/hotspot/share/jvmci/jniAccessMark.inline.hpp b/src/hotspot/share/jvmci/jniAccessMark.inline.hpp index 0087f93e014..a4b92bdc5c1 100644 --- a/src/hotspot/share/jvmci/jniAccessMark.inline.hpp +++ b/src/hotspot/share/jvmci/jniAccessMark.inline.hpp @@ -44,6 +44,7 @@ class JNIAccessMark : public StackObj { inline JNIAccessMark(JVMCIEnv* jvmci_env, JavaThread* thread=JavaThread::current()) : _ttnfv(thread), _hm(thread) { _env = jvmci_env->_env; + guarantee(jvmci_env->init_error() == JNI_OK, "invalid JVMCIEnv (err: %d)", jvmci_env->init_error()); } JNIEnv* env() const { return _env; } JNIEnv* operator () () const { return _env; } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 868f4a6db4f..09b3cb26203 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -171,7 +171,7 @@ Handle JavaArgumentUnboxer::next_arg(BasicType expectedType) { #define C2V_BLOCK(result_type, name, signature) \ JVMCI_VM_ENTRY_MARK; \ ResourceMark rm; \ - JNI_JVMCIENV(JVMCI::compilation_tick(thread), env); + JVMCIENV_FROM_JNI(JVMCI::compilation_tick(thread), env); static JavaThread* get_current_thread(bool allow_null=true) { Thread* thread = Thread::current_or_null_safe(); @@ -2436,16 +2436,13 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas JVMCIRuntime* runtime; { // Ensure the JVMCI shared library runtime is initialized. - bool jni_enomem_is_fatal = false; - JVMCIEnv __peer_jvmci_env__(thread, false, jni_enomem_is_fatal, __FILE__, __LINE__); - JVMCIEnv* peerEnv = &__peer_jvmci_env__; - if (peerEnv->has_jni_enomem()) { - JVMCI_THROW_MSG_0(OutOfMemoryError, "JNI_ENOMEM creating or attaching to libjvmci"); - } + PEER_JVMCIENV_FROM_THREAD(THREAD, false); + PEER_JVMCIENV->check_init(JVMCI_CHECK_NULL); + HandleMark hm(THREAD); runtime = JVMCI::compiler_runtime(thread); - if (peerEnv->has_pending_exception()) { - peerEnv->describe_pending_exception(tty); + if (PEER_JVMCIENV->has_pending_exception()) { + PEER_JVMCIENV->describe_pending_exception(tty); } sl_handle = JVMCI::get_shared_library(sl_path, false); if (sl_handle == nullptr) { @@ -2604,17 +2601,13 @@ C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jb { // Ensure the JVMCI shared library runtime is initialized. - bool jni_enomem_is_fatal = false; - JVMCIEnv __peer_jvmci_env__(thread, false, jni_enomem_is_fatal, __FILE__, __LINE__); - JVMCIEnv* peerJVMCIEnv = &__peer_jvmci_env__; - if (peerJVMCIEnv->has_jni_enomem()) { - JVMCI_THROW_MSG_0(OutOfMemoryError, "JNI_ENOMEM creating or attaching to libjvmci"); - } + PEER_JVMCIENV_FROM_THREAD(THREAD, false); + PEER_JVMCIENV->check_init(JVMCI_CHECK_0); HandleMark hm(thread); - JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(peerJVMCIEnv); - if (peerJVMCIEnv->has_pending_exception()) { - peerJVMCIEnv->describe_pending_exception(tty); + JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(PEER_JVMCIENV); + if (PEER_JVMCIENV->has_pending_exception()) { + PEER_JVMCIENV->describe_pending_exception(tty); } char* sl_path; if (JVMCI::get_shared_library(sl_path, false) == nullptr) { @@ -2704,33 +2697,29 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool if (obj_handle == nullptr) { return 0L; } - bool jni_enomem_is_fatal = false; - JVMCIEnv __peer_jvmci_env__(thread, !JVMCIENV->is_hotspot(), jni_enomem_is_fatal, __FILE__, __LINE__); - JVMCIEnv* peerEnv = &__peer_jvmci_env__; - JVMCIEnv* thisEnv = JVMCIENV; - if (peerEnv->has_jni_enomem()) { - JVMCI_THROW_MSG_0(OutOfMemoryError, "JNI_ENOMEM creating or attaching to libjvmci"); - } + PEER_JVMCIENV_FROM_THREAD(THREAD, !JVMCIENV->is_hotspot()); + PEER_JVMCIENV->check_init(JVMCI_CHECK_0); + JVMCIEnv* thisEnv = JVMCIENV; JVMCIObject obj = thisEnv->wrap(obj_handle); JVMCIObject result; if (thisEnv->isa_HotSpotResolvedJavaMethodImpl(obj)) { methodHandle method(THREAD, thisEnv->asMethod(obj)); - result = peerEnv->get_jvmci_method(method, JVMCI_CHECK_0); + result = PEER_JVMCIENV->get_jvmci_method(method, JVMCI_CHECK_0); } else if (thisEnv->isa_HotSpotResolvedObjectTypeImpl(obj)) { Klass* klass = thisEnv->asKlass(obj); JVMCIKlassHandle klass_handle(THREAD); klass_handle = klass; - result = peerEnv->get_jvmci_type(klass_handle, JVMCI_CHECK_0); + result = PEER_JVMCIENV->get_jvmci_type(klass_handle, JVMCI_CHECK_0); } else if (thisEnv->isa_HotSpotResolvedPrimitiveType(obj)) { BasicType type = JVMCIENV->kindToBasicType(JVMCIENV->get_HotSpotResolvedPrimitiveType_kind(obj), JVMCI_CHECK_0); - result = peerEnv->get_jvmci_primitive_type(type); + result = PEER_JVMCIENV->get_jvmci_primitive_type(type); } else if (thisEnv->isa_IndirectHotSpotObjectConstantImpl(obj) || thisEnv->isa_DirectHotSpotObjectConstantImpl(obj)) { Handle constant = thisEnv->asConstant(obj, JVMCI_CHECK_0); - result = peerEnv->get_object_constant(constant()); + result = PEER_JVMCIENV->get_object_constant(constant()); } else if (thisEnv->isa_HotSpotNmethod(obj)) { - if (peerEnv->is_hotspot()) { + if (PEER_JVMCIENV->is_hotspot()) { nmethod* nm = JVMCIENV->get_nmethod(obj); if (nm != nullptr) { JVMCINMethodData* data = nm->jvmci_nmethod_data(); @@ -2753,7 +2742,7 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool JVMCIObject name_string = thisEnv->get_InstalledCode_name(obj); const char* cstring = name_string.is_null() ? nullptr : thisEnv->as_utf8_string(name_string); // Create a new HotSpotNmethod instance in the peer runtime - result = peerEnv->new_HotSpotNmethod(mh, cstring, isDefault, compileIdSnapshot, JVMCI_CHECK_0); + result = PEER_JVMCIENV->new_HotSpotNmethod(mh, cstring, isDefault, compileIdSnapshot, JVMCI_CHECK_0); nmethod* nm = JVMCIENV->get_nmethod(obj); if (result.is_null()) { // exception occurred (e.g. OOME) creating a new HotSpotNmethod @@ -2761,9 +2750,9 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool // nmethod must have been unloaded } else { // Link the new HotSpotNmethod to the nmethod - peerEnv->initialize_installed_code(result, nm, JVMCI_CHECK_0); + PEER_JVMCIENV->initialize_installed_code(result, nm, JVMCI_CHECK_0); // Only HotSpotNmethod instances in the HotSpot heap are tracked directly by the runtime. - if (peerEnv->is_hotspot()) { + if (PEER_JVMCIENV->is_hotspot()) { JVMCINMethodData* data = nm->jvmci_nmethod_data(); if (data == nullptr) { JVMCI_THROW_MSG_0(IllegalArgumentException, "Cannot set HotSpotNmethod mirror for default nmethod"); @@ -2781,13 +2770,13 @@ C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle, jbool err_msg("Cannot translate object of type: %s", thisEnv->klass_name(obj))); } if (callPostTranslation) { - peerEnv->call_HotSpotJVMCIRuntime_postTranslation(result, JVMCI_CHECK_0); + PEER_JVMCIENV->call_HotSpotJVMCIRuntime_postTranslation(result, JVMCI_CHECK_0); } // Propagate any exception that occurred while creating the translated object - if (peerEnv->transfer_pending_exception(thread, thisEnv)) { + if (PEER_JVMCIENV->transfer_pending_exception(thread, thisEnv)) { return 0L; } - return (jlong) peerEnv->make_global(result).as_jobject(); + return (jlong) PEER_JVMCIENV->make_global(result).as_jobject(); } C2V_VMENTRY_NULL(jobject, unhand, (JNIEnv* env, jobject, jlong obj_handle)) diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index d61cc269874..bab3de8c335 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -115,7 +115,7 @@ bool JVMCICompileState::jvmti_state_changed() const { return false; } -void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env, bool jni_enomem_is_fatal) { +void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) { assert(thread != nullptr, "npe"); _env = nullptr; _pop_frame_on_close = false; @@ -147,18 +147,14 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env, boo _is_hotspot = false; _runtime = JVMCI::compiler_runtime(thread); - int create_JavaVM_err = JNI_OK; - _env = _runtime->init_shared_library_javavm(&create_JavaVM_err); + _env = _runtime->init_shared_library_javavm(&_init_error); if (_env != nullptr) { // Creating the JVMCI shared library VM also attaches the current thread _detach_on_close = true; - } else if (create_JavaVM_err != JNI_OK) { - if (!jni_enomem_is_fatal && create_JavaVM_err == JNI_ENOMEM) { - _jni_enomem = true; - return; - } else { - fatal("JNI_CreateJavaVM failed with return value %d", create_JavaVM_err); - } + } else if (_init_error != JNI_OK) { + // Caller creating this JVMCIEnv must handle the error. + JVMCI_event_1("[%s:%d] Error creating libjvmci (err: %d)", _file, _line, _init_error); + return; } else { _runtime->GetEnv(thread, (void**)&parent_env, JNI_VERSION_1_2); if (parent_env != nullptr) { @@ -174,15 +170,14 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env, boo attach_args.version = JNI_VERSION_1_2; attach_args.name = const_cast(thread->name()); attach_args.group = nullptr; - jint attach_result = _runtime->AttachCurrentThread(thread, (void**) &_env, &attach_args); - if (attach_result == JNI_OK) { + _init_error = _runtime->AttachCurrentThread(thread, (void**) &_env, &attach_args); + if (_init_error == JNI_OK) { _detach_on_close = true; - } else if (!jni_enomem_is_fatal && attach_result == JNI_ENOMEM) { + } else { + // Caller creating this JVMCIEnv must handle the error. _env = nullptr; - _jni_enomem = true; + JVMCI_event_1("[%s:%d] Error attaching to libjvmci (err: %d)", _file, _line, _init_error); return; - } else { - fatal("Error attaching current thread (%s) to JVMCI shared library JNI interface", attach_args.name); } } } @@ -193,41 +188,36 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env, boo JNIAccessMark jni(this, thread); jint result = _env->PushLocalFrame(32); if (result != JNI_OK) { - char message[256]; - jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line); - JVMCIRuntime::fatal_exception(this, message); + JVMCI_event_1("[%s:%d] Error pushing local JNI frame (err: %d)", _file, _line, _init_error); + return; } _pop_frame_on_close = true; } JVMCIEnv::JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line): - _throw_to_caller(false), _file(file), _line(line), _jni_enomem(false), _compile_state(compile_state) { - // In case of JNI_ENOMEM, there's a good chance a subsequent attempt to create libjvmci or attach to it - // might succeed. Other errors most likely indicate a non-recoverable error in the JVMCI runtime. - bool jni_enomem_is_fatal = false; - init_env_mode_runtime(thread, nullptr, jni_enomem_is_fatal); - if (_jni_enomem) { - compile_state->set_failure(true, "Out of memory while attaching JVMCI compiler to current thread"); - } + _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _compile_state(compile_state) { + init_env_mode_runtime(thread, nullptr); } JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line): - _throw_to_caller(false), _file(file), _line(line), _jni_enomem(false), _compile_state(nullptr) { + _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _compile_state(nullptr) { init_env_mode_runtime(thread, nullptr); } JVMCIEnv::JVMCIEnv(JavaThread* thread, JNIEnv* parent_env, const char* file, int line): - _throw_to_caller(true), _file(file), _line(line), _jni_enomem(false), _compile_state(nullptr) { + _throw_to_caller(true), _file(file), _line(line), _init_error(JNI_OK), _compile_state(nullptr) { + assert(parent_env != nullptr, "npe"); init_env_mode_runtime(thread, parent_env); assert(_env == nullptr || parent_env == _env, "mismatched JNIEnvironment"); + assert(_init_error == JNI_OK, "err: %d", _init_error); } -void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, bool jni_enomem_is_fatal, const char* file, int line) { +void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, const char* file, int line) { _compile_state = nullptr; _throw_to_caller = false; _file = file; _line = line; - _jni_enomem = false; + _init_error = JNI_OK; if (is_hotspot) { _env = nullptr; _pop_frame_on_close = false; @@ -235,8 +225,29 @@ void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, bool jni_enomem_is_fata _is_hotspot = true; _runtime = JVMCI::java_runtime(); } else { - init_env_mode_runtime(thread, nullptr, jni_enomem_is_fatal); + init_env_mode_runtime(thread, nullptr); + } +} + +void JVMCIEnv::check_init(JVMCI_TRAPS) { + guarantee(JVMCIENV != this, "must be"); + if (_init_error == JNI_OK) { + return; + } + if (_init_error == JNI_ENOMEM) { + JVMCI_THROW_MSG(OutOfMemoryError, "JNI_ENOMEM creating or attaching to libjvmci"); + } + JVMCI_THROW_MSG(InternalError, err_msg("Error creating or attaching to libjvmci (err: %d)", _init_error)); +} + +void JVMCIEnv::check_init(TRAPS) { + if (_init_error == JNI_OK) { + return; + } + if (_init_error == JNI_ENOMEM) { + THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "JNI_ENOMEM creating or attaching to libjvmci"); } + THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), err_msg("Error creating or attaching to libjvmci (err: %d)", _init_error)); } // Prints a pending exception (if any) and its stack trace to st. @@ -561,7 +572,7 @@ jboolean JVMCIEnv::transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer } JVMCIEnv::~JVMCIEnv() { - if (_jni_enomem) { + if (_init_error != JNI_OK) { return; } if (_throw_to_caller) { diff --git a/src/hotspot/share/jvmci/jvmciEnv.hpp b/src/hotspot/share/jvmci/jvmciEnv.hpp index 345504affb8..59600b97fe1 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.hpp +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp @@ -157,9 +157,9 @@ class JVMCIEnv : public ResourceObj { friend class JNIAccessMark; // Initializes the _env, _mode and _runtime fields. - void init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env, bool jni_enomem_is_fatal = true); + void init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env); - void init(JavaThread* thread, bool is_hotspot, bool jni_enomem_is_fatal, const char* file, int line); + void init(JavaThread* thread, bool is_hotspot, const char* file, int line); JNIEnv* _env; // JNI env for calling into shared library bool _pop_frame_on_close; // Must pop frame on close? @@ -169,9 +169,9 @@ class JVMCIEnv : public ResourceObj { bool _throw_to_caller; // Propagate an exception raised in this env to the caller? const char* _file; // The file and ... int _line; // ... line where this JNIEnv was created - bool _jni_enomem; // JNI_ENOMEM returned when creating or attaching to a libjvmci isolate. - // If true, the JVMCIEnv is invalid and should not be used apart from - // calling has_jni_enomem(). + int _init_error; // JNI code returned when creating or attaching to a libjvmci isolate. + // If not JNI_OK, the JVMCIEnv is invalid and should not be used apart from + // calling init_error(). // Translates an exception on the HotSpot heap (i.e., hotspot_env) to an exception on // the shared library heap (i.e., jni_env). The translation includes the stack and cause(s) of `throwable`. @@ -185,11 +185,12 @@ class JVMCIEnv : public ResourceObj { public: // Opens a JVMCIEnv scope for a Java to VM call (e.g., via CompilerToVM). + // The `parent_env` argument must not be null. // An exception occurring within the scope is left pending when the // scope closes so that it will be propagated back to Java. // The JVMCIEnv destructor translates the exception object for the // Java runtime if necessary. - JVMCIEnv(JavaThread* thread, JNIEnv* env, const char* file, int line); + JVMCIEnv(JavaThread* thread, JNIEnv* parent_env, const char* file, int line); // Opens a JVMCIEnv scope for a compilation scheduled by the CompileBroker. // An exception occurring within the scope must not be propagated back to @@ -200,34 +201,32 @@ class JVMCIEnv : public ResourceObj { // within the scope must not be propagated back to the caller. JVMCIEnv(JavaThread* env, const char* file, int line); - // Opens a JNIEnv scope for accessing `for_object`. An exception occurring - // within the scope must not be propagated back to the caller. - JVMCIEnv(JavaThread* thread, JVMCIObject for_object, const char* file, int line) { - // A JNI call to access an object in the shared library heap - // can block or take a long time so do not allow such access - // on the VM thread. - assert(for_object.is_hotspot() || !Thread::current()->is_VM_thread(), - "cannot open JVMCIEnv scope when in the VM thread for accessing a shared library heap object"); - bool jni_enomem_is_fatal = true; - init(thread, for_object.is_hotspot(), jni_enomem_is_fatal, file, line); - } - // Opens a JNIEnv scope for the HotSpot runtime if `is_hotspot` is true // otherwise for the shared library runtime. An exception occurring // within the scope must not be propagated back to the caller. - JVMCIEnv(JavaThread* thread, bool is_hotspot, bool jni_enomem_is_fatal, const char* file, int line) { - init(thread, is_hotspot, jni_enomem_is_fatal, file, line); + JVMCIEnv(JavaThread* thread, bool is_hotspot, const char* file, int line) { + init(thread, is_hotspot, file, line); } ~JVMCIEnv(); - // Determines if a JNI_ENOMEM occurred while trying to create a libjvmci - // isolate or attach to it within the scope of a JVMCIEnv constructor. - bool has_jni_enomem() { - return _jni_enomem; + // Gets the JNI result code returned when creating or attaching to a libjvmci isolate. + // If not JNI_OK, the JVMCIEnv is invalid and the caller must abort the operation + // this JVMCIEnv context was created for. + int init_error() { + return _init_error; } + // Checks the value of init_error() and throws an exception in `JVMCI_TRAPS` + // (which must not be this) if it is not JNI_OK. + void check_init(JVMCI_TRAPS); + + // Checks the value of init_error() and throws an exception in `TRAPS` + // if it is not JNI_OK. + void check_init(TRAPS); + JVMCIRuntime* runtime() { + guarantee(_init_error == 0, "invalid JVMCIEnv: %d", _init_error); return _runtime; } diff --git a/src/hotspot/share/jvmci/jvmciExceptions.hpp b/src/hotspot/share/jvmci/jvmciExceptions.hpp index 02dfb7924d1..2fd50c92486 100644 --- a/src/hotspot/share/jvmci/jvmciExceptions.hpp +++ b/src/hotspot/share/jvmci/jvmciExceptions.hpp @@ -31,15 +31,21 @@ class JVMCIEnv; #define JVMCIENV __jvmci_env__ #define JVMCI_TRAPS JVMCIEnv* JVMCIENV +#define PEER_JVMCIENV __peer_jvmci_env__ -#define JNI_JVMCIENV(thread, env) \ +#define JVMCIENV_FROM_JNI(thread, env) \ JVMCIEnv __stack_jvmci_env__(thread, env, __FILE__, __LINE__); \ JVMCIEnv* JVMCIENV = &__stack_jvmci_env__ -#define THREAD_JVMCIENV(thread) \ +#define JVMCIENV_FROM_THREAD(thread) \ JVMCIEnv __stack_jvmci_env__(thread, __FILE__, __LINE__); \ JVMCIEnv* JVMCIENV = &__stack_jvmci_env__ +#define PEER_JVMCIENV_FROM_THREAD(thread, is_hotspot) \ + JVMCIEnv __peer_stack_jvmci_env__(thread, is_hotspot, __FILE__, __LINE__); \ + JVMCIEnv* PEER_JVMCIENV = &__peer_stack_jvmci_env__ + + #define JVMCI_PENDING_EXCEPTION (JVMCIENV->pending_exception()) #define JVMCI_HAS_PENDING_EXCEPTION (JVMCIENV->has_pending_exception()) #define JVMCI_CLEAR_PENDING_EXCEPTION (JVMCIENV->clear_pending_exception()) diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index f8c3c432d83..31e1f259891 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -744,9 +744,10 @@ JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_call_int(JavaThread* current, int JRT_END -// private static JVMCIRuntime JVMCI.initializeRuntime() -JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) - JNI_JVMCIENV(thread, env); +// Implementation of JVMCI.initializeRuntime() +// When called from libjvmci, `libjvmciOrHotspotEnv` is a libjvmci env so use JVM_ENTRY_NO_ENV. +JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *libjvmciOrHotspotEnv, jclass c)) + JVMCIENV_FROM_JNI(thread, libjvmciOrHotspotEnv); if (!EnableJVMCI) { JVMCI_THROW_MSG_NULL(InternalError, "JVMCI is not enabled"); } @@ -755,9 +756,10 @@ JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) return JVMCIENV->get_jobject(runtime); JVM_END -// private static long Services.readSystemPropertiesInfo(int[] offsets) +// Implementation of Services.readSystemPropertiesInfo(int[] offsets) +// When called from libjvmci, `env` is a libjvmci env so use JVM_ENTRY_NO_ENV. JVM_ENTRY_NO_ENV(jlong, JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets_handle)) - JNI_JVMCIENV(thread, env); + JVMCIENV_FROM_JNI(thread, env); if (!EnableJVMCI) { JVMCI_THROW_MSG_0(InternalError, "JVMCI is not enabled"); } @@ -771,7 +773,8 @@ JVM_END void JVMCIRuntime::call_getCompiler(TRAPS) { - THREAD_JVMCIENV(JavaThread::current()); + JVMCIENV_FROM_THREAD(THREAD); + JVMCIENV->check_init(CHECK); JVMCIObject jvmciRuntime = JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_CHECK); initialize(JVMCI_CHECK); JVMCIENV->call_HotSpotJVMCIRuntime_getCompiler(jvmciRuntime, JVMCI_CHECK); @@ -1525,9 +1528,10 @@ JVMCIObject JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_TRAPS) { return _HotSpotJVMCIRuntime_instance; } -// private static void CompilerToVM.registerNatives() -JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass)) - JNI_JVMCIENV(thread, env); +// Implementation of CompilerToVM.registerNatives() +// When called from libjvmci, `libjvmciOrHotspotEnv` is a libjvmci env so use JVM_ENTRY_NO_ENV. +JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *libjvmciOrHotspotEnv, jclass c2vmClass)) + JVMCIENV_FROM_JNI(thread, libjvmciOrHotspotEnv); if (!EnableJVMCI) { JVMCI_THROW_MSG(InternalError, "JVMCI is not enabled"); @@ -1542,7 +1546,7 @@ JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass)) // Ensure _non_oop_bits is initialized Universe::non_oop_word(); - + JNIEnv *env = libjvmciOrHotspotEnv; if (JNI_OK != env->RegisterNatives(c2vmClass, CompilerToVM::methods, CompilerToVM::methods_count())) { if (!env->ExceptionCheck()) { for (int i = 0; i < CompilerToVM::methods_count(); i++) { @@ -1562,11 +1566,14 @@ JVM_END void JVMCIRuntime::shutdown() { if (_HotSpotJVMCIRuntime_instance.is_non_null()) { - bool jni_enomem_is_fatal = true; JVMCI_event_1("shutting down HotSpotJVMCIRuntime for JVMCI runtime %d", _id); - JVMCIEnv __stack_jvmci_env__(JavaThread::current(), _HotSpotJVMCIRuntime_instance.is_hotspot(), jni_enomem_is_fatal, __FILE__, __LINE__); + JVMCIEnv __stack_jvmci_env__(JavaThread::current(), _HotSpotJVMCIRuntime_instance.is_hotspot(),__FILE__, __LINE__); JVMCIEnv* JVMCIENV = &__stack_jvmci_env__; - JVMCIENV->call_HotSpotJVMCIRuntime_shutdown(_HotSpotJVMCIRuntime_instance); + if (JVMCIENV->init_error() == JNI_OK) { + JVMCIENV->call_HotSpotJVMCIRuntime_shutdown(_HotSpotJVMCIRuntime_instance); + } else { + JVMCI_event_1("Error in JVMCIEnv for shutdown (err: %d)", JVMCIENV->init_error()); + } if (_num_attached_threads == cannot_be_attached) { // Only when no other threads are attached to this runtime // is it safe to reset these fields. @@ -1611,7 +1618,8 @@ bool JVMCIRuntime::destroy_shared_library_javavm() { void JVMCIRuntime::bootstrap_finished(TRAPS) { if (_HotSpotJVMCIRuntime_instance.is_non_null()) { - THREAD_JVMCIENV(JavaThread::current()); + JVMCIENV_FROM_THREAD(THREAD); + JVMCIENV->check_init(CHECK); JVMCIENV->call_HotSpotJVMCIRuntime_bootstrapFinished(_HotSpotJVMCIRuntime_instance, JVMCIENV); } } From 6c821f5e1ddfae26c445f0cd5fe9205f49bfddee Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 4 Sep 2023 11:02:52 +0000 Subject: [PATCH 58/86] 8315545: C1: x86 cmove can use short branches Reviewed-by: adinn, kvn --- src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index cec75f210e9..5829d26aee5 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -2047,7 +2047,7 @@ void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, L } else { Label skip; - __ jcc (acond, skip); + __ jccb(acond, skip); if (opr2->is_cpu_register()) { reg2reg(opr2, result); } else if (opr2->is_stack()) { From 9def4538ab5456d689fd289bdef66fd1655773bc Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 4 Sep 2023 15:18:39 +0000 Subject: [PATCH 59/86] 8314580: PhaseIdealLoop::transform_long_range_checks fails with assert "was tested before" Reviewed-by: chagedorn, kvn --- src/hotspot/share/opto/loopnode.cpp | 8 +--- .../rangechecks/TestLongRCWithLoopIncr.java | 46 +++++++++++++++++++ 2 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestLongRCWithLoopIncr.java diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 393456b8eec..5107c6e9692 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -770,7 +770,7 @@ SafePointNode* PhaseIdealLoop::find_safepoint(Node* back_control, Node* x, Ideal // // inner_incr := AddI(inner_phi, intcon(stride)) // inner_incr = inner_phi + stride; // if (inner_incr < inner_iters_actual) { -// ... use phi=>(outer_phi+inner_phi) and incr=>(outer_phi+inner_incr) ... +// ... use phi=>(outer_phi+inner_phi) ... // continue; // } // else break; @@ -980,10 +980,6 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { // loop iv phi Node* iv_add = loop_nest_replace_iv(phi, inner_phi, outer_phi, head, bt); - // Replace inner loop long iv incr with inner loop int incr + outer - // loop iv phi - loop_nest_replace_iv(incr, inner_incr, outer_phi, head, bt); - set_subtree_ctrl(inner_iters_actual_int, body_populated); LoopNode* inner_head = create_inner_head(loop, head, exit_test); @@ -1032,7 +1028,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { // back_control: fallthrough; // else // inner_exit_branch: break; //exit_branch->clone() - // ... use phi=>(outer_phi+inner_phi) and incr=>(outer_phi+inner_incr) ... + // ... use phi=>(outer_phi+inner_phi) ... // inner_phi = inner_phi + stride; // inner_incr // } // outer_exit_test: //exit_test->clone(), in(0):=inner_exit_branch diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestLongRCWithLoopIncr.java b/test/hotspot/jtreg/compiler/rangechecks/TestLongRCWithLoopIncr.java new file mode 100644 index 00000000000..a91296bd997 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestLongRCWithLoopIncr.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8314580 + * @summary PhaseIdealLoop::transform_long_range_checks fails with assert "was tested before" + * @run main/othervm -XX:-BackgroundCompilation TestLongRCWithLoopIncr + * + */ + +import java.util.Objects; + +public class TestLongRCWithLoopIncr { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(1001); + } + } + + private static void test(long length) { + for (long i = 0; i < 1000; i++) { + Objects.checkIndex(i + 1, length); + } + } +} From f2922682688a40529df269e1551246ac8da5d7ee Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Tue, 5 Sep 2023 06:43:00 +0000 Subject: [PATCH 60/86] 8315454: Add a way to create an immutable snapshot of a BitSet Co-authored-by: Claes Redestad Reviewed-by: redestad --- .../share/classes/java/net/URLEncoder.java | 29 +++--- .../util/ImmutableBitSetPredicate.java | 85 +++++++++++++++++ .../jdk/java/util/BitSet/ImmutableBitSet.java | 92 +++++++++++++++++++ 3 files changed, 193 insertions(+), 13 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/util/ImmutableBitSetPredicate.java create mode 100644 test/jdk/java/util/BitSet/ImmutableBitSet.java diff --git a/src/java.base/share/classes/java/net/URLEncoder.java b/src/java.base/share/classes/java/net/URLEncoder.java index 1b5ff1cae26..41b9ae791fb 100644 --- a/src/java.base/share/classes/java/net/URLEncoder.java +++ b/src/java.base/share/classes/java/net/URLEncoder.java @@ -32,7 +32,9 @@ import java.nio.charset.UnsupportedCharsetException ; import java.util.BitSet; import java.util.Objects; +import java.util.function.IntPredicate; +import jdk.internal.util.ImmutableBitSetPredicate; import jdk.internal.util.StaticProperty; /** @@ -78,7 +80,7 @@ * @since 1.0 */ public class URLEncoder { - private static final BitSet DONT_NEED_ENCODING; + private static final IntPredicate DONT_NEED_ENCODING; private static final int CASE_DIFF = ('a' - 'A'); private static final String DEFAULT_ENCODING_NAME; @@ -120,17 +122,18 @@ public class URLEncoder { * */ - DONT_NEED_ENCODING = new BitSet(128); - - DONT_NEED_ENCODING.set('a', 'z' + 1); - DONT_NEED_ENCODING.set('A', 'Z' + 1); - DONT_NEED_ENCODING.set('0', '9' + 1); - DONT_NEED_ENCODING.set(' '); /* encoding a space to a + is done + var bitSet = new BitSet(128); + bitSet.set('a', 'z' + 1); + bitSet.set('A', 'Z' + 1); + bitSet.set('0', '9' + 1); + bitSet.set(' '); /* encoding a space to a + is done * in the encode() method */ - DONT_NEED_ENCODING.set('-'); - DONT_NEED_ENCODING.set('_'); - DONT_NEED_ENCODING.set('.'); - DONT_NEED_ENCODING.set('*'); + bitSet.set('-'); + bitSet.set('_'); + bitSet.set('.'); + bitSet.set('*'); + + DONT_NEED_ENCODING = ImmutableBitSetPredicate.of(bitSet); DEFAULT_ENCODING_NAME = StaticProperty.fileEncoding(); } @@ -226,7 +229,7 @@ public static String encode(String s, Charset charset) { for (int i = 0; i < s.length();) { int c = s.charAt(i); //System.out.println("Examining character: " + c); - if (DONT_NEED_ENCODING.get(c)) { + if (DONT_NEED_ENCODING.test(c)) { if (c == ' ') { c = '+'; needToChange = true; @@ -269,7 +272,7 @@ public static String encode(String s, Charset charset) { } } i++; - } while (i < s.length() && !DONT_NEED_ENCODING.get((c = s.charAt(i)))); + } while (i < s.length() && !DONT_NEED_ENCODING.test((c = s.charAt(i)))); charArrayWriter.flush(); String str = charArrayWriter.toString(); diff --git a/src/java.base/share/classes/jdk/internal/util/ImmutableBitSetPredicate.java b/src/java.base/share/classes/jdk/internal/util/ImmutableBitSetPredicate.java new file mode 100644 index 00000000000..4baeb8e31e3 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/util/ImmutableBitSetPredicate.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 jdk.internal.util; + +import jdk.internal.ValueBased; +import jdk.internal.vm.annotation.Stable; + +import java.util.BitSet; +import java.util.function.IntPredicate; + +/** + * Class for working with immutable BitSets. + */ +@ValueBased +public class ImmutableBitSetPredicate implements IntPredicate { + + @Stable + private final long[] words; + + private ImmutableBitSetPredicate(BitSet original) { + // If this class is made public, we need to do + // a defensive array copy as certain BitSet implementations + // may return a shared array. The spec says the array should be _new_ though but + // the consequences might be unspecified for a malicious BitSet. + this.words = original.toLongArray(); + } + + @Override + public boolean test(int bitIndex) { + if (bitIndex < 0) + throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); + + int wordIndex = wordIndex(bitIndex); + return (wordIndex < words.length) + && ((words[wordIndex] & (1L << bitIndex)) != 0); + } + + /** + * Given a bit index, return word index containing it. + */ + private static int wordIndex(int bitIndex) { + return bitIndex >> 6; + } + + /** + * {@return a new {@link IntPredicate } representing the {@link BitSet#get(int)} method applied + * on an immutable snapshot of the current state of this BitSet}. + *

+ * If the returned predicate is invoked with a {@code bitIndex} that is negative, the predicate + * will throw an IndexOutOfBoundsException just as the {@link BitSet#get(int)} method would. + *

+ * Returned predicates are threadsafe and can be used without external synchronisation. + * + * @implNote The method is free to return a {@link ValueBased} implementation. + * + * @since 22 + */ + public static IntPredicate of(BitSet original) { + return new ImmutableBitSetPredicate(original); + } + +} diff --git a/test/jdk/java/util/BitSet/ImmutableBitSet.java b/test/jdk/java/util/BitSet/ImmutableBitSet.java new file mode 100644 index 00000000000..7dde261ff5d --- /dev/null +++ b/test/jdk/java/util/BitSet/ImmutableBitSet.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Basic tests of immutable BitSets + * @modules java.base/jdk.internal.util + * @run junit ImmutableBitSet + */ + +import jdk.internal.util.ImmutableBitSetPredicate; +import org.junit.jupiter.api.Test; + +import java.util.BitSet; +import java.util.Random; +import java.util.function.IntPredicate; + +import static org.junit.jupiter.api.Assertions.*; + +public class ImmutableBitSet { + + @Test + void empty() { + BitSet bs = new BitSet(); + IntPredicate ibs = ImmutableBitSetPredicate.of(bs); + test(bs, ibs); + } + + @Test + void negativeIndex() { + BitSet bs = new BitSet(); + IntPredicate ibs = ImmutableBitSetPredicate.of(bs); + assertThrows(IndexOutOfBoundsException.class, () -> { + ibs.test(-1); + }); + } + + @Test + void basic() { + BitSet bs = createReference(147); + IntPredicate ibs = ImmutableBitSetPredicate.of(bs); + test(bs, ibs); + } + + @Test + void clearedAtTheTail() { + for (int i = Long.BYTES - 1; i < Long.BYTES + 2; i++) { + BitSet bs = createReference(i); + for (int j = bs.length() - 1; j > Long.BYTES - 1; j++) { + bs.clear(j); + } + IntPredicate ibs = ImmutableBitSetPredicate.of(bs); + test(bs, ibs); + } + } + + static void test(BitSet expected, IntPredicate actual) { + for (int i = 0; i < expected.length() + 17; i++) { + assertEquals(expected.get(i), actual.test(i), "at index " + i); + } + } + + private static BitSet createReference(int length) { + BitSet result = new BitSet(); + Random random = new Random(length); + for (int i = 0; i < length; i++) { + result.set(i, random.nextBoolean()); + } + return result; + } + +} \ No newline at end of file From 8bbebbba8fb870987295cb5f96147a9f9c5bfa6c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 5 Sep 2023 07:06:37 +0000 Subject: [PATCH 61/86] 8315644: increase timeout of sun/security/tools/jarsigner/Warning.java Reviewed-by: clanger, lucy --- test/jdk/sun/security/tools/jarsigner/Warning.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/sun/security/tools/jarsigner/Warning.java b/test/jdk/sun/security/tools/jarsigner/Warning.java index e7ed287e6ec..16e0b17a1b0 100644 --- a/test/jdk/sun/security/tools/jarsigner/Warning.java +++ b/test/jdk/sun/security/tools/jarsigner/Warning.java @@ -36,7 +36,7 @@ * @summary warnings, errors and -strict * @library /lib/testlibrary /test/lib * @build jdk.test.lib.util.JarUtils - * @run main Warning + * @run main/othervm/timeout=400 Warning */ public class Warning { From fe4f90021ffd44cb0af34f39d4ca0a7e44605c92 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 5 Sep 2023 07:32:51 +0000 Subject: [PATCH 62/86] 8315088: C2: assert(wq.size() - before == EMPTY_LOOP_SIZE) failed: expect the EMPTY_LOOP_SIZE nodes of this body if empty Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/loopTransform.cpp | 2 +- .../TestBrokenEmptyLoopLogic.java | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/loopstripmining/TestBrokenEmptyLoopLogic.java diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 33369e9deca..51647802efa 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -3530,7 +3530,7 @@ void IdealLoopTree::enqueue_data_nodes(PhaseIdealLoop* phase, Unique_Node_List& void IdealLoopTree::collect_loop_core_nodes(PhaseIdealLoop* phase, Unique_Node_List& wq) const { uint before = wq.size(); wq.push(_head->in(LoopNode::LoopBackControl)); - for (uint i = 0; i < wq.size(); ++i) { + for (uint i = before; i < wq.size(); ++i) { Node* n = wq.at(i); for (uint j = 0; j < n->req(); ++j) { Node* in = n->in(j); diff --git a/test/hotspot/jtreg/compiler/loopstripmining/TestBrokenEmptyLoopLogic.java b/test/hotspot/jtreg/compiler/loopstripmining/TestBrokenEmptyLoopLogic.java new file mode 100644 index 00000000000..cd720e0c76f --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopstripmining/TestBrokenEmptyLoopLogic.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8315088 + * @requires vm.compiler2.enabled + * @summary C2: assert(wq.size() - before == EMPTY_LOOP_SIZE) failed: expect the EMPTY_LOOP_SIZE nodes of this body if empty + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,TestBrokenEmptyLoopLogic::* -XX:-TieredCompilation TestBrokenEmptyLoopLogic + * + */ + +public class TestBrokenEmptyLoopLogic { + + public static void main(String[] strArr) { + for (int i = 0; i < 10000; i++) { + test(); + } + } + + static void test() { + int i8 = 209, i = 1, i12 = 1; + while (++i < 8) { + for (int j = 5; j > 1; j -= 2) { + i12 = 1; + do { + } while (++i12 < 3); + } + for (int j = i; j < 5; ++j) { + i8 += i12; + } + } + } +} From 69c9ec92d04a399946b2157690a1dc3fec517329 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Tue, 5 Sep 2023 08:30:03 +0000 Subject: [PATCH 63/86] 8314094: java/lang/ProcessHandle/InfoTest.java fails on Windows when run as user with Administrator privileges Reviewed-by: mbaesken, azeller --- .../jdk/java/lang/ProcessHandle/InfoTest.java | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/test/jdk/java/lang/ProcessHandle/InfoTest.java b/test/jdk/java/lang/ProcessHandle/InfoTest.java index e61b374e0cf..9901ee81592 100644 --- a/test/jdk/java/lang/ProcessHandle/InfoTest.java +++ b/test/jdk/java/lang/ProcessHandle/InfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,12 +39,13 @@ import java.util.Random; import java.util.concurrent.TimeUnit; -import jdk.test.lib.Platform; -import jdk.test.lib.Utils; import org.testng.Assert; import org.testng.TestNG; import org.testng.annotations.Test; +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; + /* * @test * @bug 8077350 8081566 8081567 8098852 8136597 @@ -81,7 +82,6 @@ public class InfoTest { } // Main can be used to run the tests from the command line with only testng.jar. - @SuppressWarnings("raw_types") public static void main(String[] args) { Class[] testclass = {InfoTest.class}; TestNG testng = new TestNG(); @@ -160,11 +160,7 @@ public static void test2() { ProcessHandle.Info info = p1.info(); System.out.printf(" info: %s%n", info); - if (info.user().isPresent()) { - String user = info.user().get(); - Assert.assertNotNull(user, "User name"); - Assert.assertEquals(user, whoami, "User name"); - } + assertUser(info); Optional command = info.command(); if (command.isPresent()) { @@ -291,11 +287,8 @@ public static void test3() { ProcessHandle.Info info = p.info(); System.out.printf(" info: %s%n", info); - if (info.user().isPresent()) { - String user = info.user().get(); - Assert.assertNotNull(user); - Assert.assertEquals(user, whoami); - } + assertUser(info); + if (info.command().isPresent()) { String command = info.command().get(); String expected = "sleep"; @@ -397,7 +390,7 @@ public static void test5() { Instant end = Instant.now().plusMillis(500L); while (end.isBefore(Instant.now())) { // burn the cpu time checking the time - long x = r.nextLong(); + r.nextLong(); } if (self.info().totalCpuDuration().isPresent()) { Duration totalCpu = self.info().totalCpuDuration().get(); @@ -410,6 +403,7 @@ public static void test5() { } } } + /** * Check two Durations, the second should be greater than the first or * within the supplied Epsilon. @@ -443,4 +437,31 @@ static Process spawn(String command, String... args) throws IOException { pb.command(list); return pb.start(); } + + /** + * Asserts the expected process user. + * + * The Expected user is determined by creating a file and reading its owner, see static block above. + * + * On Windows, when run privileged as member of the Administrators group, this does not always + * work because new files can be owned by BUILTIN\Administrators instead, depending on system + * settings. In that case we resort to comparing System property user.name, which does not contain + * the domain name, though. + * + * @param info ProcessHanlde info object + */ + static void assertUser(ProcessHandle.Info info) { + if (!info.user().isPresent()) { + return; + } + String user = info.user().get(); + Assert.assertNotNull(user, "User name"); + if (Platform.isWindows() && "BUILTIN\\Administrators".equals(whoami)) { + int bsi = user.lastIndexOf("\\"); + Assert.assertEquals(bsi == -1 ? user : user.substring(bsi + 1), + System.getProperty("user.name"), "User name"); + } else { + Assert.assertEquals(user, whoami, "User name"); + } + } } From 744b3970f92ff5942b5ad942831053b24367e67f Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Tue, 5 Sep 2023 08:48:39 +0000 Subject: [PATCH 64/86] 8312491: Update Classfile API snippets and examples Reviewed-by: jlahoda --- .../jdk/internal/classfile/Attribute.java | 1 + .../internal/classfile/AttributeMapper.java | 1 + .../jdk/internal/classfile/Attributes.java | 74 +- .../classfile/ClassHierarchyResolver.java | 4 +- .../jdk/internal/classfile/Classfile.java | 717 ++++++++++- .../internal/classfile/ClassfileBuilder.java | 2 + .../classfile/ClassfileTransform.java | 3 + .../jdk/internal/classfile/CodeBuilder.java | 1106 ++++++++++++++++- .../internal/classfile/CompoundElement.java | 1 + .../internal/classfile/CustomAttribute.java | 1 + .../jdk/internal/classfile/Opcode.java | 840 ++++++++++++- .../jdk/internal/classfile/Signature.java | 21 +- .../internal/classfile/TypeAnnotation.java | 220 +++- .../attribute/AnnotationDefaultAttribute.java | 4 + .../attribute/BootstrapMethodsAttribute.java | 4 + .../CharacterRangeTableAttribute.java | 2 + .../classfile/attribute/CodeAttribute.java | 4 + .../attribute/CompilationIDAttribute.java | 4 + .../attribute/ConstantValueAttribute.java | 4 + .../attribute/DeprecatedAttribute.java | 2 + .../attribute/EnclosingMethodAttribute.java | 4 + .../attribute/ExceptionsAttribute.java | 4 + .../attribute/InnerClassesAttribute.java | 4 + .../attribute/LineNumberTableAttribute.java | 2 + .../LocalVariableTableAttribute.java | 2 + .../LocalVariableTypeTableAttribute.java | 2 + .../attribute/MethodParametersAttribute.java | 4 + .../classfile/attribute/ModuleAttribute.java | 127 +- .../attribute/ModuleHashesAttribute.java | 4 + .../attribute/ModuleMainClassAttribute.java | 4 + .../classfile/attribute/ModuleOpenInfo.java | 3 + .../attribute/ModulePackagesAttribute.java | 4 + .../attribute/ModuleRequireInfo.java | 3 + .../attribute/ModuleResolutionAttribute.java | 5 + .../attribute/ModuleTargetAttribute.java | 4 + .../attribute/NestHostAttribute.java | 4 + .../attribute/NestMembersAttribute.java | 4 + .../PermittedSubclassesAttribute.java | 4 + .../classfile/attribute/RecordAttribute.java | 4 + .../RuntimeInvisibleAnnotationsAttribute.java | 4 + ...nvisibleParameterAnnotationsAttribute.java | 4 + ...timeInvisibleTypeAnnotationsAttribute.java | 4 + .../RuntimeVisibleAnnotationsAttribute.java | 4 + ...eVisibleParameterAnnotationsAttribute.java | 4 + ...untimeVisibleTypeAnnotationsAttribute.java | 4 + .../attribute/SignatureAttribute.java | 4 + .../SourceDebugExtensionAttribute.java | 6 +- .../attribute/SourceFileAttribute.java | 12 + .../attribute/SourceIDAttribute.java | 6 +- .../attribute/StackMapFrameInfo.java | 60 +- .../attribute/StackMapTableAttribute.java | 8 + .../attribute/SyntheticAttribute.java | 2 + .../instruction/BranchInstruction.java | 1 + .../classfile/instruction/LabelTarget.java | 4 + .../instruction/LoadInstruction.java | 7 + .../classfile/instruction/LocalVariable.java | 6 + .../instruction/LocalVariableType.java | 6 + .../instruction/ReturnInstruction.java | 4 + .../instruction/StoreInstruction.java | 8 + .../instruction/TypeCheckInstruction.java | 4 + .../jdk/internal/classfile/package-info.java | 18 +- .../snippet-files/PackageSnippets.java | 82 +- 62 files changed, 3385 insertions(+), 84 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/Attribute.java b/src/java.base/share/classes/jdk/internal/classfile/Attribute.java index 343ba9677e2..13df75e1514 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Attribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Attribute.java @@ -72,6 +72,7 @@ * corresponding model type. Additionally, all attributes are accessible * directly from the corresponding model type through {@link * AttributedElement#findAttribute(AttributeMapper)}. + * @param the attribute type */ public sealed interface Attribute> extends WritableElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/AttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/AttributeMapper.java index eea5877a4e8..8892b56ed60 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/AttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/AttributeMapper.java @@ -33,6 +33,7 @@ * attributes, clients can define their own {@linkplain AttributeMapper}. * Classes that model nonstandard attributes should extend {@link * CustomAttribute}. + * @param the attribute type */ public interface AttributeMapper { diff --git a/src/java.base/share/classes/jdk/internal/classfile/Attributes.java b/src/java.base/share/classes/jdk/internal/classfile/Attributes.java index 2a816e5df1b..699da664a9b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Attributes.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Attributes.java @@ -91,41 +91,113 @@ * @see AttributeMapper */ public class Attributes { + + /** AnnotationDefault */ public static final String NAME_ANNOTATION_DEFAULT = "AnnotationDefault"; + + /** BootstrapMethods */ public static final String NAME_BOOTSTRAP_METHODS = "BootstrapMethods"; + + /** CharacterRangeTable */ public static final String NAME_CHARACTER_RANGE_TABLE = "CharacterRangeTable"; + + /** Code */ public static final String NAME_CODE = "Code"; + + /** CompilationID */ public static final String NAME_COMPILATION_ID = "CompilationID"; + + /** ConstantValue */ public static final String NAME_CONSTANT_VALUE = "ConstantValue"; + + /** Deprecated */ public static final String NAME_DEPRECATED = "Deprecated"; + + /** EnclosingMethod */ public static final String NAME_ENCLOSING_METHOD = "EnclosingMethod"; + + /** Exceptions */ public static final String NAME_EXCEPTIONS = "Exceptions"; + + /** InnerClasses */ public static final String NAME_INNER_CLASSES = "InnerClasses"; + + /** LineNumberTable */ public static final String NAME_LINE_NUMBER_TABLE = "LineNumberTable"; + + /** LocalVariableTable */ public static final String NAME_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; + + /** LocalVariableTypeTable */ public static final String NAME_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; + + /** MethodParameters */ public static final String NAME_METHOD_PARAMETERS = "MethodParameters"; + + /** Module */ public static final String NAME_MODULE = "Module"; + + /** ModuleHashes */ public static final String NAME_MODULE_HASHES = "ModuleHashes"; + + /** ModuleMainClass */ public static final String NAME_MODULE_MAIN_CLASS = "ModuleMainClass"; + + /** ModulePackages */ public static final String NAME_MODULE_PACKAGES = "ModulePackages"; + + /** ModuleResolution */ public static final String NAME_MODULE_RESOLUTION = "ModuleResolution"; + + /** ModuleTarget */ public static final String NAME_MODULE_TARGET = "ModuleTarget"; + + /** NestHost */ public static final String NAME_NEST_HOST = "NestHost"; + + /** NestMembers */ public static final String NAME_NEST_MEMBERS = "NestMembers"; + + /** PermittedSubclasses */ public static final String NAME_PERMITTED_SUBCLASSES = "PermittedSubclasses"; + + /** Record */ public static final String NAME_RECORD = "Record"; + + /** RuntimeInvisibleAnnotations */ public static final String NAME_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; + + /** RuntimeInvisibleTypeAnnotations */ public static final String NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; + + /** */ public static final String NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations"; + + /** RuntimeVisibleAnnotations */ public static final String NAME_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; + + /** RuntimeVisibleParameterAnnotations */ public static final String NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; + + /** RuntimeVisibleTypeAnnotations */ public static final String NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations"; + + /** Signature */ public static final String NAME_SIGNATURE = "Signature"; + + /** SourceDebugExtension */ public static final String NAME_SOURCE_DEBUG_EXTENSION = "SourceDebugExtension"; + + /** SourceFile */ public static final String NAME_SOURCE_FILE = "SourceFile"; + + /** SourceID */ public static final String NAME_SOURCE_ID = "SourceID"; + + /** StackMapTable */ public static final String NAME_STACK_MAP_TABLE = "StackMapTable"; + + /** Synthetic */ public static final String NAME_SYNTHETIC = "Synthetic"; private Attributes() { @@ -712,7 +784,7 @@ protected void writeBody(BufWriter b, StackMapTableAttribute attr) { /** Attribute mapper for the {@code Synthetic} attribute */ public static final AttributeMapper - SYNTHETIC = new AbstractAttributeMapper<>(NAME_SYNTHETIC) { + SYNTHETIC = new AbstractAttributeMapper<>(NAME_SYNTHETIC, true) { @Override public SyntheticAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { return new BoundAttribute.BoundSyntheticAttribute(cf, this, p); diff --git a/src/java.base/share/classes/jdk/internal/classfile/ClassHierarchyResolver.java b/src/java.base/share/classes/jdk/internal/classfile/ClassHierarchyResolver.java index 94fba9b9ef5..f1c072a2f41 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/ClassHierarchyResolver.java +++ b/src/java.base/share/classes/jdk/internal/classfile/ClassHierarchyResolver.java @@ -48,8 +48,8 @@ public interface ClassHierarchyResolver { /** - * Returns a default instance of {@linkplain ClassHierarchyResolver} that - * gets {@link ClassHierarchyInfo} from system class loader with reflection. + * {@return the default instance of {@linkplain ClassHierarchyResolver} that + * gets {@link ClassHierarchyInfo} from system class loader with reflection} */ static ClassHierarchyResolver defaultResolver() { return ClassHierarchyImpl.DEFAULT_RESOLVER; diff --git a/src/java.base/share/classes/jdk/internal/classfile/Classfile.java b/src/java.base/share/classes/jdk/internal/classfile/Classfile.java index e7cc0628cbe..f8913f99b51 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Classfile.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Classfile.java @@ -96,6 +96,9 @@ static AttributeMapperOption of(Function> attribut return new ClassfileImpl.AttributeMapperOptionImpl(attributeMapper); } + /** + * {@return the function mapping attribute names to attribute mappers} + */ Function> attributeMapper(); } @@ -116,6 +119,9 @@ static ClassHierarchyResolverOption of(ClassHierarchyResolver classHierarchyReso return new ClassfileImpl.ClassHierarchyResolverOptionImpl(classHierarchyResolver); } + /** + * {@return the class hierarchy resolver} + */ ClassHierarchyResolver classHierarchyResolver(); } @@ -129,7 +135,11 @@ static ClassHierarchyResolverOption of(ClassHierarchyResolver classHierarchyReso * pool. */ enum ConstantPoolSharingOption implements Option { + + /** Preserves the original constant pool when transforming classfile */ SHARED_POOL, + + /** Creates a new constant pool when transforming classfile */ NEW_POOL } @@ -139,7 +149,11 @@ enum ConstantPoolSharingOption implements Option { * code with NOPs. */ enum DeadCodeOption implements Option { + + /** Patch unreachable code */ PATCH_DEAD_CODE, + + /** Keep the unreachable code */ KEEP_DEAD_CODE } @@ -153,7 +167,11 @@ enum DeadCodeOption implements Option { * elements instead. */ enum DeadLabelsOption implements Option { + + /** Fail on unresolved labels */ FAIL_ON_DEAD_LABELS, + + /** Filter unresolved labels */ DROP_DEAD_LABELS } @@ -165,7 +183,11 @@ enum DeadLabelsOption implements Option { * Default is {@code PASS_DEBUG} to process debug elements. */ enum DebugElementsOption implements Option { + + /** Process debug elements */ PASS_DEBUG, + + /** Drop debug elements */ DROP_DEBUG } @@ -176,7 +198,11 @@ enum DebugElementsOption implements Option { * Default is {@code PASS_LINE_NUMBERS} to process line numbers. */ enum LineNumbersOption implements Option { + + /** Process line numbers */ PASS_LINE_NUMBERS, + + /** Drop line numbers */ DROP_LINE_NUMBERS; } @@ -187,7 +213,11 @@ enum LineNumbersOption implements Option { * instructions. */ enum ShortJumpsOption implements Option { + + /** Automatically convert short jumps to long when necessary */ FIX_SHORT_JUMPS, + + /** Fail if short jump overflows */ FAIL_ON_SHORT_JUMPS } @@ -199,8 +229,14 @@ enum ShortJumpsOption implements Option { * @jvms 4.10.1 Verification by Type Checking */ enum StackMapsOption implements Option { + + /** Generate stack maps when required */ STACK_MAPS_WHEN_REQUIRED, + + /** Always generate stack maps */ GENERATE_STACK_MAPS, + + /** Drop stack maps from code */ DROP_STACK_MAPS } @@ -210,7 +246,11 @@ enum StackMapsOption implements Option { * attributes, and deliver as instances of {@link UnknownAttribute}. */ enum UnknownAttributesOption implements Option { + + /** Process unknown attributes */ PASS_UNKNOWN_ATTRIBUTES, + + /** Drop unknown attributes */ DROP_UNKNOWN_ATTRIBUTES } @@ -225,6 +265,7 @@ enum UnknownAttributesOption implements Option { * Parse a classfile into a {@link ClassModel}. * @param path the path to the classfile * @return the class model + * @throws java.io.IOException */ default ClassModel parse(Path path) throws IOException { return parse(Files.readAllBytes(path)); @@ -260,6 +301,7 @@ byte[] build(ClassEntry thisClassEntry, * @param path the path to the file to write * @param thisClass the name of the class to build * @param handler a handler that receives a {@link ClassBuilder} + * @throws java.io.IOException */ default void buildTo(Path path, ClassDesc thisClass, @@ -275,6 +317,7 @@ default void buildTo(Path path, * @param thisClassEntry the name of the class to build * @param constantPool the constant pool builder * @param handler a handler that receives a {@link ClassBuilder} + * @throws java.io.IOException */ default void buildTo(Path path, ClassEntry thisClassEntry, @@ -311,6 +354,7 @@ default byte[] buildModule(ModuleAttribute moduleAttribute, * Build a module descriptor into a file. * @param path the file to write * @param moduleAttribute the {@code Module} attribute + * @throws java.io.IOException */ default void buildModuleTo(Path path, ModuleAttribute moduleAttribute) throws IOException { @@ -322,6 +366,7 @@ default void buildModuleTo(Path path, * @param path the file to write * @param moduleAttribute the {@code Module} attribute * @param handler a handler that receives a {@link ClassBuilder} + * @throws java.io.IOException */ default void buildModuleTo(Path path, ModuleAttribute moduleAttribute, @@ -343,7 +388,7 @@ default void buildModuleTo(Path path, * b -> b.transform(model, transform)); * } * - * @param model class model to transform + * @param model the class model to transform * @param transform the transform * @return the bytes of the new class */ @@ -351,343 +396,1007 @@ default byte[] transform(ClassModel model, ClassTransform transform) { return transform(model, model.thisClass(), transform); } + /** + * Transform one classfile into a new classfile with the aid of a + * {@link ClassTransform}. The transform will receive each element of + * this class, as well as a {@link ClassBuilder} for building the new class. + * The transform is free to preserve, remove, or replace elements as it + * sees fit. + * + * @param model the class model to transform + * @param newClassName new class name + * @param transform the transform + * @return the bytes of the new class + */ default byte[] transform(ClassModel model, ClassDesc newClassName, ClassTransform transform) { return transform(model, TemporaryConstantPool.INSTANCE.classEntry(newClassName), transform); } + /** + * Transform one classfile into a new classfile with the aid of a + * {@link ClassTransform}. The transform will receive each element of + * this class, as well as a {@link ClassBuilder} for building the new class. + * The transform is free to preserve, remove, or replace elements as it + * sees fit. + * + * @implNote + * This method behaves as if: + * {@snippet lang=java : + * this.build(newClassName, ConstantPoolBuilder.of(model), + * b -> b.transform(model, transform)); + * } + * + * @param model the class model to transform + * @param newClassName new class name + * @param transform the transform + * @return the bytes of the new class + */ byte[] transform(ClassModel model, ClassEntry newClassName, ClassTransform transform); + /** 0xCAFEBABE */ int MAGIC_NUMBER = 0xCAFEBABE; + /** 0 */ int NOP = 0; + + /** 1 */ int ACONST_NULL = 1; + + /** 2 */ int ICONST_M1 = 2; + + /** 3 */ int ICONST_0 = 3; + + /** 4 */ int ICONST_1 = 4; + + /** 5 */ int ICONST_2 = 5; + + /** 6 */ int ICONST_3 = 6; + + /** 7 */ int ICONST_4 = 7; + + /** 8 */ int ICONST_5 = 8; + + /** 9 */ int LCONST_0 = 9; + + /** 10 */ int LCONST_1 = 10; + + /** 11 */ int FCONST_0 = 11; + + /** 12 */ int FCONST_1 = 12; + + /** 13 */ int FCONST_2 = 13; + + /** 14 */ int DCONST_0 = 14; + + /** 15 */ int DCONST_1 = 15; + + /** 16 */ int BIPUSH = 16; + + /** 17 */ int SIPUSH = 17; + + /** 18 */ int LDC = 18; + + /** 19 */ int LDC_W = 19; + + /** 20 */ int LDC2_W = 20; + + /** 21 */ int ILOAD = 21; + + /** 22 */ int LLOAD = 22; + + /** 23 */ int FLOAD = 23; + + /** 24 */ int DLOAD = 24; + + /** 25 */ int ALOAD = 25; + + /** 26 */ int ILOAD_0 = 26; + + /** 27 */ int ILOAD_1 = 27; + + /** 28 */ int ILOAD_2 = 28; + + /** 29 */ int ILOAD_3 = 29; + + /** 30 */ int LLOAD_0 = 30; + + /** 31 */ int LLOAD_1 = 31; + + /** 32 */ int LLOAD_2 = 32; + + /** 33 */ int LLOAD_3 = 33; + + /** 34 */ int FLOAD_0 = 34; + + /** 35 */ int FLOAD_1 = 35; + + /** 36 */ int FLOAD_2 = 36; + + /** 37 */ int FLOAD_3 = 37; + + /** 38 */ int DLOAD_0 = 38; + + /** 39 */ int DLOAD_1 = 39; + + /** 40 */ int DLOAD_2 = 40; + + /** 41 */ int DLOAD_3 = 41; + + /** 42 */ int ALOAD_0 = 42; + + /** 43 */ int ALOAD_1 = 43; + + /** 44 */ int ALOAD_2 = 44; + + /** 45 */ int ALOAD_3 = 45; + + /** 46 */ int IALOAD = 46; + + /** 47 */ int LALOAD = 47; + + /** 48 */ int FALOAD = 48; + + /** 49 */ int DALOAD = 49; + + /** 50 */ int AALOAD = 50; + + /** 51 */ int BALOAD = 51; + + /** 52 */ int CALOAD = 52; + + /** 53 */ int SALOAD = 53; + + /** 54 */ int ISTORE = 54; + + /** 55 */ int LSTORE = 55; + + /** 56 */ int FSTORE = 56; + + /** 57 */ int DSTORE = 57; + + /** 58 */ int ASTORE = 58; + + /** 59 */ int ISTORE_0 = 59; + + /** 60 */ int ISTORE_1 = 60; + + /** 61 */ int ISTORE_2 = 61; + + /** 62 */ int ISTORE_3 = 62; + + /** 63 */ int LSTORE_0 = 63; + + /** 64 */ int LSTORE_1 = 64; + + /** 65 */ int LSTORE_2 = 65; + + /** 66 */ int LSTORE_3 = 66; + + /** 67 */ int FSTORE_0 = 67; + + /** 68 */ int FSTORE_1 = 68; + + /** 69 */ int FSTORE_2 = 69; + + /** 70 */ int FSTORE_3 = 70; + + /** 71 */ int DSTORE_0 = 71; + + /** 72 */ int DSTORE_1 = 72; + + /** 73 */ int DSTORE_2 = 73; + + /** 74 */ int DSTORE_3 = 74; + + /** 75 */ int ASTORE_0 = 75; + + /** 76 */ int ASTORE_1 = 76; + + /** 77 */ int ASTORE_2 = 77; + + /** 78 */ int ASTORE_3 = 78; + + /** 79 */ int IASTORE = 79; + + /** 80 */ int LASTORE = 80; + + /** 81 */ int FASTORE = 81; + + /** 82 */ int DASTORE = 82; + + /** 83 */ int AASTORE = 83; + + /** 84 */ int BASTORE = 84; + + /** 85 */ int CASTORE = 85; + + /** 86 */ int SASTORE = 86; + + /** 87 */ int POP = 87; + + /** 88 */ int POP2 = 88; + + /** 89 */ int DUP = 89; + + /** 90 */ int DUP_X1 = 90; + + /** 91 */ int DUP_X2 = 91; + + /** 92 */ int DUP2 = 92; + + /** 93 */ int DUP2_X1 = 93; + + /** 94 */ int DUP2_X2 = 94; + + /** 95 */ int SWAP = 95; + + /** 96 */ int IADD = 96; + + /** 97 */ int LADD = 97; + + /** 98 */ int FADD = 98; + + /** 99 */ int DADD = 99; + + /** 100 */ int ISUB = 100; + + /** 101 */ int LSUB = 101; + + /** 102 */ int FSUB = 102; + + /** 103 */ int DSUB = 103; + + /** 104 */ int IMUL = 104; + + /** 105 */ int LMUL = 105; + + /** 106 */ int FMUL = 106; + + /** 107 */ int DMUL = 107; + + /** 108 */ int IDIV = 108; + + /** 109 */ int LDIV = 109; + + /** 110 */ int FDIV = 110; + + /** 111 */ int DDIV = 111; + + /** 112 */ int IREM = 112; + + /** 113 */ int LREM = 113; + + /** 114 */ int FREM = 114; + + /** 115 */ int DREM = 115; + + /** 116 */ int INEG = 116; + + /** 117 */ int LNEG = 117; + + /** 118 */ int FNEG = 118; + + /** 119 */ int DNEG = 119; + + /** 120 */ int ISHL = 120; + + /** 121 */ int LSHL = 121; + + /** 122 */ int ISHR = 122; + + /** 123 */ int LSHR = 123; + + /** 124 */ int IUSHR = 124; + + /** 125 */ int LUSHR = 125; + + /** 126 */ int IAND = 126; + + /** 127 */ int LAND = 127; + + /** 128 */ int IOR = 128; + + /** 129 */ int LOR = 129; + + /** 130 */ int IXOR = 130; + + /** 131 */ int LXOR = 131; + + /** 132 */ int IINC = 132; + + /** 133 */ int I2L = 133; + + /** 134 */ int I2F = 134; + + /** 135 */ int I2D = 135; + + /** 136 */ int L2I = 136; + + /** 137 */ int L2F = 137; + + /** 138 */ int L2D = 138; + + /** 139 */ int F2I = 139; + + /** 140 */ int F2L = 140; + + /** 141 */ int F2D = 141; + + /** 142 */ int D2I = 142; + + /** 143 */ int D2L = 143; + + /** 144 */ int D2F = 144; + + /** 145 */ int I2B = 145; + + /** 146 */ int I2C = 146; + + /** 147 */ int I2S = 147; + + /** 148 */ int LCMP = 148; + + /** 149 */ int FCMPL = 149; + + /** 150 */ int FCMPG = 150; + + /** 151 */ int DCMPL = 151; + + /** 152 */ int DCMPG = 152; + + /** 153 */ int IFEQ = 153; + + /** 154 */ int IFNE = 154; + + /** 155 */ int IFLT = 155; + + /** 156 */ int IFGE = 156; + + /** 157 */ int IFGT = 157; + + /** 158 */ int IFLE = 158; + + /** 159 */ int IF_ICMPEQ = 159; + + /** 160 */ int IF_ICMPNE = 160; + + /** 161 */ int IF_ICMPLT = 161; + + /** 162 */ int IF_ICMPGE = 162; + + /** 163 */ int IF_ICMPGT = 163; + + /** 164 */ int IF_ICMPLE = 164; + + /** 165 */ int IF_ACMPEQ = 165; + + /** 166 */ int IF_ACMPNE = 166; + + /** 167 */ int GOTO = 167; + + /** 168 */ int JSR = 168; + + /** 169 */ int RET = 169; + + /** 170 */ int TABLESWITCH = 170; + + /** 171 */ int LOOKUPSWITCH = 171; + + /** 172 */ int IRETURN = 172; + + /** 173 */ int LRETURN = 173; + + /** 174 */ int FRETURN = 174; + + /** 175 */ int DRETURN = 175; + + /** 176 */ int ARETURN = 176; + + /** 177 */ int RETURN = 177; + + /** 178 */ int GETSTATIC = 178; + + /** 179 */ int PUTSTATIC = 179; + + /** 180 */ int GETFIELD = 180; + + /** 181 */ int PUTFIELD = 181; + + /** 182 */ int INVOKEVIRTUAL = 182; + + /** 183 */ int INVOKESPECIAL = 183; + + /** 184 */ int INVOKESTATIC = 184; + + /** 185 */ int INVOKEINTERFACE = 185; + + /** 186 */ int INVOKEDYNAMIC = 186; + + /** 187 */ int NEW = 187; + + /** 188 */ int NEWARRAY = 188; + + /** 189 */ int ANEWARRAY = 189; + + /** 190 */ int ARRAYLENGTH = 190; + + /** 191 */ int ATHROW = 191; + + /** 192 */ int CHECKCAST = 192; + + /** 193 */ int INSTANCEOF = 193; + + /** 194 */ int MONITORENTER = 194; + + /** 195 */ int MONITOREXIT = 195; + + /** 196 */ int WIDE = 196; + + /** 197 */ int MULTIANEWARRAY = 197; + + /** 198 */ int IFNULL = 198; + + /** 199 */ int IFNONNULL = 199; + + /** 200 */ int GOTO_W = 200; + + /** 201 */ int JSR_W = 201; + /** 0x0001 */ int ACC_PUBLIC = 0x0001; + + /** 0x0004 */ int ACC_PROTECTED = 0x0004; + + /** 0x0002 */ int ACC_PRIVATE = 0x0002; + + /** 0x0200 */ int ACC_INTERFACE = 0x0200; + + /** 0x4000 */ int ACC_ENUM = 0x4000; + + /** 0x2000 */ int ACC_ANNOTATION = 0x2000; + + /** 0x0020 */ int ACC_SUPER = 0x0020; + + /** 0x0400 */ int ACC_ABSTRACT = 0x0400; + + /** 0x0040 */ int ACC_VOLATILE = 0x0040; + + /** 0x0080 */ int ACC_TRANSIENT = 0x0080; + + /** 0x1000 */ int ACC_SYNTHETIC = 0x1000; + + /** 0x0008 */ int ACC_STATIC = 0x0008; + + /** 0x0010 */ int ACC_FINAL = 0x0010; + + /** 0x0020 */ int ACC_SYNCHRONIZED = 0x0020; + + /** 0x0040 */ int ACC_BRIDGE = 0x0040; + + /** 0x0080 */ int ACC_VARARGS = 0x0080; + + /** 0x0100 */ int ACC_NATIVE = 0x0100; + + /** 0x0800 */ int ACC_STRICT = 0x0800; + + /** 0x8000 */ int ACC_MODULE = 0x8000; + + /** 0x20 */ int ACC_OPEN = 0x20; + + /** 0x8000 */ int ACC_MANDATED = 0x8000; + + /** 0x20 */ int ACC_TRANSITIVE = 0x20; + + /** 0x40 */ int ACC_STATIC_PHASE = 0x40; + /** 0x0001 */ int CRT_STATEMENT = 0x0001; + + /** 0x0002 */ int CRT_BLOCK = 0x0002; + + /** 0x0004 */ int CRT_ASSIGNMENT = 0x0004; + + /** 0x0008 */ int CRT_FLOW_CONTROLLER = 0x0008; + + /** 0x0010 */ int CRT_FLOW_TARGET = 0x0010; + + /** 0x0020 */ int CRT_INVOKE = 0x0020; + + /** 0x0040 */ int CRT_CREATE = 0x0040; + + /** 0x0080 */ int CRT_BRANCH_TRUE = 0x0080; + + /** 0x0100 */ int CRT_BRANCH_FALSE = 0x0100; + /** 7 */ int TAG_CLASS = 7; + + /** 17 */ int TAG_CONSTANTDYNAMIC = 17; + + /** 6 */ int TAG_DOUBLE = 6; + + /** 9 */ int TAG_FIELDREF = 9; + + /** 4 */ int TAG_FLOAT = 4; + + /** 3 */ int TAG_INTEGER = 3; + + /** 11 */ int TAG_INTERFACEMETHODREF = 11; + + /** 18 */ int TAG_INVOKEDYNAMIC = 18; + + /** 5 */ int TAG_LONG = 5; + + /** 15 */ int TAG_METHODHANDLE = 15; + + /** 10 */ int TAG_METHODREF = 10; + + /** 16 */ int TAG_METHODTYPE = 16; + + /** 19 */ int TAG_MODULE = 19; + + /** 12 */ int TAG_NAMEANDTYPE = 12; + + /** 20 */ int TAG_PACKAGE = 20; + + /** 8 */ int TAG_STRING = 8; + + /** 2 */ int TAG_UNICODE = 2; + + /** 1 */ int TAG_UTF8 = 1; // annotation element values + + /** 'B' */ char AEV_BYTE = 'B'; + + /** 'C' */ char AEV_CHAR = 'C'; + + /** 'D' */ char AEV_DOUBLE = 'D'; + + /** 'F' */ char AEV_FLOAT = 'F'; + + /** 'I' */ char AEV_INT = 'I'; + + /** 'J' */ char AEV_LONG = 'J'; + + /** 'S' */ char AEV_SHORT = 'S'; + + /** 'Z' */ char AEV_BOOLEAN = 'Z'; + + /** 's' */ char AEV_STRING = 's'; + + /** 'e' */ char AEV_ENUM = 'e'; + + /** 'c' */ char AEV_CLASS = 'c'; + + /** '@' */ char AEV_ANNOTATION = '@'; + + /** '[' */ char AEV_ARRAY = '['; //type annotations + + /** 0x00 */ int TAT_CLASS_TYPE_PARAMETER = 0x00; + + /** 0x01 */ int TAT_METHOD_TYPE_PARAMETER = 0x01; + + /** 0x10 */ int TAT_CLASS_EXTENDS = 0x10; + + /** 0x11 */ int TAT_CLASS_TYPE_PARAMETER_BOUND = 0x11; + + /** 0x12 */ int TAT_METHOD_TYPE_PARAMETER_BOUND = 0x12; + + /** 0x13 */ int TAT_FIELD = 0x13; + + /** 0x14 */ int TAT_METHOD_RETURN = 0x14; + + /** 0x15 */ int TAT_METHOD_RECEIVER = 0x15; + + /** 0x16 */ int TAT_METHOD_FORMAL_PARAMETER = 0x16; + + /** 0x17 */ int TAT_THROWS = 0x17; + + /** 0x40 */ int TAT_LOCAL_VARIABLE = 0x40; + + /** 0x41 */ int TAT_RESOURCE_VARIABLE = 0x41; + + /** 0x42 */ int TAT_EXCEPTION_PARAMETER = 0x42; + + /** 0x43 */ int TAT_INSTANCEOF = 0x43; + + /** 0x44 */ int TAT_NEW = 0x44; + + /** 0x45 */ int TAT_CONSTRUCTOR_REFERENCE = 0x45; + + /** 0x46 */ int TAT_METHOD_REFERENCE = 0x46; + + /** 0x47 */ int TAT_CAST = 0x47; + + /** 0x48 */ int TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + + /** 0x49 */ int TAT_METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + + /** 0x4A */ int TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + + /** 0x4B */ int TAT_METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; //stackmap verification types + + /** 0 */ int VT_TOP = 0; + + /** 1 */ int VT_INTEGER = 1; + + /** 2 */ int VT_FLOAT = 2; + + /** 3 */ int VT_DOUBLE = 3; + + /** 4 */ int VT_LONG = 4; + + /** 5 */ int VT_NULL = 5; + + /** 6 */ int VT_UNINITIALIZED_THIS = 6; + + /** 7 */ int VT_OBJECT = 7; + + /** 8 */ int VT_UNINITIALIZED = 8; + /** ACC_PUBLIC */ int DEFAULT_CLASS_FLAGS = ACC_PUBLIC; + /** 45 */ int JAVA_1_VERSION = 45; + + /** 46 */ int JAVA_2_VERSION = 46; + + /** 47 */ int JAVA_3_VERSION = 47; + + /** 48 */ int JAVA_4_VERSION = 48; + + /** 49 */ int JAVA_5_VERSION = 49; + + /** 50 */ int JAVA_6_VERSION = 50; + + /** 51 */ int JAVA_7_VERSION = 51; + + /** 52 */ int JAVA_8_VERSION = 52; + + /** 53 */ int JAVA_9_VERSION = 53; + + /** 54 */ int JAVA_10_VERSION = 54; + + /** 55 */ int JAVA_11_VERSION = 55; + + /** 56 */ int JAVA_12_VERSION = 56; + + /** 57 */ int JAVA_13_VERSION = 57; + + /** 58 */ int JAVA_14_VERSION = 58; + + /** 59 */ int JAVA_15_VERSION = 59; + + /** 60 */ int JAVA_16_VERSION = 60; + + /** 61 */ int JAVA_17_VERSION = 61; + + /** 62 */ int JAVA_18_VERSION = 62; + + /** 63 */ int JAVA_19_VERSION = 63; + + /** 64 */ int JAVA_20_VERSION = 64; + + /** 65 */ int JAVA_21_VERSION = 65; + + /** 66 */ int JAVA_22_VERSION = 66; /** @@ -697,10 +1406,16 @@ default byte[] transform(ClassModel model, ClassDesc newClassName, ClassTransfor */ int PREVIEW_MINOR_VERSION = 65535; + /** + * {@return the latest major Java version} + */ static int latestMajorVersion() { return JAVA_22_VERSION; } + /** + * {@return the latest minor Java version} + */ static int latestMinorVersion() { return 0; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/ClassfileBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/ClassfileBuilder.java index 241470e6d9c..965bfb293e7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/ClassfileBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/ClassfileBuilder.java @@ -38,6 +38,8 @@ * abstractly (by passing a {@link ClassfileElement} to {@link #with(ClassfileElement)} * or concretely by calling the various {@code withXxx} methods. * + * @param the element type + * @param the builder type * @see ClassfileTransform */ public sealed interface ClassfileBuilder> diff --git a/src/java.base/share/classes/jdk/internal/classfile/ClassfileTransform.java b/src/java.base/share/classes/jdk/internal/classfile/ClassfileTransform.java index 3443baf94fd..299e5153835 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/ClassfileTransform.java +++ b/src/java.base/share/classes/jdk/internal/classfile/ClassfileTransform.java @@ -68,6 +68,9 @@ *

* Complex class instrumentation sample chaining multiple transformations: * {@snippet lang="java" class="PackageSnippets" region="classInstrumentation"} + * @param the transform type + * @param the element type + * @param the builder type */ public sealed interface ClassfileTransform< C extends ClassfileTransform, diff --git a/src/java.base/share/classes/jdk/internal/classfile/CodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/CodeBuilder.java index 30534394b9d..3379e673e73 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/CodeBuilder.java @@ -197,6 +197,7 @@ sealed interface BlockCodeBuilder extends CodeBuilder * * @param handler handler that receives a {@linkplain BlockCodeBuilder} to * generate the body of the lexical block. + * @return this builder */ default CodeBuilder block(Consumer handler) { Label breakLabel = newLabel(); @@ -399,70 +400,161 @@ default CodeBuilder trying(Consumer tryHandler, // Base convenience methods + /** + * Generate an instruction to load a value from a local variable + * @param tk the load type + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder loadInstruction(TypeKind tk, int slot) { with(LoadInstruction.of(tk, slot)); return this; } + /** + * Generate an instruction to store a value to a local variable + * @param tk the store type + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder storeInstruction(TypeKind tk, int slot) { with(StoreInstruction.of(tk, slot)); return this; } + /** + * Generate an instruction to increment a local variable by a constant + * @param slot the local variable slot + * @param val the increment value + * @return this builder + */ default CodeBuilder incrementInstruction(int slot, int val) { with(IncrementInstruction.of(slot, val)); return this; } + /** + * Generate a branch instruction + * @see Opcode.Kind#BRANCH + * @param op the branch opcode + * @param target the branch target + * @return this builder + */ default CodeBuilder branchInstruction(Opcode op, Label target) { with(BranchInstruction.of(op, target)); return this; } + /** + * Generate an instruction to access a jump table by key match and jump + * @param defaultTarget the default jump target + * @param cases the switch cases + * @return this builder + */ default CodeBuilder lookupSwitchInstruction(Label defaultTarget, List cases) { with(LookupSwitchInstruction.of(defaultTarget, cases)); return this; } + /** + * Generate an instruction to access a jump table by index and jump + * @param lowValue the low key value + * @param highValue the high key value + * @param defaultTarget the default jump target + * @param cases the switch cases + * @return this builder + */ default CodeBuilder tableSwitchInstruction(int lowValue, int highValue, Label defaultTarget, List cases) { with(TableSwitchInstruction.of(lowValue, highValue, defaultTarget, cases)); return this; } + /** + * Generate return instruction + * @param tk the return type + * @return this builder + */ default CodeBuilder returnInstruction(TypeKind tk) { with(ReturnInstruction.of(tk)); return this; } + /** + * Generate an instruction to throw an exception or error + * @return this builder + */ default CodeBuilder throwInstruction() { with(ThrowInstruction.of()); return this; } + /** + * Generate an instruction to access a field + * @see Opcode.Kind#FIELD_ACCESS + * @param opcode the field access opcode + * @param ref the field reference + * @return this builder + */ default CodeBuilder fieldInstruction(Opcode opcode, FieldRefEntry ref) { with(FieldInstruction.of(opcode, ref)); return this; } + /** + * Generate an instruction to access a field + * @see Opcode.Kind#FIELD_ACCESS + * @param opcode the field access opcode + * @param owner the class + * @param name the field name + * @param type the field type + * @return this builder + */ default CodeBuilder fieldInstruction(Opcode opcode, ClassDesc owner, String name, ClassDesc type) { return fieldInstruction(opcode, constantPool().fieldRefEntry(owner, name, type)); } + /** + * Generate an instruction to invoke a method or constructor + * @see Opcode.Kind#INVOKE + * @param opcode the invoke opcode + * @param ref the interface method or method reference + * @return this builder + */ default CodeBuilder invokeInstruction(Opcode opcode, MemberRefEntry ref) { return with(InvokeInstruction.of(opcode, ref)); } + /** + * Generate an instruction to invoke a method or constructor + * @see Opcode.Kind#INVOKE + * @param opcode the invoke opcode + * @param owner the class + * @param name the method name + * @param desc the method type + * @param isInterface the interface method invocation indication + * @return this builder + */ default CodeBuilder invokeInstruction(Opcode opcode, ClassDesc owner, String name, MethodTypeDesc desc, boolean isInterface) { return invokeInstruction(opcode, isInterface ? constantPool().interfaceMethodRefEntry(owner, name, desc) : constantPool().methodRefEntry(owner, name, desc)); } + /** + * Generate an instruction to invoke a dynamically-computed call site + * @param ref the dynamic call site + * @return this builder + */ default CodeBuilder invokeDynamicInstruction(InvokeDynamicEntry ref) { with(InvokeDynamicInstruction.of(ref)); return this; } + /** + * Generate an instruction to invoke a dynamically-computed call site + * @param desc the dynamic call site + * @return this builder + */ default CodeBuilder invokeDynamicInstruction(DynamicCallSiteDesc desc) { MethodHandleEntry bsMethod = handleDescToHandleInfo(constantPool(), (DirectMethodHandleDesc) desc.bootstrapMethod()); var cpArgs = desc.bootstrapArgs(); @@ -476,77 +568,163 @@ default CodeBuilder invokeDynamicInstruction(DynamicCallSiteDesc desc) { return this; } + /** + * Generate an instruction to create a new object + * @param type the object type + * @return this builder + */ default CodeBuilder newObjectInstruction(ClassEntry type) { with(NewObjectInstruction.of(type)); return this; } + /** + * Generate an instruction to create a new object + * @param type the object type + * @return this builder + */ default CodeBuilder newObjectInstruction(ClassDesc type) { return newObjectInstruction(constantPool().classEntry(type)); } + /** + * Generate an instruction to create a new array of a primitive type + * @param typeKind the primitive component type + * @return this builder + */ default CodeBuilder newPrimitiveArrayInstruction(TypeKind typeKind) { with(NewPrimitiveArrayInstruction.of(typeKind)); return this; } + /** + * Generate an instruction to create a new array of reference + * @param type the component type + * @return this builder + */ default CodeBuilder newReferenceArrayInstruction(ClassEntry type) { with(NewReferenceArrayInstruction.of(type)); return this; } + /** + * Generate an instruction to create a new array of reference + * @param type the component type + * @return this builder + */ default CodeBuilder newReferenceArrayInstruction(ClassDesc type) { return newReferenceArrayInstruction(constantPool().classEntry(type)); } + /** + * Generate an instruction to create a new multidimensional array + * @param dimensions the number of dimensions + * @param type the array type + * @return this builder + */ default CodeBuilder newMultidimensionalArrayInstruction(int dimensions, ClassEntry type) { with(NewMultiArrayInstruction.of(type, dimensions)); return this; } + /** + * Generate an instruction to create a new multidimensional array + * @param dimensions the number of dimensions + * @param type the array type + * @return this builder + */ default CodeBuilder newMultidimensionalArrayInstruction(int dimensions, ClassDesc type) { return newMultidimensionalArrayInstruction(dimensions, constantPool().classEntry(type)); } + /** + * Generate an instruction to load from an array + * @param tk the array element type + * @return this builder + */ default CodeBuilder arrayLoadInstruction(TypeKind tk) { Opcode opcode = BytecodeHelpers.arrayLoadOpcode(tk); with(ArrayLoadInstruction.of(opcode)); return this; } + /** + * Generate an instruction to store into an array + * @param tk the array element type + * @return this builder + */ default CodeBuilder arrayStoreInstruction(TypeKind tk) { Opcode opcode = BytecodeHelpers.arrayStoreOpcode(tk); with(ArrayStoreInstruction.of(opcode)); return this; } + /** + * Generate a type checking instruction + * @see Opcode.Kind#TYPE_CHECK + * @param opcode the type check instruction opcode + * @param type the type + * @return this builder + */ default CodeBuilder typeCheckInstruction(Opcode opcode, ClassEntry type) { with(TypeCheckInstruction.of(opcode, type)); return this; } + /** + * Generate a type checking instruction + * @see Opcode.Kind#TYPE_CHECK + * @param opcode the type check instruction opcode + * @param type the type + * @return this builder + */ default CodeBuilder typeCheckInstruction(Opcode opcode, ClassDesc type) { return typeCheckInstruction(opcode, constantPool().classEntry(type)); } + /** + * Generate a type converting instruction + * @param fromType the source type + * @param toType the target type + * @return this builder + */ default CodeBuilder convertInstruction(TypeKind fromType, TypeKind toType) { with(ConvertInstruction.of(fromType, toType)); return this; } + /** + * Generate a stack manipulating instruction + * @param opcode the stack instruction opcode + * @see Opcode.Kind#STACK + * @return this builder + */ default CodeBuilder stackInstruction(Opcode opcode) { with(StackInstruction.of(opcode)); return this; } + /** + * Generate an operator instruction + * @see Opcode.Kind#OPERATOR + * @param opcode the operator instruction opcode + * @return this builder + */ default CodeBuilder operatorInstruction(Opcode opcode) { with(OperatorInstruction.of(opcode)); return this; } + /** + * Generate an instruction pushing a constant onto the operand stack + * @see Opcode.Kind#CONSTANT + * @param opcode the constant instruction opcode + * @param value the constant value + * @return this builder + */ default CodeBuilder constantInstruction(Opcode opcode, ConstantDesc value) { BytecodeHelpers.validateValue(opcode, value); return with(switch (opcode) { @@ -556,6 +734,11 @@ default CodeBuilder constantInstruction(Opcode opcode, ConstantDesc value) { }); } + /** + * Generate an instruction pushing a constant onto the operand stack + * @param value the constant value + * @return this builder + */ default CodeBuilder constantInstruction(ConstantDesc value) { //avoid switch expressions here if (value == null || value == ConstantDescs.NULL) @@ -586,72 +769,157 @@ default CodeBuilder constantInstruction(ConstantDesc value) { return Double.doubleToRawLongBits(dVal) == 0l ? dconst_0() : dVal == 1.0d ? dconst_1() : ldc(constantPool().doubleEntry(dVal)); - return ldc(BytecodeHelpers.constantEntry(constantPool(), value)); + return ldc(value); } + /** + * Generate a monitor instruction + * @see Opcode.Kind#MONITOR + * @param opcode the monitor instruction opcode + * @return this builder + */ default CodeBuilder monitorInstruction(Opcode opcode) { with(MonitorInstruction.of(opcode)); return null; } + /** + * Generate a do nothing instruction + * @return this builder + */ default CodeBuilder nopInstruction() { with(NopInstruction.of()); return this; } - + /** + * Generate a do nothing instruction + * @return this builder + */ default CodeBuilder nop() { return nopInstruction(); } // Base pseudo-instruction builder methods + /** + * Create new label bound with current position + * @return this builder + */ default Label newBoundLabel() { var label = newLabel(); labelBinding(label); return label; } + /** + * Bind label with current position + * @param label the label + * @return this builder + */ default CodeBuilder labelBinding(Label label) { with((LabelImpl) label); return this; } + /** + * Declare a source line number of the current builder position + * @param line the line number + * @return this builder + */ default CodeBuilder lineNumber(int line) { with(LineNumber.of(line)); return this; } + /** + * Declare an exception table entry + * @param start the try block start + * @param end the try block end + * @param handler the exception handler start + * @param catchType the catch type or null to catch all exceptions and errors + * @return this builder + */ default CodeBuilder exceptionCatch(Label start, Label end, Label handler, ClassEntry catchType) { with(ExceptionCatch.of(handler, start, end, Optional.of(catchType))); return this; } + /** + * Declare an exception table entry + * @param start the try block start + * @param end the try block end + * @param handler the exception handler start + * @param catchType the optional catch type, empty to catch all exceptions and errors + * @return this builder + */ default CodeBuilder exceptionCatch(Label start, Label end, Label handler, Optional catchType) { with(ExceptionCatch.of(handler, start, end, catchType)); return this; } + /** + * Declare an exception table entry + * @param start the try block start + * @param end the try block end + * @param handler the exception handler start + * @param catchType the catch type + * @return this builder + */ default CodeBuilder exceptionCatch(Label start, Label end, Label handler, ClassDesc catchType) { requireNonNull(catchType); return exceptionCatch(start, end, handler, constantPool().classEntry(catchType)); } + /** + * Declare an exception table entry catching all exceptions and errors + * @param start the try block start + * @param end the try block end + * @param handler the exception handler start + * @return this builder + */ default CodeBuilder exceptionCatchAll(Label start, Label end, Label handler) { with(ExceptionCatch.of(handler, start, end)); return this; } + /** + * Declare a character range entry + * @param startScope the start scope of the character range + * @param endScope the end scope of the character range + * @param characterRangeStart the encoded start of the character range region (inclusive) + * @param characterRangeEnd the encoded end of the character range region (exclusive) + * @param flags the flags word, indicating the kind of range + * @return this builder + */ default CodeBuilder characterRange(Label startScope, Label endScope, int characterRangeStart, int characterRangeEnd, int flags) { with(CharacterRange.of(startScope, endScope, characterRangeStart, characterRangeEnd, flags)); return this; } + /** + * Declare a local variable entry + * @param slot the local variable slot + * @param nameEntry the variable name + * @param descriptorEntry the variable descriptor + * @param startScope the start scope of the variable + * @param endScope the end scope of the variable + * @return this builder + */ default CodeBuilder localVariable(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry, Label startScope, Label endScope) { with(LocalVariable.of(slot, nameEntry, descriptorEntry, startScope, endScope)); return this; } + /** + * Declare a local variable entry + * @param slot the local variable slot + * @param name the variable name + * @param descriptor the variable descriptor + * @param startScope the start scope of the variable + * @param endScope the end scope of the variable + * @return this builder + */ default CodeBuilder localVariable(int slot, String name, ClassDesc descriptor, Label startScope, Label endScope) { return localVariable(slot, constantPool().utf8Entry(name), @@ -659,11 +927,29 @@ default CodeBuilder localVariable(int slot, String name, ClassDesc descriptor, L startScope, endScope); } + /** + * Declare a local variable type entry + * @param slot the local variable slot + * @param nameEntry the variable name + * @param signatureEntry the variable signature + * @param startScope the start scope of the variable + * @param endScope the end scope of the variable + * @return this builder + */ default CodeBuilder localVariableType(int slot, Utf8Entry nameEntry, Utf8Entry signatureEntry, Label startScope, Label endScope) { with(LocalVariableType.of(slot, nameEntry, signatureEntry, startScope, endScope)); return this; } + /** + * Declare a local variable type entry + * @param slot the local variable slot + * @param name the variable name + * @param signature the variable signature + * @param startScope the start scope of the variable + * @param endScope the end scope of the variable + * @return this builder + */ default CodeBuilder localVariableType(int slot, String name, Signature signature, Label startScope, Label endScope) { return localVariableType(slot, constantPool().utf8Entry(name), @@ -673,566 +959,1219 @@ default CodeBuilder localVariableType(int slot, String name, Signature signature // Bytecode conveniences + /** + * Generate an instruction pushing the null object reference onto the operand stack + * @return this builder + */ default CodeBuilder aconst_null() { return with(ConstantInstruction.ofIntrinsic(Opcode.ACONST_NULL)); } + /** + * Generate an instruction to load a reference from an array + * @return this builder + */ default CodeBuilder aaload() { return arrayLoadInstruction(TypeKind.ReferenceType); } + /** + * Generate an instruction to store into a reference array + * @return this builder + */ default CodeBuilder aastore() { return arrayStoreInstruction(TypeKind.ReferenceType); } + /** + * Generate an instruction to load a reference from a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder aload(int slot) { return loadInstruction(TypeKind.ReferenceType, slot); } + /** + * Generate an instruction to create a new array of reference + * @param classEntry the component type + * @return this builder + */ default CodeBuilder anewarray(ClassEntry classEntry) { return newReferenceArrayInstruction(classEntry); } + /** + * Generate an instruction to create a new array of reference + * @param className the component type + * @return this builder + */ default CodeBuilder anewarray(ClassDesc className) { return newReferenceArrayInstruction(constantPool().classEntry(className)); } + /** + * Generate an instruction to return a reference from the method + * @return this builder + */ default CodeBuilder areturn() { return returnInstruction(TypeKind.ReferenceType); } + /** + * Generate an instruction to get length of an array + * @return this builder + */ default CodeBuilder arraylength() { return operatorInstruction(Opcode.ARRAYLENGTH); } + /** + * Generate an instruction to store a reference into a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder astore(int slot) { return storeInstruction(TypeKind.ReferenceType, slot); } + /** + * Generate an instruction to throw an exception or error + * @return this builder + */ default CodeBuilder athrow() { return throwInstruction(); } + /** + * Generate an instruction to load a byte from a array + * @return this builder + */ default CodeBuilder baload() { return arrayLoadInstruction(TypeKind.ByteType); } + /** + * Generate an instruction to store into a byte array + * @return this builder + */ default CodeBuilder bastore() { return arrayStoreInstruction(TypeKind.ByteType); } + /** + * Generate an instruction pushing a byte onto the operand stack + * @param b the byte + * @return this builder + */ default CodeBuilder bipush(int b) { return constantInstruction(Opcode.BIPUSH, b); } + /** + * Generate an instruction to load a char from an array + * @return this builder + */ default CodeBuilder caload() { return arrayLoadInstruction(TypeKind.CharType); } + /** + * Generate an instruction to store into a char array + * @return this builder + */ default CodeBuilder castore() { return arrayStoreInstruction(TypeKind.CharType); } + /** + * Generate an instruction to check whether an object is of the given type + * @param type the object type + * @return this builder + */ default CodeBuilder checkcast(ClassEntry type) { return typeCheckInstruction(Opcode.CHECKCAST, type); } + /** + * Generate an instruction to check whether an object is of the given type + * @param type the object type + * @return this builder + */ default CodeBuilder checkcast(ClassDesc type) { return typeCheckInstruction(Opcode.CHECKCAST, type); } + /** + * Generate an instruction to convert a double into a float + * @return this builder + */ default CodeBuilder d2f() { return convertInstruction(TypeKind.DoubleType, TypeKind.FloatType); } + /** + * Generate an instruction to convert a double into an int + * @return this builder + */ default CodeBuilder d2i() { return convertInstruction(TypeKind.DoubleType, TypeKind.IntType); } + /** + * Generate an instruction to convert a double into a long + * @return this builder + */ default CodeBuilder d2l() { return convertInstruction(TypeKind.DoubleType, TypeKind.LongType); } + /** + * Generate an instruction to add a double + * @return this builder + */ default CodeBuilder dadd() { return operatorInstruction(Opcode.DADD); } + /** + * Generate an instruction to load a double from an array + * @return this builder + */ default CodeBuilder daload() { return arrayLoadInstruction(TypeKind.DoubleType); } + /** + * Generate an instruction to store into a double array + * @return this builder + */ default CodeBuilder dastore() { return arrayStoreInstruction(TypeKind.DoubleType); } + /** + * Generate an instruction to add a double + * @return this builder + */ default CodeBuilder dcmpg() { return operatorInstruction(Opcode.DCMPG); } + /** + * Generate an instruction to compare doubles + * @return this builder + */ default CodeBuilder dcmpl() { return operatorInstruction(Opcode.DCMPL); } + /** + * Generate an instruction pushing double constant 0 onto the operand stack + * @return this builder + */ default CodeBuilder dconst_0() { return with(ConstantInstruction.ofIntrinsic(Opcode.DCONST_0)); } + /** + * Generate an instruction pushing double constant 1 onto the operand stack + * @return this builder + */ default CodeBuilder dconst_1() { return with(ConstantInstruction.ofIntrinsic(Opcode.DCONST_1)); } + /** + * Generate an instruction to divide doubles + * @return this builder + */ default CodeBuilder ddiv() { return operatorInstruction(Opcode.DDIV); } + /** + * Generate an instruction to load a double from a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder dload(int slot) { return loadInstruction(TypeKind.DoubleType, slot); } + /** + * Generate an instruction to multiply doubles + * @return this builder + */ default CodeBuilder dmul() { return operatorInstruction(Opcode.DMUL); } + /** + * Generate an instruction to negate a double + * @return this builder + */ default CodeBuilder dneg() { return operatorInstruction(Opcode.DNEG); } + /** + * Generate an instruction to calculate double remainder + * @return this builder + */ default CodeBuilder drem() { return operatorInstruction(Opcode.DREM); } + /** + * Generate an instruction to return a double from the method + * @return this builder + */ default CodeBuilder dreturn() { return returnInstruction(TypeKind.DoubleType); } + /** + * Generate an instruction to store a double into a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder dstore(int slot) { return storeInstruction(TypeKind.DoubleType, slot); } + /** + * Generate an instruction to subtract doubles + * @return this builder + */ default CodeBuilder dsub() { return operatorInstruction(Opcode.DSUB); } + /** + * Generate an instruction to duplicate the top operand stack value + * @return this builder + */ default CodeBuilder dup() { return stackInstruction(Opcode.DUP); } + /** + * Generate an instruction to duplicate the top one or two operand stack value + * @return this builder + */ default CodeBuilder dup2() { return stackInstruction(Opcode.DUP2); } + /** + * Generate an instruction to duplicate the top one or two operand stack values and insert two or three + * values down + * @return this builder + */ default CodeBuilder dup2_x1() { return stackInstruction(Opcode.DUP2_X1); } + /** + * Generate an instruction to duplicate the top one or two operand stack values and insert two, three, + * or four values down + * @return this builder + */ default CodeBuilder dup2_x2() { return stackInstruction(Opcode.DUP2_X2); } - default CodeBuilder dup_x1() { + /** + * Generate an instruction to duplicate the top operand stack value and insert two values down + * @return this builder + */ + default CodeBuilder dup_x1() { return stackInstruction(Opcode.DUP_X1); } + /** + * Generate an instruction to duplicate the top operand stack value and insert two or three values down + * @return this builder + */ default CodeBuilder dup_x2() { return stackInstruction(Opcode.DUP_X2); } + /** + * Generate an instruction to convert a float into a double + * @return this builder + */ default CodeBuilder f2d() { return convertInstruction(TypeKind.FloatType, TypeKind.DoubleType); } + /** + * Generate an instruction to convert a float into an int + * @return this builder + */ default CodeBuilder f2i() { return convertInstruction(TypeKind.FloatType, TypeKind.IntType); } + /** + * Generate an instruction to convert a float into a long + * @return this builder + */ default CodeBuilder f2l() { return convertInstruction(TypeKind.FloatType, TypeKind.LongType); } + /** + * Generate an instruction to add a float + * @return this builder + */ default CodeBuilder fadd() { return operatorInstruction(Opcode.FADD); } + /** + * Generate an instruction to load a float from an array + * @return this builder + */ default CodeBuilder faload() { return arrayLoadInstruction(TypeKind.FloatType); } + /** + * Generate an instruction to store into a float array + * @return this builder + */ default CodeBuilder fastore() { return arrayStoreInstruction(TypeKind.FloatType); } + /** + * Generate an instruction to compare floats + * @return this builder + */ default CodeBuilder fcmpg() { return operatorInstruction(Opcode.FCMPG); } + /** + * Generate an instruction to compare floats + * @return this builder + */ default CodeBuilder fcmpl() { return operatorInstruction(Opcode.FCMPL); } + /** + * Generate an instruction pushing float constant 0 onto the operand stack + * @return this builder + */ default CodeBuilder fconst_0() { return with(ConstantInstruction.ofIntrinsic(Opcode.FCONST_0)); } + /** + * Generate an instruction pushing float constant 1 onto the operand stack + * @return this builder + */ default CodeBuilder fconst_1() { return with(ConstantInstruction.ofIntrinsic(Opcode.FCONST_1)); } + /** + * Generate an instruction pushing float constant 2 onto the operand stack + * @return this builder + */ default CodeBuilder fconst_2() { return with(ConstantInstruction.ofIntrinsic(Opcode.FCONST_2)); } + /** + * Generate an instruction to divide floats + * @return this builder + */ default CodeBuilder fdiv() { return operatorInstruction(Opcode.FDIV); } + /** + * Generate an instruction to load a float from a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder fload(int slot) { return loadInstruction(TypeKind.FloatType, slot); } + /** + * Generate an instruction to multiply floats + * @return this builder + */ default CodeBuilder fmul() { return operatorInstruction(Opcode.FMUL); } + /** + * Generate an instruction to negate a float + * @return this builder + */ default CodeBuilder fneg() { return operatorInstruction(Opcode.FNEG); } + /** + * Generate an instruction to calculate floats remainder + * @return this builder + */ default CodeBuilder frem() { return operatorInstruction(Opcode.FREM); } + /** + * Generate an instruction to return a float from the method + * @return this builder + */ default CodeBuilder freturn() { return returnInstruction(TypeKind.FloatType); } + /** + * Generate an instruction to store a float into a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder fstore(int slot) { return storeInstruction(TypeKind.FloatType, slot); } + /** + * Generate an instruction to subtract floats + * @return this builder + */ default CodeBuilder fsub() { return operatorInstruction(Opcode.FSUB); } + /** + * Generate an instruction to fetch field from an object + * @param ref the field reference + * @return this builder + */ default CodeBuilder getfield(FieldRefEntry ref) { return fieldInstruction(Opcode.GETFIELD, ref); } + /** + * Generate an instruction to fetch field from an object + * @param owner the owner class + * @param name the field name + * @param type the field type + * @return this builder + */ default CodeBuilder getfield(ClassDesc owner, String name, ClassDesc type) { return fieldInstruction(Opcode.GETFIELD, owner, name, type); } + /** + * Generate an instruction to get static field from a class + * @param ref the field reference + * @return this builder + */ default CodeBuilder getstatic(FieldRefEntry ref) { return fieldInstruction(Opcode.GETSTATIC, ref); } + /** + * Generate an instruction to get static field from a class + * @param owner the owner class + * @param name the field name + * @param type the field type + * @return this builder + */ default CodeBuilder getstatic(ClassDesc owner, String name, ClassDesc type) { return fieldInstruction(Opcode.GETSTATIC, owner, name, type); } + /** + * Generate an instruction to branch always + * @param target the branch target + * @return this builder + */ default CodeBuilder goto_(Label target) { return branchInstruction(Opcode.GOTO, target); } + /** + * Generate an instruction to branch always with wide index + * @param target the branch target + * @return this builder + */ default CodeBuilder goto_w(Label target) { return branchInstruction(Opcode.GOTO_W, target); } + /** + * Generate an instruction to convert an int into a byte + * @return this builder + */ default CodeBuilder i2b() { return convertInstruction(TypeKind.IntType, TypeKind.ByteType); } + /** + * Generate an instruction to convert an int into a char + * @return this builder + */ default CodeBuilder i2c() { return convertInstruction(TypeKind.IntType, TypeKind.CharType); } + /** + * Generate an instruction to convert an int into a double + * @return this builder + */ default CodeBuilder i2d() { return convertInstruction(TypeKind.IntType, TypeKind.DoubleType); } + /** + * Generate an instruction to convert an int into a float + * @return this builder + */ default CodeBuilder i2f() { return convertInstruction(TypeKind.IntType, TypeKind.FloatType); } + /** + * Generate an instruction to convert an int into a long + * @return this builder + */ default CodeBuilder i2l() { return convertInstruction(TypeKind.IntType, TypeKind.LongType); } + /** + * Generate an instruction to convert an int into a short + * @return this builder + */ default CodeBuilder i2s() { return convertInstruction(TypeKind.IntType, TypeKind.ShortType); } + /** + * Generate an instruction to add an int + * @return this builder + */ default CodeBuilder iadd() { return operatorInstruction(Opcode.IADD); } + /** + * Generate an instruction to load a int from an array + * @return this builder + */ default CodeBuilder iaload() { return arrayLoadInstruction(TypeKind.IntType); } + /** + * Generate an instruction to calculate boolean AND of ints + * @return this builder + */ default CodeBuilder iand() { return operatorInstruction(Opcode.IAND); } + /** + * Generate an instruction to store into an int array + * @return this builder + */ default CodeBuilder iastore() { return arrayStoreInstruction(TypeKind.IntType); } + /** + * Generate an instruction pushing int constant 0 onto the operand stack + * @return this builder + */ default CodeBuilder iconst_0() { return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_0)); } + /** + * Generate an instruction pushing int constant 1 onto the operand stack + * @return this builder + */ default CodeBuilder iconst_1() { return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_1)); } + /** + * Generate an instruction pushing int constant 2 onto the operand stack + * @return this builder + */ default CodeBuilder iconst_2() { return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_2)); } + /** + * Generate an instruction pushing int constant 3 onto the operand stack + * @return this builder + */ default CodeBuilder iconst_3() { return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_3)); } + /** + * Generate an instruction pushing int constant 4 onto the operand stack + * @return this builder + */ default CodeBuilder iconst_4() { return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_4)); } + /** + * Generate an instruction pushing int constant 5 onto the operand stack + * @return this builder + */ default CodeBuilder iconst_5() { return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_5)); } + /** + * Generate an instruction pushing int constant -1 onto the operand stack + * @return this builder + */ default CodeBuilder iconst_m1() { return with(ConstantInstruction.ofIntrinsic(Opcode.ICONST_M1)); } + /** + * Generate an instruction to divide ints + * @return this builder + */ default CodeBuilder idiv() { return operatorInstruction(Opcode.IDIV); } + /** + * Generate an instruction to branch if int comparison succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder if_acmpeq(Label target) { return branchInstruction(Opcode.IF_ACMPEQ, target); } + /** + * Generate an instruction to branch if int comparison succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder if_acmpne(Label target) { return branchInstruction(Opcode.IF_ACMPNE, target); } + /** + * Generate an instruction to branch if int comparison succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder if_icmpeq(Label target) { return branchInstruction(Opcode.IF_ICMPEQ, target); } + /** + * Generate an instruction to branch if int comparison succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder if_icmpge(Label target) { return branchInstruction(Opcode.IF_ICMPGE, target); } + /** + * Generate an instruction to branch if int comparison succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder if_icmpgt(Label target) { return branchInstruction(Opcode.IF_ICMPGT, target); } + /** + * Generate an instruction to branch if int comparison succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder if_icmple(Label target) { return branchInstruction(Opcode.IF_ICMPLE, target); } + /** + * Generate an instruction to branch if int comparison succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder if_icmplt(Label target) { return branchInstruction(Opcode.IF_ICMPLT, target); } + /** + * Generate an instruction to branch if int comparison succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder if_icmpne(Label target) { return branchInstruction(Opcode.IF_ICMPNE, target); } + /** + * Generate an instruction to branch if reference is not null + * @param target the branch target + * @return this builder + */ default CodeBuilder if_nonnull(Label target) { return branchInstruction(Opcode.IFNONNULL, target); } + /** + * Generate an instruction to branch if reference is null + * @param target the branch target + * @return this builder + */ default CodeBuilder if_null(Label target) { return branchInstruction(Opcode.IFNULL, target); } + /** + * Generate an instruction to branch if int comparison with zero succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder ifeq(Label target) { return branchInstruction(Opcode.IFEQ, target); } + /** + * Generate an instruction to branch if int comparison with zero succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder ifge(Label target) { return branchInstruction(Opcode.IFGE, target); } + /** + * Generate an instruction to branch if int comparison with zero succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder ifgt(Label target) { return branchInstruction(Opcode.IFGT, target); } + /** + * Generate an instruction to branch if int comparison with zero succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder ifle(Label target) { return branchInstruction(Opcode.IFLE, target); } + /** + * Generate an instruction to branch if int comparison with zero succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder iflt(Label target) { return branchInstruction(Opcode.IFLT, target); } + /** + * Generate an instruction to branch if int comparison with zero succeeds + * @param target the branch target + * @return this builder + */ default CodeBuilder ifne(Label target) { return branchInstruction(Opcode.IFNE, target); } + /** + * Generate an instruction to increment a local variable by a constant + * @param slot the local variable slot + * @param val the increment value + * @return this builder + */ default CodeBuilder iinc(int slot, int val) { return incrementInstruction(slot, val); } + /** + * Generate an instruction to load an int from a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder iload(int slot) { return loadInstruction(TypeKind.IntType, slot); } + /** + * Generate an instruction to multiply ints + * @return this builder + */ default CodeBuilder imul() { return operatorInstruction(Opcode.IMUL); } + /** + * Generate an instruction to negate an int + * @return this builder + */ default CodeBuilder ineg() { return operatorInstruction(Opcode.INEG); } + /** + * Generate an instruction to determine if an object is of the given type + * @param target the target type + * @return this builder + */ default CodeBuilder instanceof_(ClassEntry target) { return typeCheckInstruction(Opcode.INSTANCEOF, target); } + /** + * Generate an instruction to determine if an object is of the given type + * @param target the target type + * @return this builder + */ default CodeBuilder instanceof_(ClassDesc target) { return typeCheckInstruction(Opcode.INSTANCEOF, constantPool().classEntry(target)); } + /** + * Generate an instruction to invoke a dynamically-computed call site + * @param ref the dynamic call site + * @return this builder + */ default CodeBuilder invokedynamic(InvokeDynamicEntry ref) { return invokeDynamicInstruction(ref); } + /** + * Generate an instruction to invoke a dynamically-computed call site + * @param ref the dynamic call site + * @return this builder + */ default CodeBuilder invokedynamic(DynamicCallSiteDesc ref) { return invokeDynamicInstruction(ref); } + /** + * Generate an instruction to invoke an interface method + * @param ref the interface method reference + * @return this builder + */ default CodeBuilder invokeinterface(InterfaceMethodRefEntry ref) { return invokeInstruction(Opcode.INVOKEINTERFACE, ref); } + /** + * Generate an instruction to invoke an interface method + * @param owner the owner class + * @param name the method name + * @param type the method type + * @return this builder + */ default CodeBuilder invokeinterface(ClassDesc owner, String name, MethodTypeDesc type) { return invokeInstruction(Opcode.INVOKEINTERFACE, constantPool().interfaceMethodRefEntry(owner, name, type)); } + /** + * Generate an instruction to invoke an instance method; direct invocation of instance initialization + * methods and methods of the current class and its supertypes + * @param ref the interface method reference + * @return this builder + */ default CodeBuilder invokespecial(InterfaceMethodRefEntry ref) { return invokeInstruction(Opcode.INVOKESPECIAL, ref); } + /** + * Generate an instruction to invoke an instance method; direct invocation of instance initialization + * methods and methods of the current class and its supertypes + * @param ref the method reference + * @return this builder + */ default CodeBuilder invokespecial(MethodRefEntry ref) { return invokeInstruction(Opcode.INVOKESPECIAL, ref); } + /** + * Generate an instruction to invoke an instance method; direct invocation of instance initialization + * methods and methods of the current class and its supertypes + * @param owner the owner class + * @param name the method name + * @param type the method type + * @return this builder + */ default CodeBuilder invokespecial(ClassDesc owner, String name, MethodTypeDesc type) { return invokeInstruction(Opcode.INVOKESPECIAL, owner, name, type, false); } + /** + * Generate an instruction to invoke an instance method; direct invocation of instance initialization + * methods and methods of the current class and its supertypes + * @param owner the owner class + * @param name the method name + * @param type the method type + * @param isInterface the interface method invocation indication + * @return this builder + */ default CodeBuilder invokespecial(ClassDesc owner, String name, MethodTypeDesc type, boolean isInterface) { return invokeInstruction(Opcode.INVOKESPECIAL, owner, name, type, isInterface); } + /** + * Generate an instruction to invoke a class (static) method + * @param ref the interface method reference + * @return this builder + */ default CodeBuilder invokestatic(InterfaceMethodRefEntry ref) { return invokeInstruction(Opcode.INVOKESTATIC, ref); } + /** + * Generate an instruction to invoke a class (static) method + * @param ref the method reference + * @return this builder + */ default CodeBuilder invokestatic(MethodRefEntry ref) { return invokeInstruction(Opcode.INVOKESTATIC, ref); } + /** + * Generate an instruction to invoke a class (static) method + * @param owner the owner class + * @param name the method name + * @param type the method type + * @return this builder + */ default CodeBuilder invokestatic(ClassDesc owner, String name, MethodTypeDesc type) { return invokeInstruction(Opcode.INVOKESTATIC, owner, name, type, false); } + /** + * Generate an instruction to invoke a class (static) method + * @param owner the owner class + * @param name the method name + * @param type the method type + * @param isInterface the interface method invocation indication + * @return this builder + */ default CodeBuilder invokestatic(ClassDesc owner, String name, MethodTypeDesc type, boolean isInterface) { return invokeInstruction(Opcode.INVOKESTATIC, owner, name, type, isInterface); } + /** + * Generate an instruction to invoke an instance method; dispatch based on class + * @param ref the method reference + * @return this builder + */ default CodeBuilder invokevirtual(MethodRefEntry ref) { return invokeInstruction(Opcode.INVOKEVIRTUAL, ref); } + /** + * Generate an instruction to invoke an instance method; dispatch based on class + * @param owner the owner class + * @param name the method name + * @param type the method type + * @return this builder + */ default CodeBuilder invokevirtual(ClassDesc owner, String name, MethodTypeDesc type) { return invokeInstruction(Opcode.INVOKEVIRTUAL, owner, name, type, false); } + /** + * Generate an instruction to calculate boolean OR of ints + * @return this builder + */ default CodeBuilder ior() { return operatorInstruction(Opcode.IOR); } + /** + * Generate an instruction to calculate ints remainder + * @return this builder + */ default CodeBuilder irem() { return operatorInstruction(Opcode.IREM); } + /** + * Generate an instruction to return an int from the method + * @return this builder + */ default CodeBuilder ireturn() { return returnInstruction(TypeKind.IntType); } + /** + * Generate an instruction to shift an int left + * @return this builder + */ default CodeBuilder ishl() { return operatorInstruction(Opcode.ISHL); } + /** + * Generate an instruction to shift an int right + * @return this builder + */ default CodeBuilder ishr() { return operatorInstruction(Opcode.ISHR); } + /** + * Generate an instruction to store an int into a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder istore(int slot) { return storeInstruction(TypeKind.IntType, slot); } + /** + * Generate an instruction to subtract ints + * @return this builder + */ default CodeBuilder isub() { return operatorInstruction(Opcode.ISUB); } + /** + * Generate an instruction to logical shift an int right + * @return this builder + */ default CodeBuilder iushr() { return operatorInstruction(Opcode.IUSHR); } + /** + * Generate an instruction to calculate boolean XOR of ints + * @return this builder + */ default CodeBuilder ixor() { return operatorInstruction(Opcode.IXOR); } + /** + * Generate an instruction to access a jump table by key match and jump + * @param defaultTarget the default jump target + * @param cases the switch cases + * @return this builder + */ default CodeBuilder lookupswitch(Label defaultTarget, List cases) { return lookupSwitchInstruction(defaultTarget, cases); } + /** + * Generate an instruction to convert a long into a double + * @return this builder + */ default CodeBuilder l2d() { return convertInstruction(TypeKind.LongType, TypeKind.DoubleType); } + /** + * Generate an instruction to convert a long into a float + * @return this builder + */ default CodeBuilder l2f() { return convertInstruction(TypeKind.LongType, TypeKind.FloatType); } + /** + * Generate an instruction to convert a long into an int + * @return this builder + */ default CodeBuilder l2i() { return convertInstruction(TypeKind.LongType, TypeKind.IntType); } + /** + * Generate an instruction to add a long + * @return this builder + */ default CodeBuilder ladd() { return operatorInstruction(Opcode.LADD); } + /** + * Generate an instruction to load a long from an array + * @return this builder + */ default CodeBuilder laload() { return arrayLoadInstruction(TypeKind.LongType); } + /** + * Generate an instruction to calculate boolean AND of longs + * @return this builder + */ default CodeBuilder land() { return operatorInstruction(Opcode.LAND); } + /** + * Generate an instruction to store into a long array + * @return this builder + */ default CodeBuilder lastore() { return arrayStoreInstruction(TypeKind.LongType); } + /** + * Generate an instruction to compare longs + * @return this builder + */ default CodeBuilder lcmp() { return operatorInstruction(Opcode.LCMP); } + /** + * Generate an instruction pushing long constant 0 onto the operand stack + * @return this builder + */ default CodeBuilder lconst_0() { return with(ConstantInstruction.ofIntrinsic(Opcode.LCONST_0)); } + /** + * Generate an instruction pushing long constant 1 onto the operand stack + * @return this builder + */ default CodeBuilder lconst_1() { return with(ConstantInstruction.ofIntrinsic(Opcode.LCONST_1)); } + /** + * Generate an instruction pushing an item from the run-time constant pool onto the operand stack + * @param value the constant value + * @return this builder + */ + default CodeBuilder ldc(ConstantDesc value) { + return ldc(BytecodeHelpers.constantEntry(constantPool(), value)); + } + + /** + * Generate an instruction pushing an item from the run-time constant pool onto the operand stack + * @param entry the constant value + * @return this builder + */ default CodeBuilder ldc(LoadableConstantEntry entry) { return with(ConstantInstruction.ofLoad( entry.typeKind().slotSize() == 2 ? Opcode.LDC2_W @@ -1240,134 +2179,290 @@ default CodeBuilder ldc(LoadableConstantEntry entry) { : Opcode.LDC, entry)); } + /** + * Generate an instruction to divide longs + * @return this builder + */ default CodeBuilder ldiv() { return operatorInstruction(Opcode.LDIV); } + /** + * Generate an instruction to load a long from a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder lload(int slot) { return loadInstruction(TypeKind.LongType, slot); } + /** + * Generate an instruction to multiply longs + * @return this builder + */ default CodeBuilder lmul() { return operatorInstruction(Opcode.LMUL); } + /** + * Generate an instruction to negate a long + * @return this builder + */ default CodeBuilder lneg() { return operatorInstruction(Opcode.LNEG); } + /** + * Generate an instruction to calculate boolean OR of longs + * @return this builder + */ default CodeBuilder lor() { return operatorInstruction(Opcode.LOR); } + /** + * Generate an instruction to calculate longs remainder + * @return this builder + */ default CodeBuilder lrem() { return operatorInstruction(Opcode.LREM); } + /** + * Generate an instruction to return a long from the method + * @return this builder + */ default CodeBuilder lreturn() { return returnInstruction(TypeKind.LongType); } + /** + * Generate an instruction to shift a long left + * @return this builder + */ default CodeBuilder lshl() { return operatorInstruction(Opcode.LSHL); } + /** + * Generate an instruction to shift a long right + * @return this builder + */ default CodeBuilder lshr() { return operatorInstruction(Opcode.LSHR); } + /** + * Generate an instruction to store a long into a local variable + * @param slot the local variable slot + * @return this builder + */ default CodeBuilder lstore(int slot) { return storeInstruction(TypeKind.LongType, slot); } + /** + * Generate an instruction to subtract longs + * @return this builder + */ default CodeBuilder lsub() { return operatorInstruction(Opcode.LSUB); } + /** + * Generate an instruction to logical shift a long left + * @return this builder + */ default CodeBuilder lushr() { return operatorInstruction(Opcode.LUSHR); } + /** + * Generate an instruction to calculate boolean XOR of longs + * @return this builder + */ default CodeBuilder lxor() { return operatorInstruction(Opcode.LXOR); } + /** + * Generate an instruction to enter monitor for an object + * @return this builder + */ default CodeBuilder monitorenter() { return monitorInstruction(Opcode.MONITORENTER); } + /** + * Generate an instruction to exit monitor for an object + * @return this builder + */ default CodeBuilder monitorexit() { return monitorInstruction(Opcode.MONITOREXIT); } + /** + * Generate an instruction to create a new multidimensional array + * @param array the array type + * @param dims the number of dimensions + * @return this builder + */ default CodeBuilder multianewarray(ClassEntry array, int dims) { return newMultidimensionalArrayInstruction(dims, array); } + /** + * Generate an instruction to create a new multidimensional array + * @param array the array type + * @param dims the number of dimensions + * @return this builder + */ default CodeBuilder multianewarray(ClassDesc array, int dims) { return newMultidimensionalArrayInstruction(dims, constantPool().classEntry(array)); } + /** + * Generate an instruction to create a new object + * @param clazz the new class type + * @return this builder + */ default CodeBuilder new_(ClassEntry clazz) { return newObjectInstruction(clazz); } + /** + * Generate an instruction to create a new object + * @param clazz the new class type + * @return this builder + */ default CodeBuilder new_(ClassDesc clazz) { return newObjectInstruction(constantPool().classEntry(clazz)); } + /** + * Generate an instruction to create a new array of a primitive type + * @param typeKind the primitive array type + * @return this builder + */ default CodeBuilder newarray(TypeKind typeKind) { return newPrimitiveArrayInstruction(typeKind); } + /** + * Generate an instruction to pop the top operand stack value + * @return this builder + */ default CodeBuilder pop() { return stackInstruction(Opcode.POP); } + /** + * Generate an instruction to pop the top one or two operand stack values + * @return this builder + */ default CodeBuilder pop2() { return stackInstruction(Opcode.POP2); } + /** + * Generate an instruction to set field in an object + * @param ref the field reference + * @return this builder + */ default CodeBuilder putfield(FieldRefEntry ref) { return fieldInstruction(Opcode.PUTFIELD, ref); } + /** + * Generate an instruction to set field in an object + * @param owner the owner class + * @param name the field name + * @param type the field type + * @return this builder + */ default CodeBuilder putfield(ClassDesc owner, String name, ClassDesc type) { return fieldInstruction(Opcode.PUTFIELD, owner, name, type); } + /** + * Generate an instruction to set static field in a class + * @param ref the field reference + * @return this builder + */ default CodeBuilder putstatic(FieldRefEntry ref) { return fieldInstruction(Opcode.PUTSTATIC, ref); } + /** + * Generate an instruction to set static field in a class + * @param owner the owner class + * @param name the field name + * @param type the field type + * @return this builder + */ default CodeBuilder putstatic(ClassDesc owner, String name, ClassDesc type) { return fieldInstruction(Opcode.PUTSTATIC, owner, name, type); } + /** + * Generate an instruction to return void from the method + * @return this builder + */ default CodeBuilder return_() { return returnInstruction(TypeKind.VoidType); } + /** + * Generate an instruction to load a short from an array + * @return this builder + */ default CodeBuilder saload() { return arrayLoadInstruction(TypeKind.ShortType); } + /** + * Generate an instruction to store into a short array + * @return this builder + */ default CodeBuilder sastore() { return arrayStoreInstruction(TypeKind.ShortType); } + /** + * Generate an instruction pushing a short onto the operand stack + * @param s the short + * @return this builder + */ default CodeBuilder sipush(int s) { return constantInstruction(Opcode.SIPUSH, s); } + /** + * Generate an instruction to swap the top two operand stack values + * @return this builder + */ default CodeBuilder swap() { return stackInstruction(Opcode.SWAP); } + /** + * Generate an instruction to access a jump table by index and jump + * @param low the low key value + * @param high the high key value + * @param defaultTarget the default jump target + * @param cases the switch cases + * @return this builder + */ default CodeBuilder tableswitch(int low, int high, Label defaultTarget, List cases) { return tableSwitchInstruction(low, high, defaultTarget, cases); } + /** + * Generate an instruction to access a jump table by index and jump + * @param defaultTarget the default jump target + * @param cases the switch cases + * @return this builder + */ default CodeBuilder tableswitch(Label defaultTarget, List cases) { int low = Integer.MAX_VALUE; int high = Integer.MIN_VALUE; @@ -1378,9 +2473,4 @@ default CodeBuilder tableswitch(Label defaultTarget, List cases) { } return tableSwitchInstruction(low, high, defaultTarget, cases); } - - // Structured conveniences: - - // allocLocal(type) - // returnFromMethod(inferred) } diff --git a/src/java.base/share/classes/jdk/internal/classfile/CompoundElement.java b/src/java.base/share/classes/jdk/internal/classfile/CompoundElement.java index 3ba7d73760b..40f85aea705 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/CompoundElement.java +++ b/src/java.base/share/classes/jdk/internal/classfile/CompoundElement.java @@ -40,6 +40,7 @@ * option to treat the element as a single entity (e.g., an entire method) * or to traverse the contents of that element with the methods in this class * (e.g., {@link #elements()}, {@link #forEachElement(Consumer)}, etc.) + * @param the element type */ public sealed interface CompoundElement extends ClassfileElement, Iterable diff --git a/src/java.base/share/classes/jdk/internal/classfile/CustomAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/CustomAttribute.java index d84e2628b9c..cd4d430403a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/CustomAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/CustomAttribute.java @@ -31,6 +31,7 @@ * this class to provide an implementation class for non-standard attributes, * and provide an {@link AttributeMapper} to mediate between the classfile * format and the {@linkplain CustomAttribute} representation. + * @param the custom attribute type */ @SuppressWarnings("exports") public abstract non-sealed class CustomAttribute> diff --git a/src/java.base/share/classes/jdk/internal/classfile/Opcode.java b/src/java.base/share/classes/jdk/internal/classfile/Opcode.java index 6779e55448b..af1027baeca 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Opcode.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Opcode.java @@ -28,237 +28,1030 @@ import java.lang.constant.ConstantDescs; /** - * Describes the opcodes of the JVM instruction set, as well as a number of - * pseudo-instructions that may be encountered when traversing the instructions - * of a method. + * Describes the opcodes of the JVM instruction set, as described in {@jvms 6.5}. + * As well as a number of pseudo-instructions that may be encountered when + * traversing the instructions of a method. * * @see Instruction * @see PseudoInstruction */ public enum Opcode { + + /** Do nothing */ NOP(Classfile.NOP, 1, Kind.NOP), + + /** Push null */ ACONST_NULL(Classfile.ACONST_NULL, 1, Kind.CONSTANT, TypeKind.ReferenceType, 0, ConstantDescs.NULL), + + /** Push int constant -1 */ ICONST_M1(Classfile.ICONST_M1, 1, Kind.CONSTANT, TypeKind.IntType, 0, -1), + + /** Push int constant 0 */ ICONST_0(Classfile.ICONST_0, 1, Kind.CONSTANT, TypeKind.IntType, 0, 0), + + /** Push int constant 1 */ ICONST_1(Classfile.ICONST_1, 1, Kind.CONSTANT, TypeKind.IntType, 0, 1), + + /** Push int constant 2 */ ICONST_2(Classfile.ICONST_2, 1, Kind.CONSTANT, TypeKind.IntType, 0, 2), + + /** Push int constant 3 */ ICONST_3(Classfile.ICONST_3, 1, Kind.CONSTANT, TypeKind.IntType, 0, 3), + + /** Push int constant 4 */ ICONST_4(Classfile.ICONST_4, 1, Kind.CONSTANT, TypeKind.IntType, 0, 4), + + /** Push int constant 5 */ ICONST_5(Classfile.ICONST_5, 1, Kind.CONSTANT, TypeKind.IntType, 0, 5), + + /** Push long constant 0 */ LCONST_0(Classfile.LCONST_0, 1, Kind.CONSTANT, TypeKind.LongType, 0, 0L), + + /** Push long constant 1 */ LCONST_1(Classfile.LCONST_1, 1, Kind.CONSTANT, TypeKind.LongType, 0, 1L), + + /** Push float constant 0 */ FCONST_0(Classfile.FCONST_0, 1, Kind.CONSTANT, TypeKind.FloatType, 0, 0.0f), + + /** Push float constant 1 */ FCONST_1(Classfile.FCONST_1, 1, Kind.CONSTANT, TypeKind.FloatType, 0, 1.0f), + + /** Push float constant 2 */ FCONST_2(Classfile.FCONST_2, 1, Kind.CONSTANT, TypeKind.FloatType, 0, 2.0f), + + /** Push double constant 0 */ DCONST_0(Classfile.DCONST_0, 1, Kind.CONSTANT, TypeKind.DoubleType, 0, 0.0d), + + /** Push double constant 1 */ DCONST_1(Classfile.DCONST_1, 1, Kind.CONSTANT, TypeKind.DoubleType, 0, 1.0d), + + /** Push byte */ BIPUSH(Classfile.BIPUSH, 2, Kind.CONSTANT, TypeKind.ByteType), + + /** Push short */ SIPUSH(Classfile.SIPUSH, 3, Kind.CONSTANT, TypeKind.ShortType), + + /** Push item from run-time constant pool */ LDC(Classfile.LDC, 2, Kind.CONSTANT), + + /** Push item from run-time constant pool (wide index) */ LDC_W(Classfile.LDC_W, 3, Kind.CONSTANT), + + /** Push long or double from run-time constant pool (wide index) */ LDC2_W(Classfile.LDC2_W, 3, Kind.CONSTANT), + + /** Load int from local variable */ ILOAD(Classfile.ILOAD, 2, Kind.LOAD, TypeKind.IntType, -1), + + /** Load long from local variable */ LLOAD(Classfile.LLOAD, 2, Kind.LOAD, TypeKind.LongType, -1), + + /** Load float from local variable */ FLOAD(Classfile.FLOAD, 2, Kind.LOAD, TypeKind.FloatType, -1), + + /** Load double from local variable */ DLOAD(Classfile.DLOAD, 2, Kind.LOAD, TypeKind.DoubleType, -1), + + /** Load reference from local variable */ ALOAD(Classfile.ALOAD, 2, Kind.LOAD, TypeKind.ReferenceType, -1), + + /** Load int from local variable 0 */ ILOAD_0(Classfile.ILOAD_0, 1, Kind.LOAD, TypeKind.IntType, 0), + + /** Load int from local variable 1 */ ILOAD_1(Classfile.ILOAD_1, 1, Kind.LOAD, TypeKind.IntType, 1), + + /** Load int from local variable 2 */ ILOAD_2(Classfile.ILOAD_2, 1, Kind.LOAD, TypeKind.IntType, 2), + + /** Load int from local variable3 */ ILOAD_3(Classfile.ILOAD_3, 1, Kind.LOAD, TypeKind.IntType, 3), + + /** Load long from local variable 0 */ LLOAD_0(Classfile.LLOAD_0, 1, Kind.LOAD, TypeKind.LongType, 0), + + /** Load long from local variable 1 */ LLOAD_1(Classfile.LLOAD_1, 1, Kind.LOAD, TypeKind.LongType, 1), + + /** Load long from local variable 2 */ LLOAD_2(Classfile.LLOAD_2, 1, Kind.LOAD, TypeKind.LongType, 2), + + /** Load long from local variable 3 */ LLOAD_3(Classfile.LLOAD_3, 1, Kind.LOAD, TypeKind.LongType, 3), + + /** Load float from local variable 0 */ FLOAD_0(Classfile.FLOAD_0, 1, Kind.LOAD, TypeKind.FloatType, 0), + + /** Load float from local variable 1 */ FLOAD_1(Classfile.FLOAD_1, 1, Kind.LOAD, TypeKind.FloatType, 1), + + /** Load float from local variable 2 */ FLOAD_2(Classfile.FLOAD_2, 1, Kind.LOAD, TypeKind.FloatType, 2), + + /** Load float from local variable 3 */ FLOAD_3(Classfile.FLOAD_3, 1, Kind.LOAD, TypeKind.FloatType, 3), + + /** Load double from local variable 0 */ DLOAD_0(Classfile.DLOAD_0, 1, Kind.LOAD, TypeKind.DoubleType, 0), + + /** Load double from local variable 1 */ DLOAD_1(Classfile.DLOAD_1, 1, Kind.LOAD, TypeKind.DoubleType, 1), + + /** Load double from local variable 2 */ DLOAD_2(Classfile.DLOAD_2, 1, Kind.LOAD, TypeKind.DoubleType, 2), + + /** Load double from local variable 3 */ DLOAD_3(Classfile.DLOAD_3, 1, Kind.LOAD, TypeKind.DoubleType, 3), + + /** Load reference from local variable 0 */ ALOAD_0(Classfile.ALOAD_0, 1, Kind.LOAD, TypeKind.ReferenceType, 0), + + /** Load reference from local variable 1 */ ALOAD_1(Classfile.ALOAD_1, 1, Kind.LOAD, TypeKind.ReferenceType, 1), + + /** Load reference from local variable 2 */ ALOAD_2(Classfile.ALOAD_2, 1, Kind.LOAD, TypeKind.ReferenceType, 2), + + /** Load reference from local variable 3 */ ALOAD_3(Classfile.ALOAD_3, 1, Kind.LOAD, TypeKind.ReferenceType, 3), + + /** Load int from array */ IALOAD(Classfile.IALOAD, 1, Kind.ARRAY_LOAD, TypeKind.IntType), + + /** Load long from array */ LALOAD(Classfile.LALOAD, 1, Kind.ARRAY_LOAD, TypeKind.LongType), + + /** Load float from array */ FALOAD(Classfile.FALOAD, 1, Kind.ARRAY_LOAD, TypeKind.FloatType), + + /** Load double from array */ DALOAD(Classfile.DALOAD, 1, Kind.ARRAY_LOAD, TypeKind.DoubleType), + + /** Load reference from array */ AALOAD(Classfile.AALOAD, 1, Kind.ARRAY_LOAD, TypeKind.ReferenceType), + + /** Load byte from array */ BALOAD(Classfile.BALOAD, 1, Kind.ARRAY_LOAD, TypeKind.ByteType), + + /** Load char from array */ CALOAD(Classfile.CALOAD, 1, Kind.ARRAY_LOAD, TypeKind.CharType), + + /** Load short from array */ SALOAD(Classfile.SALOAD, 1, Kind.ARRAY_LOAD, TypeKind.ShortType), + + /** Store int into local variable */ ISTORE(Classfile.ISTORE, 2, Kind.STORE, TypeKind.IntType, -1), + + /** Store long into local variable */ LSTORE(Classfile.LSTORE, 2, Kind.STORE, TypeKind.LongType, -1), + + /** Store float into local variable */ FSTORE(Classfile.FSTORE, 2, Kind.STORE, TypeKind.FloatType, -1), + + /** Store double into local variable */ DSTORE(Classfile.DSTORE, 2, Kind.STORE, TypeKind.DoubleType, -1), + + /** Store reference into local variable */ ASTORE(Classfile.ASTORE, 2, Kind.STORE, TypeKind.ReferenceType, -1), + + /** Store int into local variable 0 */ ISTORE_0(Classfile.ISTORE_0, 1, Kind.STORE, TypeKind.IntType, 0), + + /** Store int into local variable 1 */ ISTORE_1(Classfile.ISTORE_1, 1, Kind.STORE, TypeKind.IntType, 1), + + /** Store int into local variable 2 */ ISTORE_2(Classfile.ISTORE_2, 1, Kind.STORE, TypeKind.IntType, 2), + + /** Store int into local variable 3 */ ISTORE_3(Classfile.ISTORE_3, 1, Kind.STORE, TypeKind.IntType, 3), + + /** Store long into local variable 0 */ LSTORE_0(Classfile.LSTORE_0, 1, Kind.STORE, TypeKind.LongType, 0), + + /** Store long into local variable 1 */ LSTORE_1(Classfile.LSTORE_1, 1, Kind.STORE, TypeKind.LongType, 1), + + /** Store long into local variable 2 */ LSTORE_2(Classfile.LSTORE_2, 1, Kind.STORE, TypeKind.LongType, 2), + + /** Store long into local variable 3 */ LSTORE_3(Classfile.LSTORE_3, 1, Kind.STORE, TypeKind.LongType, 3), + + /** Store float into local variable 0 */ FSTORE_0(Classfile.FSTORE_0, 1, Kind.STORE, TypeKind.FloatType, 0), + + /** Store float into local variable 1 */ FSTORE_1(Classfile.FSTORE_1, 1, Kind.STORE, TypeKind.FloatType, 1), + + /** Store float into local variable 2 */ FSTORE_2(Classfile.FSTORE_2, 1, Kind.STORE, TypeKind.FloatType, 2), + + /** Store float into local variable 3 */ FSTORE_3(Classfile.FSTORE_3, 1, Kind.STORE, TypeKind.FloatType, 3), + + /** Store double into local variable 0 */ DSTORE_0(Classfile.DSTORE_0, 1, Kind.STORE, TypeKind.DoubleType, 0), + + /** Store double into local variable 1 */ DSTORE_1(Classfile.DSTORE_1, 1, Kind.STORE, TypeKind.DoubleType, 1), + + /** Store double into local variable 2 */ DSTORE_2(Classfile.DSTORE_2, 1, Kind.STORE, TypeKind.DoubleType, 2), + + /** Store double into local variable 3 */ DSTORE_3(Classfile.DSTORE_3, 1, Kind.STORE, TypeKind.DoubleType, 3), + + /** Store reference into local variable 0 */ ASTORE_0(Classfile.ASTORE_0, 1, Kind.STORE, TypeKind.ReferenceType, 0), + + /** Store reference into local variable 1 */ ASTORE_1(Classfile.ASTORE_1, 1, Kind.STORE, TypeKind.ReferenceType, 1), + + /** Store reference into local variable 2 */ ASTORE_2(Classfile.ASTORE_2, 1, Kind.STORE, TypeKind.ReferenceType, 2), + + /** Store reference into local variable 3 */ ASTORE_3(Classfile.ASTORE_3, 1, Kind.STORE, TypeKind.ReferenceType, 3), + + /** Store into int array */ IASTORE(Classfile.IASTORE, 1, Kind.ARRAY_STORE, TypeKind.IntType), + + /** Store into long array */ LASTORE(Classfile.LASTORE, 1, Kind.ARRAY_STORE, TypeKind.LongType), + + /** Store into float array */ FASTORE(Classfile.FASTORE, 1, Kind.ARRAY_STORE, TypeKind.FloatType), + + /** Store into double array */ DASTORE(Classfile.DASTORE, 1, Kind.ARRAY_STORE, TypeKind.DoubleType), + + /** Store into reference array */ AASTORE(Classfile.AASTORE, 1, Kind.ARRAY_STORE, TypeKind.ReferenceType), + + /** Store into byte array */ BASTORE(Classfile.BASTORE, 1, Kind.ARRAY_STORE, TypeKind.ByteType), + + /** Store into char array */ CASTORE(Classfile.CASTORE, 1, Kind.ARRAY_STORE, TypeKind.CharType), + + /** Store into short array */ SASTORE(Classfile.SASTORE, 1, Kind.ARRAY_STORE, TypeKind.ShortType), + + /** Pop the top operand stack value */ POP(Classfile.POP, 1, Kind.STACK), + + /** Pop the top one or two operand stack values */ POP2(Classfile.POP2, 1, Kind.STACK), + + /** Duplicate the top operand stack value */ DUP(Classfile.DUP, 1, Kind.STACK), + + /** Duplicate the top operand stack value and insert two values down */ DUP_X1(Classfile.DUP_X1, 1, Kind.STACK), + + /** Duplicate the top operand stack value and insert two or three values down */ DUP_X2(Classfile.DUP_X2, 1, Kind.STACK), + + /** Duplicate the top one or two operand stack values */ DUP2(Classfile.DUP2, 1, Kind.STACK), + + /** Duplicate the top one or two operand stack values and insert two or three values down */ DUP2_X1(Classfile.DUP2_X1, 1, Kind.STACK), + + /** Duplicate the top one or two operand stack values and insert two, three, or four values down */ DUP2_X2(Classfile.DUP2_X2, 1, Kind.STACK), + + /** Swap the top two operand stack values */ SWAP(Classfile.SWAP, 1, Kind.STACK), + + /** Add int */ IADD(Classfile.IADD, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Add long */ LADD(Classfile.LADD, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Add float */ FADD(Classfile.FADD, 1, Kind.OPERATOR, TypeKind.FloatType), + + /** Add double */ DADD(Classfile.DADD, 1, Kind.OPERATOR, TypeKind.DoubleType), + + /** Subtract int */ ISUB(Classfile.ISUB, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Subtract long */ LSUB(Classfile.LSUB, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Subtract float */ FSUB(Classfile.FSUB, 1, Kind.OPERATOR, TypeKind.FloatType), + + /** Subtract double */ DSUB(Classfile.DSUB, 1, Kind.OPERATOR, TypeKind.DoubleType), + + /** Multiply int */ IMUL(Classfile.IMUL, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Multiply long */ LMUL(Classfile.LMUL, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Multiply float */ FMUL(Classfile.FMUL, 1, Kind.OPERATOR, TypeKind.FloatType), + + /** Multiply double */ DMUL(Classfile.DMUL, 1, Kind.OPERATOR, TypeKind.DoubleType), + + /** Divide int */ IDIV(Classfile.IDIV, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Divide long */ LDIV(Classfile.LDIV, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Divide float */ FDIV(Classfile.FDIV, 1, Kind.OPERATOR, TypeKind.FloatType), + + /** Divide double */ DDIV(Classfile.DDIV, 1, Kind.OPERATOR, TypeKind.DoubleType), + + /** Remainder int */ IREM(Classfile.IREM, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Remainder long */ LREM(Classfile.LREM, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Remainder float */ FREM(Classfile.FREM, 1, Kind.OPERATOR, TypeKind.FloatType), + + /** Remainder double */ DREM(Classfile.DREM, 1, Kind.OPERATOR, TypeKind.DoubleType), + + /** Negate int */ INEG(Classfile.INEG, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Negate long */ LNEG(Classfile.LNEG, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Negate float */ FNEG(Classfile.FNEG, 1, Kind.OPERATOR, TypeKind.FloatType), + + /** Negate double */ DNEG(Classfile.DNEG, 1, Kind.OPERATOR, TypeKind.DoubleType), + + /** Shift left int */ ISHL(Classfile.ISHL, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Shift left long */ LSHL(Classfile.LSHL, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Shift right int */ ISHR(Classfile.ISHR, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Shift right long */ LSHR(Classfile.LSHR, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Logical shift right int */ IUSHR(Classfile.IUSHR, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Logical shift right long */ LUSHR(Classfile.LUSHR, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Boolean AND int */ IAND(Classfile.IAND, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Boolean AND long */ LAND(Classfile.LAND, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Boolean OR int */ IOR(Classfile.IOR, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Boolean OR long */ LOR(Classfile.LOR, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Boolean XOR int */ IXOR(Classfile.IXOR, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Boolean XOR long */ LXOR(Classfile.LXOR, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Increment local variable by constant */ IINC(Classfile.IINC, 3, Kind.INCREMENT, TypeKind.IntType, -1), + + /** Convert int to long */ I2L(Classfile.I2L, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.LongType), + + /** Convert int to float */ I2F(Classfile.I2F, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.FloatType), + + /** Convert int to double */ I2D(Classfile.I2D, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.DoubleType), + + /** Convert long to int */ L2I(Classfile.L2I, 1, Kind.CONVERT, TypeKind.LongType, TypeKind.IntType), + + /** Convert long to float */ L2F(Classfile.L2F, 1, Kind.CONVERT, TypeKind.LongType, TypeKind.FloatType), + + /** Convert long to double */ L2D(Classfile.L2D, 1, Kind.CONVERT, TypeKind.LongType, TypeKind.DoubleType), + + /** Convert float to int */ F2I(Classfile.F2I, 1, Kind.CONVERT, TypeKind.FloatType, TypeKind.IntType), + + /** Convert float to long */ F2L(Classfile.F2L, 1, Kind.CONVERT, TypeKind.FloatType, TypeKind.LongType), + + /** Convert float to double */ F2D(Classfile.F2D, 1, Kind.CONVERT, TypeKind.FloatType, TypeKind.DoubleType), + + /** Convert double to int */ D2I(Classfile.D2I, 1, Kind.CONVERT, TypeKind.DoubleType, TypeKind.IntType), + + /** Convert double to long */ D2L(Classfile.D2L, 1, Kind.CONVERT, TypeKind.DoubleType, TypeKind.LongType), + + /** Convert double to float */ D2F(Classfile.D2F, 1, Kind.CONVERT, TypeKind.DoubleType, TypeKind.FloatType), + + /** Convert int to byte */ I2B(Classfile.I2B, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.ByteType), + + /** Convert int to char */ I2C(Classfile.I2C, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.CharType), + + /** Convert int to short */ I2S(Classfile.I2S, 1, Kind.CONVERT, TypeKind.IntType, TypeKind.ShortType), + + /** Compare long */ LCMP(Classfile.LCMP, 1, Kind.OPERATOR, TypeKind.LongType), + + /** Compare float */ FCMPL(Classfile.FCMPL, 1, Kind.OPERATOR, TypeKind.FloatType), + + /** Compare float */ FCMPG(Classfile.FCMPG, 1, Kind.OPERATOR, TypeKind.FloatType), + + /** Compare double */ DCMPL(Classfile.DCMPL, 1, Kind.OPERATOR, TypeKind.DoubleType), + + /** Compare double */ DCMPG(Classfile.DCMPG, 1, Kind.OPERATOR, TypeKind.DoubleType), + + /** Branch if int comparison with zero succeeds */ IFEQ(Classfile.IFEQ, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison with zero succeeds */ IFNE(Classfile.IFNE, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison with zero succeeds */ IFLT(Classfile.IFLT, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison with zero succeeds */ IFGE(Classfile.IFGE, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison with zero succeeds */ IFGT(Classfile.IFGT, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison with zero succeeds */ IFLE(Classfile.IFLE, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison succeeds */ IF_ICMPEQ(Classfile.IF_ICMPEQ, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison succeeds */ IF_ICMPNE(Classfile.IF_ICMPNE, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison succeeds */ IF_ICMPLT(Classfile.IF_ICMPLT, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison succeeds */ IF_ICMPGE(Classfile.IF_ICMPGE, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison succeeds */ IF_ICMPGT(Classfile.IF_ICMPGT, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if int comparison succeeds */ IF_ICMPLE(Classfile.IF_ICMPLE, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch if reference comparison succeeds */ IF_ACMPEQ(Classfile.IF_ACMPEQ, 3, Kind.BRANCH, TypeKind.ReferenceType), + + /** Branch if reference comparison succeeds */ IF_ACMPNE(Classfile.IF_ACMPNE, 3, Kind.BRANCH, TypeKind.ReferenceType), + + /** Branch always */ GOTO(Classfile.GOTO, 3, Kind.BRANCH, TypeKind.VoidType), + + /** Jump subroutine */ JSR(Classfile.JSR, 3, Kind.DISCONTINUED_JSR), + + /** Return from subroutine */ RET(Classfile.RET, 2, Kind.DISCONTINUED_RET), + + /** Access jump table by index and jump */ TABLESWITCH(Classfile.TABLESWITCH, -1, Kind.TABLE_SWITCH), + + /** Access jump table by key match and jump */ LOOKUPSWITCH(Classfile.LOOKUPSWITCH, -1, Kind.LOOKUP_SWITCH), + + /** Return int from method */ IRETURN(Classfile.IRETURN, 1, Kind.RETURN, TypeKind.IntType), + + /** Return long from method */ LRETURN(Classfile.LRETURN, 1, Kind.RETURN, TypeKind.LongType), + + /** Return float from method */ FRETURN(Classfile.FRETURN, 1, Kind.RETURN, TypeKind.FloatType), + + /** Return double from method */ DRETURN(Classfile.DRETURN, 1, Kind.RETURN, TypeKind.DoubleType), + + /** Return reference from method */ ARETURN(Classfile.ARETURN, 1, Kind.RETURN, TypeKind.ReferenceType), + + /** Return void from method */ RETURN(Classfile.RETURN, 1, Kind.RETURN, TypeKind.VoidType), + + /** Get static field from class */ GETSTATIC(Classfile.GETSTATIC, 3, Kind.FIELD_ACCESS), + + /** Set static field in class */ PUTSTATIC(Classfile.PUTSTATIC, 3, Kind.FIELD_ACCESS), + + /** Fetch field from object */ GETFIELD(Classfile.GETFIELD, 3, Kind.FIELD_ACCESS), + + /** Set field in object */ PUTFIELD(Classfile.PUTFIELD, 3, Kind.FIELD_ACCESS), + + /** Invoke instance method; dispatch based on class */ INVOKEVIRTUAL(Classfile.INVOKEVIRTUAL, 3, Kind.INVOKE), + + /** + * Invoke instance method; direct invocation of instance initialization + * methods and methods of the current class and its supertypes + */ INVOKESPECIAL(Classfile.INVOKESPECIAL, 3, Kind.INVOKE), + + /** Invoke a class (static) method */ INVOKESTATIC(Classfile.INVOKESTATIC, 3, Kind.INVOKE), + + /** Invoke interface method */ INVOKEINTERFACE(Classfile.INVOKEINTERFACE, 5, Kind.INVOKE), + + /** Invoke a dynamically-computed call site */ INVOKEDYNAMIC(Classfile.INVOKEDYNAMIC, 5, Kind.INVOKE_DYNAMIC), + + /** Create new object */ NEW(Classfile.NEW, 3, Kind.NEW_OBJECT), + + /** Create new array */ NEWARRAY(Classfile.NEWARRAY, 2, Kind.NEW_PRIMITIVE_ARRAY), + + /** Create new array of reference */ ANEWARRAY(Classfile.ANEWARRAY, 3, Kind.NEW_REF_ARRAY), + + /** Get length of array */ ARRAYLENGTH(Classfile.ARRAYLENGTH, 1, Kind.OPERATOR, TypeKind.IntType), + + /** Throw exception or error */ ATHROW(Classfile.ATHROW, 1, Kind.THROW_EXCEPTION), + + /** Check whether object is of given type */ CHECKCAST(Classfile.CHECKCAST, 3, Kind.TYPE_CHECK), + + /** Determine if object is of given type */ INSTANCEOF(Classfile.INSTANCEOF, 3, Kind.TYPE_CHECK), + + /** Enter monitor for object */ MONITORENTER(Classfile.MONITORENTER, 1, Kind.MONITOR), + + /** Exit monitor for object */ MONITOREXIT(Classfile.MONITOREXIT, 1, Kind.MONITOR), + + /** Create new multidimensional array */ MULTIANEWARRAY(Classfile.MULTIANEWARRAY, 4, Kind.NEW_MULTI_ARRAY), + + /** Branch if reference is null */ IFNULL(Classfile.IFNULL, 3, Kind.BRANCH, TypeKind.ReferenceType), + + /** Branch if reference not null */ IFNONNULL(Classfile.IFNONNULL, 3, Kind.BRANCH, TypeKind.IntType), + + /** Branch always (wide index) */ GOTO_W(Classfile.GOTO_W, 5, Kind.BRANCH, TypeKind.VoidType), + + /** Jump subroutine (wide index) */ JSR_W(Classfile.JSR_W, 5, Kind.DISCONTINUED_JSR), + + /** Load int from local variable (wide index) */ ILOAD_W((Classfile.WIDE << 8) | Classfile.ILOAD, 4, Kind.LOAD, TypeKind.IntType, -1), + + /** Load long from local variable (wide index) */ LLOAD_W((Classfile.WIDE << 8) | Classfile.LLOAD, 4, Kind.LOAD, TypeKind.LongType, -1), + + /** Load float from local variable (wide index) */ FLOAD_W((Classfile.WIDE << 8) | Classfile.FLOAD, 4, Kind.LOAD, TypeKind.FloatType, -1), + + /** Load double from local variable (wide index) */ DLOAD_W((Classfile.WIDE << 8) | Classfile.DLOAD, 4, Kind.LOAD, TypeKind.DoubleType, -1), + + /** Load reference from local variable (wide index) */ ALOAD_W((Classfile.WIDE << 8) | Classfile.ALOAD, 4, Kind.LOAD, TypeKind.ReferenceType, -1), + + /** Store int into local variable (wide index) */ ISTORE_W((Classfile.WIDE << 8) | Classfile.ISTORE, 4, Kind.STORE, TypeKind.IntType, -1), + + /** Store long into local variable (wide index) */ LSTORE_W((Classfile.WIDE << 8) | Classfile.LSTORE, 4, Kind.STORE, TypeKind.LongType, -1), + + /** Store float into local variable (wide index) */ FSTORE_W((Classfile.WIDE << 8) | Classfile.FSTORE, 4, Kind.STORE, TypeKind.FloatType, -1), + + /** Store double into local variable (wide index) */ DSTORE_W((Classfile.WIDE << 8) | Classfile.DSTORE, 4, Kind.STORE, TypeKind.DoubleType, -1), + + /** Store reference into local variable (wide index) */ ASTORE_W((Classfile.WIDE << 8) | Classfile.ASTORE, 4, Kind.STORE, TypeKind.ReferenceType, -1), + + /** Return from subroutine (wide index) */ RET_W((Classfile.WIDE << 8) | Classfile.RET, 4, Kind.DISCONTINUED_RET), + + /** Increment local variable by constant (wide index) */ IINC_W((Classfile.WIDE << 8) | Classfile.IINC, 6, Kind.INCREMENT, TypeKind.IntType, -1); /** * Kinds of opcodes. */ public static enum Kind { - LOAD, STORE, INCREMENT, BRANCH, LOOKUP_SWITCH, TABLE_SWITCH, RETURN, THROW_EXCEPTION, - FIELD_ACCESS, INVOKE, INVOKE_DYNAMIC, - NEW_OBJECT, NEW_PRIMITIVE_ARRAY, NEW_REF_ARRAY, NEW_MULTI_ARRAY, - TYPE_CHECK, ARRAY_LOAD, ARRAY_STORE, STACK, CONVERT, OPERATOR, CONSTANT, - MONITOR, NOP, DISCONTINUED_JSR, DISCONTINUED_RET; + + /** + * Load from local variable + * + * @see Opcode#ILOAD + * @see Opcode#LLOAD + * @see Opcode#FLOAD + * @see Opcode#DLOAD + * @see Opcode#ALOAD + * @see Opcode#ILOAD_0 + * @see Opcode#ILOAD_1 + * @see Opcode#ILOAD_2 + * @see Opcode#ILOAD_3 + * @see Opcode#LLOAD_0 + * @see Opcode#LLOAD_1 + * @see Opcode#LLOAD_2 + * @see Opcode#LLOAD_3 + * @see Opcode#FLOAD_0 + * @see Opcode#FLOAD_1 + * @see Opcode#FLOAD_2 + * @see Opcode#FLOAD_3 + * @see Opcode#DLOAD_0 + * @see Opcode#DLOAD_1 + * @see Opcode#DLOAD_2 + * @see Opcode#DLOAD_3 + * @see Opcode#ALOAD_0 + * @see Opcode#ALOAD_1 + * @see Opcode#ALOAD_2 + * @see Opcode#ALOAD_3 + * @see Opcode#ILOAD_W + * @see Opcode#LLOAD_W + * @see Opcode#FLOAD_W + * @see Opcode#DLOAD_W + * @see Opcode#ALOAD_W + */ + LOAD, + + /** + * Store into local variable + * + * @see Opcode#ISTORE + * @see Opcode#LSTORE + * @see Opcode#FSTORE + * @see Opcode#DSTORE + * @see Opcode#ASTORE + * @see Opcode#ISTORE_0 + * @see Opcode#ISTORE_1 + * @see Opcode#ISTORE_2 + * @see Opcode#ISTORE_3 + * @see Opcode#LSTORE_0 + * @see Opcode#LSTORE_1 + * @see Opcode#LSTORE_2 + * @see Opcode#LSTORE_3 + * @see Opcode#FSTORE_0 + * @see Opcode#FSTORE_1 + * @see Opcode#FSTORE_2 + * @see Opcode#FSTORE_3 + * @see Opcode#DSTORE_0 + * @see Opcode#DSTORE_1 + * @see Opcode#DSTORE_2 + * @see Opcode#DSTORE_3 + * @see Opcode#ASTORE_0 + * @see Opcode#ASTORE_1 + * @see Opcode#ASTORE_2 + * @see Opcode#ASTORE_3 + * @see Opcode#ISTORE_W + * @see Opcode#LSTORE_W + * @see Opcode#FSTORE_W + * @see Opcode#DSTORE_W + * @see Opcode#ASTORE_W + */ + STORE, + + /** + * Increment local variable + * + * @see Opcode#IINC + * @see Opcode#IINC_W + */ + INCREMENT, + + /** + * Branch + * + * @see Opcode#IFEQ + * @see Opcode#IFNE + * @see Opcode#IFLT + * @see Opcode#IFGE + * @see Opcode#IFGT + * @see Opcode#IFLE + * @see Opcode#IF_ICMPEQ + * @see Opcode#IF_ICMPNE + * @see Opcode#IF_ICMPLT + * @see Opcode#IF_ICMPGE + * @see Opcode#IF_ICMPGT + * @see Opcode#IF_ICMPLE + * @see Opcode#IF_ACMPEQ + * @see Opcode#IF_ACMPNE + * @see Opcode#GOTO + * @see Opcode#IFNULL + * @see Opcode#IFNONNULL + * @see Opcode#GOTO_W + */ + BRANCH, + + /** + * Access jump table by key match and jump + * + * @see Opcode#LOOKUPSWITCH + */ + LOOKUP_SWITCH, + + /** + * Access jump table by index and jump + * + * @see Opcode#TABLESWITCH + */ + TABLE_SWITCH, + + /** + * Return from method + * + * @see Opcode#IRETURN + * @see Opcode#LRETURN + * @see Opcode#FRETURN + * @see Opcode#DRETURN + * @see Opcode#ARETURN + * @see Opcode#RETURN + */ + RETURN, + + /** + * Throw exception or error + * + * @see Opcode#ATHROW + */ + THROW_EXCEPTION, + + /** + * Access field + * + * @see Opcode#GETSTATIC + * @see Opcode#PUTSTATIC + * @see Opcode#GETFIELD + * @see Opcode#PUTFIELD + */ + FIELD_ACCESS, + + /** + * Invoke method or constructor + * + * @see Opcode#INVOKEVIRTUAL + * @see Opcode#INVOKESPECIAL + * @see Opcode#INVOKESTATIC + * @see Opcode#INVOKEINTERFACE + */ + INVOKE, + + /** + * Invoke a dynamically-computed call site + * + * @see Opcode#INVOKEDYNAMIC + */ + INVOKE_DYNAMIC, + + /** + * Create new object + * + * @see Opcode#NEW + */ + NEW_OBJECT, + + /** + * Create new array + * + * @see Opcode#NEWARRAY + */ + NEW_PRIMITIVE_ARRAY, + + /** + * Create new reference array + * + * @see Opcode#ANEWARRAY + */ + NEW_REF_ARRAY, + + /** + * Create new multidimensional array + * + * @see Opcode#MULTIANEWARRAY + */ + NEW_MULTI_ARRAY, + + /** + * Check whether object is of given type + * + * @see Opcode#CHECKCAST + * @see Opcode#INSTANCEOF + */ + TYPE_CHECK, + + /** + * Load from array + * + * @see Opcode#IALOAD + * @see Opcode#LALOAD + * @see Opcode#FALOAD + * @see Opcode#DALOAD + * @see Opcode#AALOAD + * @see Opcode#BALOAD + * @see Opcode#CALOAD + * @see Opcode#SALOAD + */ + ARRAY_LOAD, + + /** + * Store into array + * + * @see Opcode#IASTORE + * @see Opcode#LASTORE + * @see Opcode#FASTORE + * @see Opcode#DASTORE + * @see Opcode#AASTORE + * @see Opcode#BASTORE + * @see Opcode#CASTORE + * @see Opcode#SASTORE + */ + ARRAY_STORE, + + /** + * Stack operations + * + * @see Opcode#POP + * @see Opcode#POP2 + * @see Opcode#DUP + * @see Opcode#DUP_X1 + * @see Opcode#DUP_X2 + * @see Opcode#DUP2 + * @see Opcode#DUP2_X1 + * @see Opcode#DUP2_X2 + * @see Opcode#SWAP + */ + STACK, + + /** + * Type conversions + * + * @see Opcode#I2L + * @see Opcode#I2F + * @see Opcode#I2D + * @see Opcode#L2I + * @see Opcode#L2F + * @see Opcode#L2D + * @see Opcode#F2I + * @see Opcode#F2L + * @see Opcode#F2D + * @see Opcode#D2I + * @see Opcode#D2L + * @see Opcode#D2F + * @see Opcode#I2B + * @see Opcode#I2C + * @see Opcode#I2S + */ + CONVERT, + + /** + * Operators + * + * @see Opcode#IADD + * @see Opcode#LADD + * @see Opcode#FADD + * @see Opcode#DADD + * @see Opcode#ISUB + * @see Opcode#LSUB + * @see Opcode#FSUB + * @see Opcode#DSUB + * @see Opcode#IMUL + * @see Opcode#LMUL + * @see Opcode#FMUL + * @see Opcode#DMUL + * @see Opcode#IDIV + * @see Opcode#LDIV + * @see Opcode#FDIV + * @see Opcode#DDIV + * @see Opcode#IREM + * @see Opcode#LREM + * @see Opcode#FREM + * @see Opcode#DREM + * @see Opcode#INEG + * @see Opcode#LNEG + * @see Opcode#FNEG + * @see Opcode#DNEG + * @see Opcode#ISHL + * @see Opcode#LSHL + * @see Opcode#ISHR + * @see Opcode#LSHR + * @see Opcode#IUSHR + * @see Opcode#LUSHR + * @see Opcode#IAND + * @see Opcode#LAND + * @see Opcode#IOR + * @see Opcode#LOR + * @see Opcode#IXOR + * @see Opcode#LXOR + * @see Opcode#LCMP + * @see Opcode#FCMPL + * @see Opcode#FCMPG + * @see Opcode#DCMPL + * @see Opcode#DCMPG + * @see Opcode#ARRAYLENGTH + */ + OPERATOR, + + /** + * Constants + * + * @see Opcode#ACONST_NULL + * @see Opcode#ICONST_M1 + * @see Opcode#ICONST_0 + * @see Opcode#ICONST_1 + * @see Opcode#ICONST_2 + * @see Opcode#ICONST_3 + * @see Opcode#ICONST_4 + * @see Opcode#ICONST_5 + * @see Opcode#LCONST_0 + * @see Opcode#LCONST_1 + * @see Opcode#FCONST_0 + * @see Opcode#FCONST_1 + * @see Opcode#FCONST_2 + * @see Opcode#DCONST_0 + * @see Opcode#DCONST_1 + * @see Opcode#BIPUSH + * @see Opcode#SIPUSH + * @see Opcode#LDC + * @see Opcode#LDC_W + * @see Opcode#LDC2_W + */ + CONSTANT, + + /** + * Monitor + * + * @see Opcode#MONITORENTER + * @see Opcode#MONITOREXIT + */ + MONITOR, + + /** + * Do nothing + * + * @see Opcode#NOP + */ + NOP, + + /** + * Discontinued jump subroutine + * + * @see Opcode#JSR + * @see Opcode#JSR_W + */ + DISCONTINUED_JSR, + + /** + * Discontinued return from subroutine + * + * @see Opcode#RET + * @see Opcode#RET_W + */ + DISCONTINUED_RET; } private final int bytecode; @@ -270,11 +1063,11 @@ public static enum Kind { private final ConstantDesc constantValue; Opcode(int bytecode, int sizeIfFixed, Kind kind) { - this(bytecode, sizeIfFixed, kind, null, null, 0, null); + this(bytecode, sizeIfFixed, kind, null, null, -1, null); } Opcode(int bytecode, int sizeIfFixed, Kind kind, TypeKind typeKind) { - this(bytecode, sizeIfFixed, kind, typeKind, null, 0, null); + this(bytecode, sizeIfFixed, kind, typeKind, null, -1, null); } Opcode(int bytecode, int sizeIfFixed, Kind kind, TypeKind typeKind, int slot) { @@ -305,30 +1098,57 @@ public static enum Kind { this.constantValue = constantValue; } + /** + * {@return bytecode} + */ public int bytecode() { return bytecode; } + /** + * {@return true if the instruction has extended local variable index by additional bytes} + */ public boolean isWide() { return bytecode > 255; } + /** + * {@return size of the instruction if fixed, or -1 otherwise} + */ public int sizeIfFixed() { return sizeIfFixed; } + /** + * {@return instruction kind} + */ public Kind kind() { return kind; } + /** + * {@return primary type kind for instructions operating with at least one type, or null otherwise} + */ public TypeKind primaryTypeKind() { return primaryTypeKind; } + /** + * {@return secondary type kind for instructions operating with two types, or null otherwise} + */ public TypeKind secondaryTypeKind() { return secondaryTypeKind; } + /** + * {@return local variable slot for instructions operating with local variable, or -1 otherwise} + */ public int slot() { return slot; } + /** + * {@return constant value for constant instructions, or null otherwise} + */ public ConstantDesc constantValue() { return constantValue; } + /** + * {@return true if the instruction represents an unconditional branch} + */ public boolean isUnconditionalBranch() { return switch (this) { case GOTO, ATHROW, GOTO_W, LOOKUPSWITCH, TABLESWITCH -> true; diff --git a/src/java.base/share/classes/jdk/internal/classfile/Signature.java b/src/java.base/share/classes/jdk/internal/classfile/Signature.java index 9e513ff622b..ae32ad7d84d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/Signature.java +++ b/src/java.base/share/classes/jdk/internal/classfile/Signature.java @@ -176,7 +176,26 @@ public sealed interface TypeArg * an upper bound, or a lower bound */ public enum WildcardIndicator { - DEFAULT, UNBOUNDED, EXTENDS, SUPER; + + /** + * default bound wildcard (empty) + */ + DEFAULT, + + /** + * unbounded indicator {@code *} + */ + UNBOUNDED, + + /** + * upper-bounded indicator {@code +} + */ + EXTENDS, + + /** + * lower-bounded indicator {@code -} + */ + SUPER; } /** {@return the wildcard indicator} */ diff --git a/src/java.base/share/classes/jdk/internal/classfile/TypeAnnotation.java b/src/java.base/share/classes/jdk/internal/classfile/TypeAnnotation.java index 3572ea20f09..4b9c1f1bbc4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/jdk/internal/classfile/TypeAnnotation.java @@ -59,7 +59,7 @@ import jdk.internal.classfile.impl.TemporaryConstantPool; /** - * Models an annotation on a type use. + * Models an annotation on a type use, as defined in {@jvms 4.7.19} and {@jvms 4.7.20}. * * @see RuntimeVisibleTypeAnnotationsAttribute * @see RuntimeInvisibleTypeAnnotationsAttribute @@ -69,7 +69,7 @@ public sealed interface TypeAnnotation permits UnboundAttribute.UnboundTypeAnnotation { /** - * The kind of target on which the annotation appears. + * The kind of target on which the annotation appears, as defined in {@jvms 4.7.20.1}. */ public enum TargetType { /** For annotations on a class type parameter declaration. */ @@ -146,10 +146,16 @@ private TargetType(int targetTypeValue, int sizeIfFixed) { this.sizeIfFixed = sizeIfFixed; } + /** + * {@return the target type value} + */ public int targetTypeValue() { return targetTypeValue; } + /** + * {@return the size of the target type if fixed or -1 if variable} + */ public int sizeIfFixed() { return sizeIfFixed; } @@ -225,120 +231,269 @@ static TypeAnnotation of(TargetInfo targetInfo, List targetPa */ sealed interface TargetInfo { + /** + * {@return the type of the target} + */ TargetType targetType(); + /** + * {@return the size of the target info} + */ default int size() { return targetType().sizeIfFixed; } + /** + * {@return a target for annotations on a class or method type parameter declaration} + * @param targetType {@link TargetType#CLASS_TYPE_PARAMETER} or {@link TargetType#METHOD_TYPE_PARAMETER} + * @param typeParameterIndex specifies which type parameter declaration is annotated + */ static TypeParameterTarget ofTypeParameter(TargetType targetType, int typeParameterIndex) { return new TargetInfoImpl.TypeParameterTargetImpl(targetType, typeParameterIndex); } + /** + * {@return a target for annotations on a class type parameter declaration} + * @param typeParameterIndex specifies which type parameter declaration is annotated + */ static TypeParameterTarget ofClassTypeParameter(int typeParameterIndex) { return ofTypeParameter(TargetType.CLASS_TYPE_PARAMETER, typeParameterIndex); } + /** + * {@return a target for annotations on a method type parameter declaration} + * @param typeParameterIndex specifies which type parameter declaration is annotated + */ static TypeParameterTarget ofMethodTypeParameter(int typeParameterIndex) { return ofTypeParameter(TargetType.METHOD_TYPE_PARAMETER, typeParameterIndex); } + /** + * {@return a target for annotations on the type of an "extends" or "implements" clause} + * @param supertypeIndex the index into the interfaces array or 65535 to indicate it is the superclass + */ static SupertypeTarget ofClassExtends(int supertypeIndex) { return new TargetInfoImpl.SupertypeTargetImpl(supertypeIndex); } + /** + * {@return a target for annotations on the i'th bound of the j'th type parameter declaration of + * a generic class, interface, method, or constructor} + * @param targetType {@link TargetType#CLASS_TYPE_PARAMETER_BOUND} or {@link TargetType#METHOD_TYPE_PARAMETER_BOUND} + * @param typeParameterIndex specifies which type parameter declaration is annotated + * @param boundIndex specifies which bound of the type parameter declaration is annotated + */ static TypeParameterBoundTarget ofTypeParameterBound(TargetType targetType, int typeParameterIndex, int boundIndex) { return new TargetInfoImpl.TypeParameterBoundTargetImpl(targetType, typeParameterIndex, boundIndex); } + /** + * {@return a target for annotations on the i'th bound of the j'th type parameter declaration of + * a generic class, or interface} + * @param typeParameterIndex specifies which type parameter declaration is annotated + * @param boundIndex specifies which bound of the type parameter declaration is annotated + */ static TypeParameterBoundTarget ofClassTypeParameterBound(int typeParameterIndex, int boundIndex) { return ofTypeParameterBound(TargetType.CLASS_TYPE_PARAMETER_BOUND, typeParameterIndex, boundIndex); } + /** + * {@return a target for annotations on the i'th bound of the j'th type parameter declaration of + * a generic method, or constructor} + * @param typeParameterIndex specifies which type parameter declaration is annotated + * @param boundIndex specifies which bound of the type parameter declaration is annotated + */ static TypeParameterBoundTarget ofMethodTypeParameterBound(int typeParameterIndex, int boundIndex) { return ofTypeParameterBound(TargetType.METHOD_TYPE_PARAMETER_BOUND, typeParameterIndex, boundIndex); } + /** + * {@return a target for annotations} + * @param targetType {@link TargetType#FIELD}, {@link TargetType#METHOD_RETURN} or {@link TargetType#METHOD_RECEIVER} + */ static EmptyTarget of(TargetType targetType) { return new TargetInfoImpl.EmptyTargetImpl(targetType); } + /** + * {@return a target for annotations on the type in a field or record declaration} + */ static EmptyTarget ofField() { return of(TargetType.FIELD); } + /** + * {@return a target for annotations on the return type of a method or a newly constructed object} + */ static EmptyTarget ofMethodReturn() { return of(TargetType.METHOD_RETURN); } + /** + * {@return a target for annotations on the receiver type of a method or constructor} + */ static EmptyTarget ofMethodReceiver() { return of(TargetType.METHOD_RECEIVER); } + /** + * {@return a target for annotations on the type in a formal parameter declaration of a method, + * constructor, or lambda expression} + * @param formalParameterIndex specifies which formal parameter declaration has an annotated type + */ static FormalParameterTarget ofMethodFormalParameter(int formalParameterIndex) { return new TargetInfoImpl.FormalParameterTargetImpl(formalParameterIndex); } + /** + * {@return a target for annotations on the i'th type in the throws clause of a method or + * constructor declaration} + * @param throwsTargetIndex the index into the exception table of the Exceptions attribute of the method + */ static ThrowsTarget ofThrows(int throwsTargetIndex) { return new TargetInfoImpl.ThrowsTargetImpl(throwsTargetIndex); } + /** + * {@return a target for annotations on the type in a local variable declaration, + * including a variable declared as a resource in a try-with-resources statement} + * @param targetType {@link TargetType#LOCAL_VARIABLE} or {@link TargetType#RESOURCE_VARIABLE} + * @param table the list of local variable targets + */ static LocalVarTarget ofVariable(TargetType targetType, List table) { return new TargetInfoImpl.LocalVarTargetImpl(targetType, table); } + /** + * {@return a target for annotations on the type in a local variable declaration} + * @param table the list of local variable targets + */ static LocalVarTarget ofLocalVariable(List table) { return ofVariable(TargetType.LOCAL_VARIABLE, table); } + /** + * {@return a target for annotations on the type in a local variable declared + * as a resource in a try-with-resources statement} + * @param table the list of local variable targets + */ static LocalVarTarget ofResourceVariable(List table) { return ofVariable(TargetType.RESOURCE_VARIABLE, table); } + /** + * {@return a target for annotations on the i'th type in an exception parameter declaration} + * @param exceptionTableIndex the index into the exception table of the Code attribute + */ static CatchTarget ofExceptionParameter(int exceptionTableIndex) { return new TargetInfoImpl.CatchTargetImpl(exceptionTableIndex); } + /** + * {@return a target for annotations on the type in an instanceof expression or a new expression, + * or the type before the :: in a method reference expression} + * {@param targetType {@link TargetType#INSTANCEOF}, {@link TargetType#NEW}, + * {@link TargetType#CONSTRUCTOR_REFERENCE}, + * or {@link TargetType#METHOD_REFERENCE}} + * @param target the code label corresponding to the instruction + */ static OffsetTarget ofOffset(TargetType targetType, Label target) { return new TargetInfoImpl.OffsetTargetImpl(targetType, target); } + /** + * {@return a target for annotations on the type in an instanceof expression} + * @param target the code label corresponding to the instruction + */ static OffsetTarget ofInstanceofExpr(Label target) { return ofOffset(TargetType.INSTANCEOF, target); } + /** + * {@return a target for annotations on the type in a new expression} + * @param target the code label corresponding to the instruction + */ static OffsetTarget ofNewExpr(Label target) { return ofOffset(TargetType.NEW, target); } + /** + * {@return a target for annotations on the type before the :: in a constructor reference expression} + * @param target the code label corresponding to the instruction + */ static OffsetTarget ofConstructorReference(Label target) { return ofOffset(TargetType.CONSTRUCTOR_REFERENCE, target); } + /** + * {@return a target for annotations on the type before the :: in a method reference expression} + * @param target the code label corresponding to the instruction + */ static OffsetTarget ofMethodReference(Label target) { return ofOffset(TargetType.METHOD_REFERENCE, target); } + /** + * {@return a target for annotations on the i'th type in a cast expression, + * or on the i'th type argument in the explicit type argument list for any of the following: + * a new expression, an explicit constructor invocation statement, a method invocation expression, + * or a method reference expression} + * {@param targetType {@link TargetType#CAST}, {@link TargetType#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, + * {@link TargetType#METHOD_INVOCATION_TYPE_ARGUMENT}, + * {@link TargetType#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, + * or {@link TargetType#METHOD_REFERENCE_TYPE_ARGUMENT}} + * @param target the code label corresponding to the instruction + * @param typeArgumentIndex specifies which type in the cast operator or argument is annotated + */ static TypeArgumentTarget ofTypeArgument(TargetType targetType, Label target, int typeArgumentIndex) { return new TargetInfoImpl.TypeArgumentTargetImpl(targetType, target, typeArgumentIndex); } + /** + * {@return a target for annotations on the i'th type in a cast expression} + * @param target the code label corresponding to the instruction + * @param typeArgumentIndex specifies which type in the cast operator is annotated + */ static TypeArgumentTarget ofCastExpr(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.CAST, target, typeArgumentIndex); } + /** + * {@return a target for annotations on the i'th type argument in the explicit type argument list for + * an explicit constructor invocation statement} + * @param target the code label corresponding to the instruction + * @param typeArgumentIndex specifies which type in the argument is annotated + */ static TypeArgumentTarget ofConstructorInvocationTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, target, typeArgumentIndex); } + /** + * {@return a target for annotations on the i'th type argument in the explicit type argument list for + * a method invocation expression} + * @param target the code label corresponding to the instruction + * @param typeArgumentIndex specifies which type in the argument is annotated + */ static TypeArgumentTarget ofMethodInvocationTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.METHOD_INVOCATION_TYPE_ARGUMENT, target, typeArgumentIndex); } + /** + * {@return a target for annotations on the i'th type argument in the explicit type argument list for + * a new expression} + * @param target the code label corresponding to the instruction + * @param typeArgumentIndex specifies which type in the argument is annotated + */ static TypeArgumentTarget ofConstructorReferenceTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT, target, typeArgumentIndex); } + /** + * {@return a target for annotations on the i'th type argument in the explicit type argument list for + * a method reference expression} + * @param target the code label corresponding to the instruction + * @param typeArgumentIndex specifies which type in the argument is annotated + */ static TypeArgumentTarget ofMethodReferenceTypeArgument(Label target, int typeArgumentIndex) { return ofTypeArgument(TargetType.METHOD_REFERENCE_TYPE_ARGUMENT, target, typeArgumentIndex); } @@ -441,7 +596,7 @@ sealed interface ThrowsTarget extends TargetInfo * Exceptions attribute of the method_info structure enclosing the * RuntimeVisibleTypeAnnotations attribute. * - * @return index into the list jdk.internal.classfile.attribute.ExceptionsAttribute.exceptions() + * @return the index into the list jdk.internal.classfile.attribute.ExceptionsAttribute.exceptions() */ int throwsTargetIndex(); } @@ -471,7 +626,7 @@ sealed interface LocalVarTargetInfo * The given local variable has a value at indices into the code array in the interval * [start_pc, start_pc + length), that is, between start_pc inclusive and start_pc + length exclusive. * - * @return the start of the bytecode section. + * @return the start of the bytecode section */ Label startLabel(); @@ -480,7 +635,7 @@ sealed interface LocalVarTargetInfo * The given local variable has a value at indices into the code array in the interval * [start_pc, start_pc + length), that is, between start_pc inclusive and start_pc + length exclusive. * - * @return + * @return the end of the bytecode section */ Label endLabel(); @@ -489,10 +644,16 @@ sealed interface LocalVarTargetInfo * * If the local variable at index is of type double or long, it occupies both index and index + 1. * - * @return index into the local variables + * @return the index into the local variables */ int index(); + /** + * {@return local variable target info} + * @param startLabel the code label indicating start of an interval where variable has value + * @param endLabel the code label indicating start of an interval where variable has value + * @param index index into the local variables + */ static LocalVarTargetInfo of(Label startLabel, Label endLabel, int index) { return new TargetInfoImpl.LocalVarTargetInfoImpl(startLabel, endLabel, index); } @@ -526,7 +687,7 @@ sealed interface OffsetTarget extends TargetInfo * corresponding to the instanceof expression, the new bytecode instruction corresponding to the new * expression, or the bytecode instruction corresponding to the method reference expression. * - * @return + * @return the code label corresponding to the instruction */ Label target(); } @@ -547,7 +708,7 @@ sealed interface TypeArgumentTarget extends TargetInfo * instruction corresponding to the method invocation expression, or the bytecode instruction corresponding to * the method reference expression. * - * @return + * @return the code label corresponding to the instruction */ Label target(); @@ -567,31 +728,27 @@ sealed interface TypeArgumentTarget extends TargetInfo } /** - * JVMS: Wherever a type is used in a declaration or expression, the type_path structure identifies which part of - * the type is annotated. An annotation may appear on the type itself, but if the type is a reference type, then - * there are additional locations where an annotation may appear: - * - * If an array type T[] is used in a declaration or expression, then an annotation may appear on any component type - * of the array type, including the element type. - * - * If a nested type T1.T2 is used in a declaration or expression, then an annotation may appear on the name of the - * innermost member type and any enclosing type for which a type annotation is admissible {@jls 9.7.4}. - * - * If a parameterized type {@literal T or T or T} is used in a declaration or expression, then an - * annotation may appear on any type argument or on the bound of any wildcard type argument. - * - * JVMS: ... each entry in the path array represents an iterative, left-to-right step towards the precise location - * of the annotation in an array type, nested type, or parameterized type. (In an array type, the iteration visits - * the array type itself, then its component type, then the component type of that component type, and so on, - * until the element type is reached.) + * JVMS: Type_path structure identifies which part of the type is annotated, + * as defined in {@jvms 4.7.20.2} */ sealed interface TypePathComponent permits UnboundAttribute.TypePathComponentImpl { + /** + * Type path kind, as defined in {@jvms 4.7.20.2} + */ public enum Kind { + + /** Annotation is deeper in an array type */ ARRAY(0), + + /** Annotation is deeper in a nested type */ INNER_TYPE(1), + + /** Annotation is on the bound of a wildcard type argument of a parameterized type */ WILDCARD(2), + + /** Annotation is on a type argument of a parameterized type */ TYPE_ARGUMENT(3); private final int tag; @@ -600,13 +757,21 @@ private Kind(int tag) { this.tag = tag; } + /** + * {@return the type path kind value} + */ public int tag() { return tag; } } + /** static instance for annotation is deeper in an array type */ TypePathComponent ARRAY = new UnboundAttribute.TypePathComponentImpl(Kind.ARRAY, 0); + + /** static instance for annotation is deeper in a nested type */ TypePathComponent INNER_TYPE = new UnboundAttribute.TypePathComponentImpl(Kind.INNER_TYPE, 0); + + /** static instance for annotation is on the bound of a wildcard type argument of a parameterized type */ TypePathComponent WILDCARD = new UnboundAttribute.TypePathComponentImpl(Kind.WILDCARD, 0); @@ -629,6 +794,11 @@ public int tag() { */ int typeArgumentIndex(); + /** + * {@return type path component of an annotation} + * @param typePathKind the kind of path element + * @param typeArgumentIndex the type argument index + */ static TypePathComponent of(Kind typePathKind, int typeArgumentIndex) { return switch (typePathKind) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/AnnotationDefaultAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/AnnotationDefaultAttribute.java index 790b1370cdc..3a0842cc5f6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/AnnotationDefaultAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/AnnotationDefaultAttribute.java @@ -37,6 +37,10 @@ * appear on methods of annotation types, and records the default value * {@jls 9.6.2} for the element corresponding to this method. Delivered as a * {@link MethodElement} when traversing the elements of a {@link MethodModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface AnnotationDefaultAttribute extends Attribute, MethodElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/BootstrapMethodsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/BootstrapMethodsAttribute.java index 69db048af6c..638043f0e09 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/BootstrapMethodsAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/BootstrapMethodsAttribute.java @@ -37,6 +37,10 @@ * Models the {@code BootstrapMethods} attribute {@jvms 4.7.23}, which serves as * an extension to the constant pool of a classfile. Elements of the bootstrap * method table are accessed through {@link ConstantPool}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface BootstrapMethodsAttribute extends Attribute diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/CharacterRangeTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/CharacterRangeTableAttribute.java index 549a4830789..287ecb55fc3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/CharacterRangeTableAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/CharacterRangeTableAttribute.java @@ -54,6 +54,8 @@ * several code index ranges, but there will be a smallest code index range, and * for each kind of range in which it is enclosed there will be a smallest code * index range. The character range entries may appear in any order. + *

+ * The attribute permits multiple instances in a given location. */ public sealed interface CharacterRangeTableAttribute extends Attribute diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/CodeAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/CodeAttribute.java index 47f2627cd09..50a2990d949 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/CodeAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/CodeAttribute.java @@ -35,6 +35,10 @@ * non-abstract methods and contains the bytecode of the method body. Delivered * as a {@link jdk.internal.classfile.MethodElement} when traversing the elements of a * {@link jdk.internal.classfile.MethodModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface CodeAttribute extends Attribute, CodeModel permits BoundAttribute.BoundCodeAttribute { diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/CompilationIDAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/CompilationIDAttribute.java index 0e536f374fe..588f1fc55d6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/CompilationIDAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/CompilationIDAttribute.java @@ -37,6 +37,10 @@ * appear on classes and records the compilation time of the class. Delivered * as a {@link jdk.internal.classfile.ClassElement} when traversing the elements of * a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface CompilationIDAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ConstantValueAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ConstantValueAttribute.java index a0fecb03dba..17eb6260e62 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ConstantValueAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ConstantValueAttribute.java @@ -37,6 +37,10 @@ * fields and indicates that the field's value is a constant. Delivered as a * {@link jdk.internal.classfile.FieldElement} when traversing the elements of a * {@link jdk.internal.classfile.FieldModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface ConstantValueAttribute extends Attribute, FieldElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/DeprecatedAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/DeprecatedAttribute.java index 0c4272599e8..a55b38a6ae0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/DeprecatedAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/DeprecatedAttribute.java @@ -36,6 +36,8 @@ * classes, methods, and fields. Delivered as a {@link ClassElement}, * {@link MethodElement}, or {@link FieldElement} when traversing the elements * of a corresponding model. + *

+ * The attribute permits multiple instances in a given location. */ public sealed interface DeprecatedAttribute extends Attribute, diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/EnclosingMethodAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/EnclosingMethodAttribute.java index 505c2f2b590..06c3af0f1b7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/EnclosingMethodAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/EnclosingMethodAttribute.java @@ -43,6 +43,10 @@ * on classes, and indicates that the class is a local or anonymous class. * Delivered as a {@link ClassElement} when traversing the elements of a {@link * jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface EnclosingMethodAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ExceptionsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ExceptionsAttribute.java index bcf9f41c5ed..90db3988cbb 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ExceptionsAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ExceptionsAttribute.java @@ -40,6 +40,10 @@ * methods, and records the exceptions declared to be thrown by this method. * Delivered as a {@link MethodElement} when traversing the elements of a * {@link jdk.internal.classfile.MethodModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface ExceptionsAttribute extends Attribute, MethodElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/InnerClassesAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/InnerClassesAttribute.java index 89c55ecc456..b92b323bd4e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/InnerClassesAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/InnerClassesAttribute.java @@ -37,6 +37,10 @@ * appear on classes, and records which classes referenced by this classfile * are inner classes. Delivered as a {@link jdk.internal.classfile.ClassElement} when * traversing the elements of a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface InnerClassesAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/LineNumberTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/LineNumberTableAttribute.java index 9314dedc6c8..224b0505911 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/LineNumberTableAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/LineNumberTableAttribute.java @@ -37,6 +37,8 @@ * Delivered as a {@link jdk.internal.classfile.instruction.LineNumber} when traversing the * elements of a {@link jdk.internal.classfile.CodeModel}, according to the setting of the * {@link jdk.internal.classfile.Classfile.LineNumbersOption} option. + *

+ * The attribute permits multiple instances in a given location. */ public sealed interface LineNumberTableAttribute extends Attribute diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTableAttribute.java index e2cd49e8e59..3b409bf7e3c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTableAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTableAttribute.java @@ -37,6 +37,8 @@ * Delivered as a {@link jdk.internal.classfile.instruction.LocalVariable} when traversing the * elements of a {@link jdk.internal.classfile.CodeModel}, according to the setting of the * {@link jdk.internal.classfile.Classfile.DebugElementsOption} option. + *

+ * The attribute permits multiple instances in a given location. */ public sealed interface LocalVariableTableAttribute extends Attribute diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTypeTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTypeTableAttribute.java index cbe1257ad54..a0016cd2e23 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTypeTableAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/LocalVariableTypeTableAttribute.java @@ -38,6 +38,8 @@ * Delivered as a {@link jdk.internal.classfile.instruction.LocalVariable} when traversing the * elements of a {@link jdk.internal.classfile.CodeModel}, according to the setting of the * {@link jdk.internal.classfile.Classfile.LineNumbersOption} option. + *

+ * The attribute permits multiple instances in a given location. */ public sealed interface LocalVariableTypeTableAttribute extends Attribute diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/MethodParametersAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/MethodParametersAttribute.java index a3486db891d..8f9b14ffe04 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/MethodParametersAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/MethodParametersAttribute.java @@ -37,6 +37,10 @@ * appear on methods, and records optional information about the method's * parameters. Delivered as a {@link jdk.internal.classfile.MethodElement} when * traversing the elements of a {@link jdk.internal.classfile.MethodModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface MethodParametersAttribute extends Attribute, MethodElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleAttribute.java index bc684d8632a..9be842a04dd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleAttribute.java @@ -49,6 +49,10 @@ * appear on classes that represent module descriptors. * Delivered as a {@link jdk.internal.classfile.ClassElement} when * traversing the elements of a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface ModuleAttribute @@ -72,12 +76,17 @@ default Set moduleFlags() { return AccessFlag.maskToAccessFlags(moduleFlagsMask(), AccessFlag.Location.MODULE); } + /** + * Tests presence of module flag + * @param flag the module flag + * @return true if the flag is set + */ default boolean has(AccessFlag flag) { return Util.has(AccessFlag.Location.MODULE, moduleFlagsMask(), flag); } /** - * {@return version of the module, if present} + * {@return the version of the module, if present} */ Optional moduleVersion(); @@ -155,40 +164,156 @@ static ModuleAttribute of(ModuleEntry moduleName, return mb.build(); } + /** + * A builder for module attributes. + */ public sealed interface ModuleAttributeBuilder permits ModuleAttributeBuilderImpl { + /** + * Sets the module name + * @param moduleName the module name + * @return this builder + */ ModuleAttributeBuilder moduleName(ModuleDesc moduleName); + + /** + * Sets the module flags + * @param flagsMask the module flags + * @return this builder + */ ModuleAttributeBuilder moduleFlags(int flagsMask); + + /** + * Sets the module flags + * @param moduleFlags the module flags + * @return this builder + */ default ModuleAttributeBuilder moduleFlags(AccessFlag... moduleFlags) { return moduleFlags(Util.flagsToBits(AccessFlag.Location.MODULE, moduleFlags)); } + + /** + * Sets the module flags + * @param version the module version + * @return this builder + */ ModuleAttributeBuilder moduleVersion(String version); + /** + * Adds module requirement + * @param module the required module + * @param requiresFlagsMask the requires flags + * @param version the required module version + * @return this builder + */ ModuleAttributeBuilder requires(ModuleDesc module, int requiresFlagsMask, String version); + + /** + * Adds module requirement + * @param module the required module + * @param requiresFlags the requires flags + * @param version the required module version + * @return this builder + */ default ModuleAttributeBuilder requires(ModuleDesc module, Collection requiresFlags, String version) { return requires(module, Util.flagsToBits(AccessFlag.Location.MODULE_REQUIRES, requiresFlags), version); } + + /** + * Adds module requirement + * @param requires the module require info + * @return this builder + */ ModuleAttributeBuilder requires(ModuleRequireInfo requires); + /** + * Adds exported package + * @param pkge the exported package + * @param exportsFlagsMask the export flags + * @param exportsToModules the modules to export to + * @return this builder + */ ModuleAttributeBuilder exports(PackageDesc pkge, int exportsFlagsMask, ModuleDesc... exportsToModules); + + /** + * Adds exported package + * @param pkge the exported package + * @param exportsFlags the export flags + * @param exportsToModules the modules to export to + * @return this builder + */ default ModuleAttributeBuilder exports(PackageDesc pkge, Collection exportsFlags, ModuleDesc... exportsToModules) { return exports(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_EXPORTS, exportsFlags), exportsToModules); } + + /** + * Adds exported package + * @param exports the module export info + * @return this builder + */ ModuleAttributeBuilder exports(ModuleExportInfo exports); + /** + * + * @param pkge the opened package + * @param opensFlagsMask the open package flags + * @param opensToModules the modules to open to + * @return this builder + */ ModuleAttributeBuilder opens(PackageDesc pkge, int opensFlagsMask, ModuleDesc... opensToModules); + + /** + * + * @param pkge the opened package + * @param opensFlags the open package flags + * @param opensToModules the modules to open to + * @return this builder + */ default ModuleAttributeBuilder opens(PackageDesc pkge, Collection opensFlags, ModuleDesc... opensToModules) { return opens(pkge, Util.flagsToBits(AccessFlag.Location.MODULE_OPENS, opensFlags), opensToModules); } + + /** + * Opens package + * @param opens the module open info + * @return this builder + */ ModuleAttributeBuilder opens(ModuleOpenInfo opens); + /** + * Declares use of a service + * @param service the service class used + * @return this builder + */ ModuleAttributeBuilder uses(ClassDesc service); + + /** + * Declares use of a service + * @param uses the service class used + * @return this builder + */ ModuleAttributeBuilder uses(ClassEntry uses); + /** + * Declares provision of a service + * @param service the service class provided + * @param implClasses the implementation classes + * @return this builder + */ ModuleAttributeBuilder provides(ClassDesc service, ClassDesc... implClasses); + + /** + * Declares provision of a service + * @param provides the module provides info + * @return this builder + */ ModuleAttributeBuilder provides(ModuleProvideInfo provides); + /** + * Builds module attribute. + * @return the module attribute + */ ModuleAttribute build(); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleHashesAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleHashesAttribute.java index 5447ea0e043..e1b3af294c3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleHashesAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleHashesAttribute.java @@ -63,6 +63,10 @@ * * } * } + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface ModuleHashesAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleMainClassAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleMainClassAttribute.java index a21e0f4888b..0b429a6afda 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleMainClassAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleMainClassAttribute.java @@ -38,6 +38,10 @@ * appear on classes that represent module descriptors. * Delivered as a {@link jdk.internal.classfile.ClassElement} when * traversing the elements of a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface ModuleMainClassAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleOpenInfo.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleOpenInfo.java index 706f9779cf9..9e22b517c3d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleOpenInfo.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleOpenInfo.java @@ -56,6 +56,9 @@ public sealed interface ModuleOpenInfo */ int opensFlagsMask(); + /** + * {@return the access flags} + */ default Set opensFlags() { return AccessFlag.maskToAccessFlags(opensFlagsMask(), AccessFlag.Location.MODULE_OPENS); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModulePackagesAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModulePackagesAttribute.java index f1851835ef9..b53c77859b5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModulePackagesAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModulePackagesAttribute.java @@ -41,6 +41,10 @@ * appear on classes that represent module descriptors. * Delivered as a {@link jdk.internal.classfile.ClassElement} when * traversing the elements of a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface ModulePackagesAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleRequireInfo.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleRequireInfo.java index 313b4020d55..3e56a953b87 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleRequireInfo.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleRequireInfo.java @@ -56,6 +56,9 @@ public sealed interface ModuleRequireInfo */ int requiresFlagsMask(); + /** + * {@return the access flags} + */ default Set requiresFlags() { return AccessFlag.maskToAccessFlags(requiresFlagsMask(), AccessFlag.Location.MODULE_REQUIRES); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleResolutionAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleResolutionAttribute.java index c26ead18f4e..0a67d8f2f3c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleResolutionAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleResolutionAttribute.java @@ -56,6 +56,10 @@ * 0x0008 (WARN_INCUBATING) * } * } + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface ModuleResolutionAttribute extends Attribute, ClassElement @@ -72,6 +76,7 @@ public sealed interface ModuleResolutionAttribute * 0x0002 (WARN_DEPRECATED) * 0x0004 (WARN_DEPRECATED_FOR_REMOVAL) * 0x0008 (WARN_INCUBATING) + * @return the module resolution flags */ int resolutionFlags(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleTargetAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleTargetAttribute.java index 36beab9e485..744b0bd298a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleTargetAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/ModuleTargetAttribute.java @@ -51,6 +51,10 @@ * u2 target_platform_index; * } * } + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface ModuleTargetAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/NestHostAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/NestHostAttribute.java index e2a311a76f3..e8606593511 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/NestHostAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/NestHostAttribute.java @@ -38,6 +38,10 @@ * appear on classes to indicate that this class is a member of a nest. * Delivered as a {@link jdk.internal.classfile.ClassElement} when * traversing the elements of a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface NestHostAttribute extends Attribute, ClassElement permits BoundAttribute.BoundNestHostAttribute, diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/NestMembersAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/NestMembersAttribute.java index 00c4a595158..82796e26cd5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/NestMembersAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/NestMembersAttribute.java @@ -40,6 +40,10 @@ * appear on classes to indicate that this class is the host of a nest. * Delivered as a {@link jdk.internal.classfile.ClassElement} when * traversing the elements of a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface NestMembersAttribute extends Attribute, ClassElement permits BoundAttribute.BoundNestMembersAttribute, UnboundAttribute.UnboundNestMembersAttribute { diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/PermittedSubclassesAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/PermittedSubclassesAttribute.java index affad318bf5..11523dd2417 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/PermittedSubclassesAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/PermittedSubclassesAttribute.java @@ -40,6 +40,10 @@ * appear on classes to indicate which classes may extend this class. * Delivered as a {@link jdk.internal.classfile.ClassElement} when * traversing the elements of a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface PermittedSubclassesAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RecordAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RecordAttribute.java index bede1ac97ac..84b9ac49d8a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RecordAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RecordAttribute.java @@ -37,6 +37,10 @@ * appear on classes to indicate that this class is a record class. * Delivered as a {@link jdk.internal.classfile.ClassElement} when * traversing the elements of a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface RecordAttribute extends Attribute, ClassElement permits BoundAttribute.BoundRecordAttribute, UnboundAttribute.UnboundRecordAttribute { diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java index 6ffbfdc5d45..ff6c5df2fe6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java @@ -36,6 +36,10 @@ * can appear on classes, methods, and fields. Delivered as a * {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement}, or * {@link jdk.internal.classfile.MethodElement} when traversing the corresponding model type. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface RuntimeInvisibleAnnotationsAttribute extends Attribute, diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java index 5140251611b..ef4e5bf8473 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java @@ -38,6 +38,10 @@ * Models the {@code RuntimeInvisibleParameterAnnotations} attribute * {@jvms 4.7.19}, which can appear on methods. Delivered as a {@link * jdk.internal.classfile.MethodElement} when traversing a {@link MethodModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface RuntimeInvisibleParameterAnnotationsAttribute extends Attribute, MethodElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java index f86c7ca1b39..2db2a6270f0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java @@ -42,6 +42,10 @@ * {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement}, * {@link jdk.internal.classfile.MethodElement}, or {@link CodeElement} when traversing * the corresponding model type. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface RuntimeInvisibleTypeAnnotationsAttribute extends Attribute, diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java index 98f92546aa6..54ca6926f8a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java @@ -36,6 +36,10 @@ * can appear on classes, methods, and fields. Delivered as a * {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement}, or * {@link jdk.internal.classfile.MethodElement} when traversing the corresponding model type. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface RuntimeVisibleAnnotationsAttribute extends Attribute, diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java index 91d9234c3a1..32947a831a5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java @@ -38,6 +38,10 @@ * Models the {@code RuntimeVisibleParameterAnnotations} attribute {@jvms 4.7.18}, which * can appear on methods. Delivered as a {@link jdk.internal.classfile.MethodElement} * when traversing a {@link MethodModel}. + * + * @apiNote The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface RuntimeVisibleParameterAnnotationsAttribute extends Attribute, MethodElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java index 79ca6e435fc..dbb4d8b06f0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java @@ -42,6 +42,10 @@ * {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement}, * {@link jdk.internal.classfile.MethodElement}, or {@link CodeElement} when traversing * the corresponding model type. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface RuntimeVisibleTypeAnnotationsAttribute extends Attribute, diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SignatureAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SignatureAttribute.java index af83f3522d3..dfcaa4bae7d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SignatureAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SignatureAttribute.java @@ -43,6 +43,10 @@ * {@link jdk.internal.classfile.ClassElement}, {@link jdk.internal.classfile.FieldElement}, or * {@link jdk.internal.classfile.MethodElement} when traversing * the corresponding model type. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface SignatureAttribute extends Attribute, diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceDebugExtensionAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceDebugExtensionAttribute.java index e5024094510..1771acf2cc9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceDebugExtensionAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceDebugExtensionAttribute.java @@ -31,9 +31,13 @@ import jdk.internal.classfile.impl.UnboundAttribute; /** - * Models the {@code SourceDebugExtension} attribute (@@@ need reference). + * Models the {@code SourceDebugExtension} attribute. * Delivered as a {@link jdk.internal.classfile.ClassElement} when traversing the elements of * a {@link jdk.internal.classfile.ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface SourceDebugExtensionAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceFileAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceFileAttribute.java index 7f9a73a8482..7c93deadbf2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceFileAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceFileAttribute.java @@ -37,6 +37,10 @@ * Models the {@code SourceFile} attribute {@jvms 4.7.10}, which * can appear on classes. Delivered as a {@link jdk.internal.classfile.ClassElement} * when traversing a {@link ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface SourceFileAttribute extends Attribute, ClassElement @@ -47,10 +51,18 @@ public sealed interface SourceFileAttribute */ Utf8Entry sourceFile(); + /** + * {@return a source file attribute} + * @param sourceFile the source file name + */ static SourceFileAttribute of(String sourceFile) { return of(TemporaryConstantPool.INSTANCE.utf8Entry(sourceFile)); } + /** + * {@return a source file attribute} + * @param sourceFile the source file name + */ static SourceFileAttribute of(Utf8Entry sourceFile) { return new UnboundAttribute.UnboundSourceFileAttribute(sourceFile); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceIDAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceIDAttribute.java index 05534e434df..22aa9390a26 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceIDAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SourceIDAttribute.java @@ -34,9 +34,13 @@ import jdk.internal.classfile.impl.UnboundAttribute; /** - * Models the {@code SourceID} attribute (@@@ reference needed), which can + * Models the {@code SourceID} attribute, which can * appear on classes. Delivered as a {@link jdk.internal.classfile.ClassElement} when * traversing a {@link ClassModel}. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface SourceIDAttribute extends Attribute, ClassElement diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapFrameInfo.java index 82219dcfee8..6c0f9925b30 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapFrameInfo.java @@ -40,11 +40,32 @@ public sealed interface StackMapFrameInfo permits StackMapDecoder.StackMapFrameImpl { + /** + * {@return the frame compact form type} + */ int frameType(); + + /** + * {@return the frame target label} + */ Label target(); + + /** + * {@return the expanded local variable types} + */ List locals(); + + /** + * {@return the expanded stack types} + */ List stack(); + /** + * {@return a new stack map frame} + * @param target the location of the frame + * @param locals the complete list of frame locals + * @param stack the complete frame stack + */ public static StackMapFrameInfo of(Label target, List locals, List stack) { @@ -56,6 +77,10 @@ public static StackMapFrameInfo of(Label target, * The type of a stack value. */ sealed interface VerificationTypeInfo { + + /** + * {@return the tag of the type info} + */ int tag(); } @@ -63,12 +88,26 @@ sealed interface VerificationTypeInfo { * A simple stack value. */ public enum SimpleVerificationTypeInfo implements VerificationTypeInfo { + + /** verification type top */ ITEM_TOP(VT_TOP), + + /** verification type int */ ITEM_INTEGER(VT_INTEGER), + + /** verification type float */ ITEM_FLOAT(VT_FLOAT), + + /** verification type double */ ITEM_DOUBLE(VT_DOUBLE), + + /** verification type long */ ITEM_LONG(VT_LONG), + + /** verification type null */ ITEM_NULL(VT_NULL), + + /** verification type uninitializedThis */ ITEM_UNINITIALIZED_THIS(VT_UNINITIALIZED_THIS); @@ -90,19 +129,30 @@ public int tag() { sealed interface ObjectVerificationTypeInfo extends VerificationTypeInfo permits StackMapDecoder.ObjectVerificationTypeInfoImpl { + /** + * {@return a new object verification type info} + * @param className the class of the object + */ public static ObjectVerificationTypeInfo of(ClassEntry className) { return new StackMapDecoder.ObjectVerificationTypeInfoImpl(className); } + /** + * {@return a new object verification type info} + * @param classDesc the class of the object + */ public static ObjectVerificationTypeInfo of(ClassDesc classDesc) { return of(TemporaryConstantPool.INSTANCE.classEntry(classDesc)); } /** - * {@return the class of the value} + * {@return the class of the object} */ ClassEntry className(); + /** + * {@return the class of the object} + */ default ClassDesc classSymbol() { return className().asSymbol(); } @@ -113,8 +163,16 @@ default ClassDesc classSymbol() { */ sealed interface UninitializedVerificationTypeInfo extends VerificationTypeInfo permits StackMapDecoder.UninitializedVerificationTypeInfoImpl { + + /** + * {@return the {@code new} instruction position that creates this unitialized object} + */ Label newTarget(); + /** + * {@return an unitialized verification type info} + * @param newTarget the {@code new} instruction position that creates this unitialized object + */ public static UninitializedVerificationTypeInfo of(Label newTarget) { return new StackMapDecoder.UninitializedVerificationTypeInfoImpl(newTarget); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapTableAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapTableAttribute.java index 6f7cc69b978..ca5d1732021 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapTableAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/StackMapTableAttribute.java @@ -35,6 +35,10 @@ /** * Models the {@code StackMapTable} attribute {@jvms 4.7.4}, which can appear * on a {@code Code} attribute. + *

+ * The attribute does not permit multiple instances in a given location. + * Subsequent occurrence of the attribute takes precedence during the attributed + * element build or transformation. */ public sealed interface StackMapTableAttribute extends Attribute, CodeElement @@ -45,6 +49,10 @@ public sealed interface StackMapTableAttribute */ List entries(); + /** + * {@return a stack map table attribute} + * @param entries the stack map frames + */ public static StackMapTableAttribute of(List entries) { return new UnboundAttribute.UnboundStackMapTableAttribute(entries); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/attribute/SyntheticAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/attribute/SyntheticAttribute.java index 7f84ed496a0..a4aee1408a1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/attribute/SyntheticAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/attribute/SyntheticAttribute.java @@ -37,6 +37,8 @@ * classes, methods, and fields. Delivered as a {@link ClassElement}, * {@link MethodElement}, or {@link FieldElement} when traversing the elements * of a corresponding model. + *

+ * The attribute permits multiple instances in a given location. */ public sealed interface SyntheticAttribute extends Attribute, diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/BranchInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/BranchInstruction.java index 7ad5c1a649a..4223adf5d9f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/instruction/BranchInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/BranchInstruction.java @@ -51,6 +51,7 @@ public sealed interface BranchInstruction extends Instruction * * @param op the opcode for the specific type of branch instruction, * which must be of kind {@link Opcode.Kind#BRANCH} + * @param target the target of the branch */ static BranchInstruction of(Opcode op, Label target) { Util.checkKind(op, Opcode.Kind.BRANCH); diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/LabelTarget.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/LabelTarget.java index a6948e07369..029eb37ea5b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/instruction/LabelTarget.java +++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/LabelTarget.java @@ -39,5 +39,9 @@ */ public sealed interface LabelTarget extends PseudoInstruction permits LabelImpl { + + /** + * {@return the label corresponding to this target} + */ Label label(); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/LoadInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/LoadInstruction.java index 0d91f285cc1..935e33d64b5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/instruction/LoadInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/LoadInstruction.java @@ -42,8 +42,15 @@ public sealed interface LoadInstruction extends Instruction permits AbstractInstruction.BoundLoadInstruction, AbstractInstruction.UnboundLoadInstruction { + + /** + * {@return the local variable slot to load from} + */ int slot(); + /** + * {@return the type of the value to be loaded} + */ TypeKind typeKind(); /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariable.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariable.java index ac803e3cf3c..9fbc991416a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariable.java +++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariable.java @@ -80,6 +80,12 @@ default ClassDesc typeSymbol() { */ Label endScope(); + /** + * Writes the local variable to the specified writer + * + * @param buf the writer + * @return true if the variable has been written + */ boolean writeTo(BufWriter buf); /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariableType.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariableType.java index 3c01f1df3d4..168552a7ee2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariableType.java +++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/LocalVariableType.java @@ -77,6 +77,12 @@ default Signature signatureSymbol() { */ Label endScope(); + /** + * Writes the local variable to the specified writer + * + * @param buf the writer + * @return true if the variable has been written + */ boolean writeTo(BufWriter buf); /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/ReturnInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/ReturnInstruction.java index ee17d758a97..35afaae898f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/instruction/ReturnInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/ReturnInstruction.java @@ -41,6 +41,10 @@ */ public sealed interface ReturnInstruction extends Instruction permits AbstractInstruction.UnboundReturnInstruction { + + /** + * {@return the type of the return instruction} + */ TypeKind typeKind(); /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/StoreInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/StoreInstruction.java index b7c26ac1b31..a6254dfc052 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/instruction/StoreInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/StoreInstruction.java @@ -41,7 +41,15 @@ */ public sealed interface StoreInstruction extends Instruction permits AbstractInstruction.BoundStoreInstruction, AbstractInstruction.UnboundStoreInstruction { + + /** + * {@return the local variable slot to store to} + */ int slot(); + + /** + * {@return the type of the value to be stored} + */ TypeKind typeKind(); /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/instruction/TypeCheckInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/instruction/TypeCheckInstruction.java index 19400079b3d..a777edb39fd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/instruction/TypeCheckInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/instruction/TypeCheckInstruction.java @@ -43,6 +43,10 @@ public sealed interface TypeCheckInstruction extends Instruction permits AbstractInstruction.BoundTypeCheckInstruction, AbstractInstruction.UnboundTypeCheckInstruction { + + /** + * {@return the type against which the instruction checks or casts} + */ ClassEntry type(); /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/package-info.java b/src/java.base/share/classes/jdk/internal/classfile/package-info.java index 1286f791c61..db14e8f61c9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/package-info.java +++ b/src/java.base/share/classes/jdk/internal/classfile/package-info.java @@ -211,7 +211,12 @@ * builders for the constructor and {@code main} method, and in turn use the * method builders to create a {@code Code} attribute and use the code builders * to generate the instructions: - * {@snippet lang="java" class="PackageSnippets" region="helloWorld"} + * {@snippet lang="java" class="PackageSnippets" region="helloWorld1"} + *

+ * The convenience methods {@code ClassBuilder.buildMethodBody} allows us to ask + * {@link ClassBuilder} to create code builders to build method bodies directly, + * skipping the method builder custom lambda: + * {@snippet lang="java" class="PackageSnippets" region="helloWorld2"} *

* Builders often support multiple ways of expressing the same entity at * different levels of abstraction. For example, the {@code invokevirtual} @@ -276,9 +281,13 @@ * builder and an element, and an implementation "flatMap"s elements * into the builder. We could express the above as: * {@snippet lang="java" class="PackageSnippets" region="stripDebugMethods2"} + *

+ * {@code ClassTransform.dropping} convenience method allow us to simplify the same + * transformation construction and express the above as: + * {@snippet lang="java" class="PackageSnippets" region="stripDebugMethods3"} * *

Lifting transforms

- * While the second example is only slightly shorter than the first, the + * While the example using transformations are only slightly shorter, the * advantage of expressing transformation in this way is that the transform * operations can be more easily combined. Suppose we want to redirect * invocations of static methods on {@code Foo} to the corresponding method on @@ -301,6 +310,11 @@ * ClassTransform ct = ClassTransform.transformingMethods(mt); * } *

+ * or lift the code transform into the class transform directly: + * {@snippet lang=java : + * ClassTransform ct = ClassTransform.transformingMethodBodiess(fooToBar); + * } + *

* and then transform the classfile: * {@snippet lang=java : * var cc = Classfile.of(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/snippet-files/PackageSnippets.java b/src/java.base/share/classes/jdk/internal/classfile/snippet-files/PackageSnippets.java index b22c7dd0548..16c467c77d9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/snippet-files/PackageSnippets.java +++ b/src/java.base/share/classes/jdk/internal/classfile/snippet-files/PackageSnippets.java @@ -132,28 +132,41 @@ void gatherDependencies2(byte[] bytes) { private static final MethodTypeDesc MTD_void_StringArray = MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_String.arrayType()); private static final MethodTypeDesc MTD_void_String = MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_String); - void writeHelloWorld() { - // @start region="helloWorld" - byte[] bytes = Classfile.of().build(CD_Hello, cb -> { - cb.withFlags(AccessFlag.PUBLIC); - cb.withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC, - mb -> mb.withCode( - b -> b.aload(0) - .invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME, - ConstantDescs.MTD_void) - .returnInstruction(TypeKind.VoidType) - ) - ) - .withMethod("main", MTD_void_StringArray, - Classfile.ACC_PUBLIC, - mb -> mb.withFlags(AccessFlag.STATIC, AccessFlag.PUBLIC) - .withCode( - b -> b.getstatic(CD_System, "out", CD_PrintStream) - .constantInstruction(Opcode.LDC, "Hello World") - .invokevirtual(CD_PrintStream, "println", MTD_void_String) - .returnInstruction(TypeKind.VoidType) - )); - }); + void writeHelloWorld1() { + // @start region="helloWorld1" + byte[] bytes = Classfile.of().build(CD_Hello, + clb -> clb.withFlags(Classfile.ACC_PUBLIC) + .withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, + Classfile.ACC_PUBLIC, + mb -> mb.withCode( + cob -> cob.aload(0) + .invokespecial(ConstantDescs.CD_Object, + ConstantDescs.INIT_NAME, ConstantDescs.MTD_void) + .return_())) + .withMethod("main", MTD_void_StringArray, Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, + mb -> mb.withCode( + cob -> cob.getstatic(CD_System, "out", CD_PrintStream) + .ldc("Hello World") + .invokevirtual(CD_PrintStream, "println", MTD_void_String) + .return_()))); + // @end + } + + void writeHelloWorld2() { + // @start region="helloWorld2" + byte[] bytes = Classfile.of().build(CD_Hello, + clb -> clb.withFlags(Classfile.ACC_PUBLIC) + .withMethodBody(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, + Classfile.ACC_PUBLIC, + cob -> cob.aload(0) + .invokespecial(ConstantDescs.CD_Object, + ConstantDescs.INIT_NAME, ConstantDescs.MTD_void) + .return_()) + .withMethodBody("main", MTD_void_StringArray, Classfile.ACC_PUBLIC + Classfile.ACC_STATIC, + cob -> cob.getstatic(CD_System, "out", CD_PrintStream) + .ldc("Hello World") + .invokevirtual(CD_PrintStream, "println", MTD_void_String) + .return_())); // @end } @@ -161,13 +174,14 @@ void stripDebugMethods1(byte[] bytes) { // @start region="stripDebugMethods1" ClassModel classModel = Classfile.of().parse(bytes); byte[] newBytes = Classfile.of().build(classModel.thisClass().asSymbol(), - classBuilder -> { - for (ClassElement ce : classModel) { - if (!(ce instanceof MethodModel mm - && mm.methodName().stringValue().startsWith("debug"))) - classBuilder.with(ce); - } - }); + classBuilder -> { + for (ClassElement ce : classModel) { + if (!(ce instanceof MethodModel mm + && mm.methodName().stringValue().startsWith("debug"))) { + classBuilder.with(ce); + } + } + }); // @end } @@ -182,6 +196,14 @@ void stripDebugMethods2(byte[] bytes) { // @end } + void stripDebugMethods3(byte[] bytes) { + // @start region="stripDebugMethods3" + ClassTransform ct = ClassTransform.dropping( + element -> element instanceof MethodModel mm + && mm.methodName().stringValue().startsWith("debug")); + // @end + } + void fooToBarTransform() { // @start region="fooToBarTransform" CodeTransform fooToBar = (b, e) -> { @@ -199,7 +221,7 @@ void instrumentCallsTransform() { CodeTransform instrumentCalls = (b, e) -> { if (e instanceof InvokeInstruction i) { b.getstatic(CD_System, "out", CD_PrintStream) - .constantInstruction(Opcode.LDC, i.name().stringValue()) + .ldc(i.name().stringValue()) .invokevirtual(CD_PrintStream, "println", MTD_void_String); } b.with(e); From 9013b032448518e09a7c6f2e80054be722c970a3 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 5 Sep 2023 10:08:35 +0000 Subject: [PATCH 65/86] 8315442: Enable parallelism in vmTestbase/nsk/monitoring/stress/thread tests Reviewed-by: stuefe, lmesnik --- .../stress/thread/cmon001/TEST.properties | 23 ------------------- .../stress/thread/cmon002/TEST.properties | 23 ------------------- .../stress/thread/cmon003/TEST.properties | 23 ------------------- .../stress/thread/strace001/TEST.properties | 23 ------------------- .../stress/thread/strace002/TEST.properties | 23 ------------------- .../stress/thread/strace003/TEST.properties | 23 ------------------- .../stress/thread/strace004/TEST.properties | 23 ------------------- .../stress/thread/strace005/TEST.properties | 23 ------------------- .../stress/thread/strace006/TEST.properties | 23 ------------------- .../stress/thread/strace007/TEST.properties | 23 ------------------- .../stress/thread/strace008/TEST.properties | 23 ------------------- .../stress/thread/strace009/TEST.properties | 23 ------------------- .../stress/thread/strace010/TEST.properties | 23 ------------------- .../stress/thread/strace011/TEST.properties | 23 ------------------- .../stress/thread/strace012/TEST.properties | 23 ------------------- .../stress/thread/strace013/TEST.properties | 23 ------------------- .../stress/thread/strace014/TEST.properties | 23 ------------------- .../stress/thread/strace015/TEST.properties | 23 ------------------- .../stress/thread/strace016/TEST.properties | 23 ------------------- .../stress/thread/strace017/TEST.properties | 23 ------------------- .../stress/thread/strace018/TEST.properties | 23 ------------------- 21 files changed, 483 deletions(-) delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon002/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon003/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace004/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace005/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace006/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace007/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace008/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace009/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace010/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace011/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace012/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace013/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace014/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace015/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace016/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace017/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace018/TEST.properties diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon002/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon002/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon002/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon003/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon003/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon003/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace001/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace002/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace003/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace004/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace004/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace004/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace005/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace005/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace005/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace006/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace006/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace006/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace007/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace007/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace007/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace008/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace008/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace008/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace009/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace009/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace009/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace010/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace010/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace010/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace011/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace011/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace011/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace012/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace012/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace012/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace013/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace013/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace013/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace014/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace014/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace014/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace015/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace015/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace015/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace016/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace016/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace016/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace017/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace017/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace017/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace018/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace018/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/strace018/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -exclusiveAccess.dirs=. From 5a2e151d4839787323732232b698315bcb3a3bd6 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Tue, 5 Sep 2023 10:12:24 +0000 Subject: [PATCH 66/86] 8315548: G1: Document why VM_G1CollectForAllocation::doit() may allocate without completing a GC Reviewed-by: tschatzl --- src/hotspot/share/gc/g1/g1VMOperations.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hotspot/share/gc/g1/g1VMOperations.cpp b/src/hotspot/share/gc/g1/g1VMOperations.cpp index c19c399cfb6..7820c9abff7 100644 --- a/src/hotspot/share/gc/g1/g1VMOperations.cpp +++ b/src/hotspot/share/gc/g1/g1VMOperations.cpp @@ -127,6 +127,10 @@ void VM_G1CollectForAllocation::doit() { if (_word_size > 0) { // An allocation has been requested. So, try to do that first. + // During the execution of this VM operation, there may have been a concurrent active + // GCLocker, potentially leading to expansion of the Eden space by other mutators. + // If the Eden space were expanded, this allocation request might succeed without + // the need for triggering a garbage collection. _result = g1h->attempt_allocation_at_safepoint(_word_size, false /* expect_null_cur_alloc_region */); if (_result != nullptr) { From 8647f001bbb804503e8491d10f77aa0f34d66bf2 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Tue, 5 Sep 2023 11:05:49 +0000 Subject: [PATCH 67/86] 8293850: need a largest_committed metric for each category of NMT's output Reviewed-by: gziemski, jsjolen --- src/hotspot/share/services/memReporter.cpp | 22 +++++++++++-------- src/hotspot/share/services/memReporter.hpp | 6 ++--- .../share/services/virtualMemoryTracker.cpp | 14 ++++++++++++ .../share/services/virtualMemoryTracker.hpp | 13 ++++++++++- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/services/memReporter.cpp b/src/hotspot/share/services/memReporter.cpp index e1fb2b7a32f..3e2927a8bad 100644 --- a/src/hotspot/share/services/memReporter.cpp +++ b/src/hotspot/share/services/memReporter.cpp @@ -50,10 +50,13 @@ size_t MemReporterBase::committed_total(const MallocMemory* malloc, const Virtua return malloc->malloc_size() + malloc->arena_size() + vm->committed(); } -void MemReporterBase::print_total(size_t reserved, size_t committed) const { +void MemReporterBase::print_total(size_t reserved, size_t committed, size_t peak) const { const char* scale = current_scale(); output()->print("reserved=" SIZE_FORMAT "%s, committed=" SIZE_FORMAT "%s", amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale); + if (peak != 0) { + output()->print(", largest_committed=" SIZE_FORMAT "%s", amount_in_current_scale(peak), scale); + } } void MemReporterBase::print_malloc(const MemoryCounter* c, MEMFLAGS flag) const { @@ -89,10 +92,10 @@ void MemReporterBase::print_malloc(const MemoryCounter* c, MEMFLAGS flag) const } } -void MemReporterBase::print_virtual_memory(size_t reserved, size_t committed) const { +void MemReporterBase::print_virtual_memory(size_t reserved, size_t committed, size_t peak) const { const char* scale = current_scale(); - output()->print("(mmap: reserved=" SIZE_FORMAT "%s, committed=" SIZE_FORMAT "%s)", - amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale); + output()->print("(mmap: reserved=" SIZE_FORMAT "%s, committed=" SIZE_FORMAT "%s, largest_committed=" SIZE_FORMAT "%s)", + amount_in_current_scale(reserved), scale, amount_in_current_scale(committed), scale, amount_in_current_scale(peak), scale); } void MemReporterBase::print_malloc_line(const MemoryCounter* c) const { @@ -101,9 +104,9 @@ void MemReporterBase::print_malloc_line(const MemoryCounter* c) const { output()->print_cr(" "); } -void MemReporterBase::print_virtual_memory_line(size_t reserved, size_t committed) const { +void MemReporterBase::print_virtual_memory_line(size_t reserved, size_t committed, size_t peak) const { output()->print("%28s", " "); - print_virtual_memory(reserved, committed); + print_virtual_memory(reserved, committed, peak); output()->print_cr(" "); } @@ -228,7 +231,7 @@ void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag, // report thread count out->print_cr("%27s (threads #" SIZE_FORMAT ")", " ", ThreadStackTracker::thread_count()); out->print("%27s (stack: ", " "); - print_total(thread_stack_usage->reserved(), thread_stack_usage->committed()); + print_total(thread_stack_usage->reserved(), thread_stack_usage->committed(), thread_stack_usage->peak_size()); } else { MallocMemory* thread_stack_memory = _malloc_snapshot->by_type(mtThreadStack); const char* scale = current_scale(); @@ -247,8 +250,9 @@ void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag, print_malloc_line(malloc_memory->malloc_counter()); } - if (amount_in_current_scale(virtual_memory->reserved()) > 0) { - print_virtual_memory_line(virtual_memory->reserved(), virtual_memory->committed()); + if (amount_in_current_scale(virtual_memory->reserved()) > 0 + DEBUG_ONLY(|| amount_in_current_scale(virtual_memory->peak_size()) > 0)) { + print_virtual_memory_line(virtual_memory->reserved(), virtual_memory->committed(), virtual_memory->peak_size()); } if (amount_in_current_scale(malloc_memory->arena_size()) > 0 diff --git a/src/hotspot/share/services/memReporter.hpp b/src/hotspot/share/services/memReporter.hpp index affc97098dc..b9e31d4bc4b 100644 --- a/src/hotspot/share/services/memReporter.hpp +++ b/src/hotspot/share/services/memReporter.hpp @@ -107,12 +107,12 @@ class MemReporterBase : public StackObj { } // Print summary total, malloc and virtual memory - void print_total(size_t reserved, size_t committed) const; + void print_total(size_t reserved, size_t committed, size_t peak = 0) const; void print_malloc(const MemoryCounter* c, MEMFLAGS flag = mtNone) const; - void print_virtual_memory(size_t reserved, size_t committed) const; + void print_virtual_memory(size_t reserved, size_t committed, size_t peak) const; void print_malloc_line(const MemoryCounter* c) const; - void print_virtual_memory_line(size_t reserved, size_t committed) const; + void print_virtual_memory_line(size_t reserved, size_t committed, size_t peak) const; void print_arena_line(const MemoryCounter* c) const; void print_virtual_memory_region(const char* type, address base, size_t size) const; diff --git a/src/hotspot/share/services/virtualMemoryTracker.cpp b/src/hotspot/share/services/virtualMemoryTracker.cpp index 66fdb236256..ebb32ecbeeb 100644 --- a/src/hotspot/share/services/virtualMemoryTracker.cpp +++ b/src/hotspot/share/services/virtualMemoryTracker.cpp @@ -34,6 +34,20 @@ size_t VirtualMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(VirtualMemorySnapshot, size_t)]; +#ifdef ASSERT +void VirtualMemory::update_peak(size_t size) { + size_t peak_sz = peak_size(); + while (peak_sz < size) { + size_t old_sz = Atomic::cmpxchg(&_peak_size, peak_sz, size, memory_order_relaxed); + if (old_sz == peak_sz) { + break; + } else { + peak_sz = old_sz; + } + } +} +#endif // ASSERT + void VirtualMemorySummary::initialize() { assert(sizeof(_snapshot) >= sizeof(VirtualMemorySnapshot), "Sanity Check"); // Use placement operator new to initialize static data area. diff --git a/src/hotspot/share/services/virtualMemoryTracker.hpp b/src/hotspot/share/services/virtualMemoryTracker.hpp index af9f8bdbfc0..172c3cc7d0c 100644 --- a/src/hotspot/share/services/virtualMemoryTracker.hpp +++ b/src/hotspot/share/services/virtualMemoryTracker.hpp @@ -43,12 +43,20 @@ class VirtualMemory { size_t _reserved; size_t _committed; +#ifdef ASSERT + volatile size_t _peak_size; + void update_peak(size_t size); +#endif // ASSERT + public: - VirtualMemory() : _reserved(0), _committed(0) { } + VirtualMemory() : _reserved(0), _committed(0) { + DEBUG_ONLY(_peak_size = 0;) + } inline void reserve_memory(size_t sz) { _reserved += sz; } inline void commit_memory (size_t sz) { _committed += sz; + DEBUG_ONLY(update_peak(sz);) assert(_committed <= _reserved, "Sanity check"); } @@ -64,6 +72,9 @@ class VirtualMemory { inline size_t reserved() const { return _reserved; } inline size_t committed() const { return _committed; } + inline size_t peak_size() const { + return DEBUG_ONLY(Atomic::load(&_peak_size)) NOT_DEBUG(0); + } }; // Virtual memory allocation site, keeps track where the virtual memory is reserved. From 4b445753e6f4683f4c638fdbd1b2823a3bbacef2 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Tue, 5 Sep 2023 12:45:55 +0000 Subject: [PATCH 68/86] 8305637: Remove Opaque1 nodes for Parse Predicates and clean up useless predicate elimination Reviewed-by: roland, kvn --- .../gc/shenandoah/c2/shenandoahSupport.cpp | 6 +- src/hotspot/share/opto/cfgnode.hpp | 20 +- src/hotspot/share/opto/compile.cpp | 31 +-- src/hotspot/share/opto/compile.hpp | 37 ++-- src/hotspot/share/opto/graphKit.cpp | 6 +- src/hotspot/share/opto/ifnode.cpp | 40 ++-- src/hotspot/share/opto/loopPredicate.cpp | 160 ++++++++-------- src/hotspot/share/opto/loopnode.cpp | 178 ++++++++++-------- src/hotspot/share/opto/loopnode.hpp | 29 ++- src/hotspot/share/opto/loopopts.cpp | 2 +- src/hotspot/share/opto/macro.cpp | 2 +- src/hotspot/share/opto/multnode.cpp | 37 +--- src/hotspot/share/opto/multnode.hpp | 4 +- src/hotspot/share/opto/node.cpp | 7 + src/hotspot/share/opto/predicates.cpp | 26 ++- src/hotspot/share/opto/predicates.hpp | 15 ++ 16 files changed, 343 insertions(+), 257 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 71068f76043..21e6a068de1 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -734,7 +734,7 @@ Node* ShenandoahBarrierC2Support::no_branches(Node* c, Node* dom, bool allow_one for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) { Node* u = n->fast_out(j); if (u->is_CFG()) { - if (!wq.member(u) && !u->as_Proj()->is_uncommon_trap_proj(Deoptimization::Reason_none)) { + if (!wq.member(u) && !u->as_Proj()->is_uncommon_trap_proj()) { return NodeSentinel; } } @@ -743,7 +743,7 @@ Node* ShenandoahBarrierC2Support::no_branches(Node* c, Node* dom, bool allow_one } } else if (c->is_Proj()) { if (c->is_IfProj()) { - if (c->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) != nullptr) { + if (c->as_Proj()->is_uncommon_trap_if_pattern() != nullptr) { // continue; } else { if (!allow_one_proj) { @@ -1138,7 +1138,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { if (u_t->meet(TypePtr::NULL_PTR) != u_t && u->in(0)->Opcode() == Op_IfTrue && - u->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) && + u->in(0)->as_Proj()->is_uncommon_trap_if_pattern() && u->in(0)->in(0)->is_If() && u->in(0)->in(0)->in(1)->Opcode() == Op_Bool && u->in(0)->in(0)->in(1)->as_Bool()->_test._test == BoolTest::ne && diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 9fc68f56309..e0a640aae94 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -463,8 +463,9 @@ class RangeCheckNode : public IfNode { // More information about predicates can be found in loopPredicate.cpp. class ParsePredicateNode : public IfNode { Deoptimization::DeoptReason _deopt_reason; + bool _useless; // If the associated loop dies, this parse predicate becomes useless and can be cleaned up by Value(). public: - ParsePredicateNode(Node* control, Node* bol, Deoptimization::DeoptReason deopt_reason); + ParsePredicateNode(Node* control, Deoptimization::DeoptReason deopt_reason, PhaseGVN* gvn); virtual int Opcode() const; virtual uint size_of() const { return sizeof(*this); } @@ -472,8 +473,25 @@ class ParsePredicateNode : public IfNode { return _deopt_reason; } + bool is_useless() const { + return _useless; + } + + void mark_useless() { + _useless = true; + } + + void mark_useful() { + _useless = false; + } + Node* uncommon_trap() const; + Node* Ideal(PhaseGVN* phase, bool can_reshape) { + return nullptr; // Don't optimize + } + + const Type* Value(PhaseGVN* phase) const; NOT_PRODUCT(void dump_spec(outputStream* st) const;) }; diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index d9628459cf8..b715936f237 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -360,10 +360,11 @@ void Compile::remove_useless_late_inlines(GrowableArray* inlines assert(found <= 1, "not unique"); } -void Compile::remove_useless_nodes(GrowableArray& node_list, Unique_Node_List& useful) { +template::value)> +void Compile::remove_useless_nodes(GrowableArray& node_list, Unique_Node_List& useful) { for (int i = node_list.length() - 1; i >= 0; i--) { - Node* n = node_list.at(i); - if (!useful.member(n)) { + N* node = node_list.at(i); + if (!useful.member(node)) { node_list.delete_at(i); // replaces i-th with last element which is known to be useful (already processed) } } @@ -389,6 +390,9 @@ void Compile::remove_useless_node(Node* dead) { if (dead->Opcode() == Op_Opaque4) { remove_template_assertion_predicate_opaq(dead); } + if (dead->is_ParsePredicate()) { + remove_parse_predicate(dead->as_ParsePredicate()); + } if (dead->for_post_loop_opts_igvn()) { remove_from_post_loop_opts_igvn(dead); } @@ -436,7 +440,7 @@ void Compile::disconnect_useless_nodes(Unique_Node_List& useful, Unique_Node_Lis } remove_useless_nodes(_macro_nodes, useful); // remove useless macro nodes - remove_useless_nodes(_parse_predicate_opaqs, useful); // remove useless Parse Predicate opaque nodes + remove_useless_nodes(_parse_predicates, useful); // remove useless Parse Predicate nodes remove_useless_nodes(_template_assertion_predicate_opaqs, useful); // remove useless Assertion Predicate opaque nodes remove_useless_nodes(_expensive_nodes, useful); // remove useless expensive nodes remove_useless_nodes(_for_post_loop_igvn, useful); // remove useless node recorded for post loop opts IGVN pass @@ -631,7 +635,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, _failure_reason(nullptr), _intrinsics (comp_arena(), 0, 0, nullptr), _macro_nodes (comp_arena(), 8, 0, nullptr), - _parse_predicate_opaqs (comp_arena(), 8, 0, nullptr), + _parse_predicates (comp_arena(), 8, 0, nullptr), _template_assertion_predicate_opaqs (comp_arena(), 8, 0, nullptr), _expensive_nodes (comp_arena(), 8, 0, nullptr), _for_post_loop_igvn(comp_arena(), 8, 0, nullptr), @@ -1807,18 +1811,18 @@ bool Compile::can_alias(const TypePtr* adr_type, int alias_idx) { return adr_idx == alias_idx; } -// Remove the opaque nodes that protect the Parse Predicates so that all unused -// checks and uncommon_traps will be eliminated from the ideal graph. -void Compile::cleanup_parse_predicates(PhaseIterGVN& igvn) const { +// Mark all ParsePredicateNodes as useless. They will later be removed from the graph in IGVN together with their +// uncommon traps if no Runtime Predicates were created from the Parse Predicates. +void Compile::mark_parse_predicate_nodes_useless(PhaseIterGVN& igvn) { if (parse_predicate_count() == 0) { return; } - for (int i = parse_predicate_count(); i > 0; i--) { - Node* n = parse_predicate_opaque1_node(i - 1); - assert(n->Opcode() == Op_Opaque1, "must be"); - igvn.replace_node(n, n->in(1)); + for (int i = 0; i < parse_predicate_count(); i++) { + ParsePredicateNode* parse_predicate = _parse_predicates.at(i); + parse_predicate->mark_useless(); + igvn._worklist.push(parse_predicate); } - assert(parse_predicate_count() == 0, "should be clean!"); + _parse_predicates.clear(); } void Compile::record_for_post_loop_opts_igvn(Node* n) { @@ -1851,6 +1855,7 @@ void Compile::process_for_post_loop_opts_igvn(PhaseIterGVN& igvn) { } igvn.optimize(); assert(_for_post_loop_igvn.length() == 0, "no more delayed nodes allowed"); + assert(C->parse_predicate_count() == 0, "all parse predicates should have been removed now"); // Sometimes IGVN sets major progress (e.g., when processing loop nodes). if (C->major_progress()) { diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index a8d7f78942c..1eb021feebf 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -69,6 +69,7 @@ class Node_Notes; class NodeHash; class NodeCloneInfo; class OptoReg; +class ParsePredicateNode; class PhaseCFG; class PhaseGVN; class PhaseIterGVN; @@ -357,7 +358,7 @@ class Compile : public Phase { const char* _failure_reason; // for record_failure/failing pattern GrowableArray _intrinsics; // List of intrinsics. GrowableArray _macro_nodes; // List of nodes which need to be expanded before matching. - GrowableArray _parse_predicate_opaqs; // List of Opaque1 nodes for the Parse Predicates. + GrowableArray _parse_predicates; // List of Parse Predicates. GrowableArray _template_assertion_predicate_opaqs; // List of Opaque4 nodes for Template Assertion Predicates. GrowableArray _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common GrowableArray _for_post_loop_igvn; // List of nodes for IGVN after loop opts are over @@ -703,13 +704,13 @@ class Compile : public Phase { #endif int macro_count() const { return _macro_nodes.length(); } - int parse_predicate_count() const { return _parse_predicate_opaqs.length(); } + int parse_predicate_count() const { return _parse_predicates.length(); } int template_assertion_predicate_count() const { return _template_assertion_predicate_opaqs.length(); } int expensive_count() const { return _expensive_nodes.length(); } int coarsened_count() const { return _coarsened_locks.length(); } Node* macro_node(int idx) const { return _macro_nodes.at(idx); } - Node* parse_predicate_opaque1_node(int idx) const { return _parse_predicate_opaqs.at(idx); } + ParsePredicateNode* parse_predicate(int idx) const { return _parse_predicates.at(idx); } Node* template_assertion_predicate_opaq_node(int idx) const { return _template_assertion_predicate_opaqs.at(idx); @@ -728,10 +729,6 @@ class Compile : public Phase { // this function may be called twice for a node so we can only remove it // if it's still existing. _macro_nodes.remove_if_existing(n); - // remove from _parse_predicate_opaqs list also if it is there - if (parse_predicate_count() > 0) { - _parse_predicate_opaqs.remove_if_existing(n); - } // Remove from coarsened locks list if present if (coarsened_count() > 0) { remove_coarsened_lock(n); @@ -741,16 +738,24 @@ class Compile : public Phase { void remove_expensive_node(Node* n) { _expensive_nodes.remove_if_existing(n); } - void add_parse_predicate_opaq(Node* n) { - assert(!_parse_predicate_opaqs.contains(n), "duplicate entry in Parse Predicate opaque1 list"); - assert(_macro_nodes.contains(n), "should have already been in macro list"); - _parse_predicate_opaqs.append(n); + + void add_parse_predicate(ParsePredicateNode* n) { + assert(!_parse_predicates.contains(n), "duplicate entry in Parse Predicate list"); + _parse_predicates.append(n); + } + + void remove_parse_predicate(ParsePredicateNode* n) { + if (parse_predicate_count() > 0) { + _parse_predicates.remove_if_existing(n); + } } + void add_template_assertion_predicate_opaq(Node* n) { assert(!_template_assertion_predicate_opaqs.contains(n), "duplicate entry in template assertion predicate opaque4 list"); _template_assertion_predicate_opaqs.append(n); } + void remove_template_assertion_predicate_opaq(Node* n) { if (template_assertion_predicate_count() > 0) { _template_assertion_predicate_opaqs.remove_if_existing(n); @@ -775,12 +780,7 @@ class Compile : public Phase { void sort_macro_nodes(); - // Remove the opaque nodes that protect the Parse Predicates so that the unused checks and - // uncommon traps will be eliminated from the graph. - void cleanup_parse_predicates(PhaseIterGVN &igvn) const; - bool is_predicate_opaq(Node* n) const { - return _parse_predicate_opaqs.contains(n); - } + void mark_parse_predicate_nodes_useless(PhaseIterGVN& igvn); // Are there candidate expensive nodes for optimization? bool should_optimize_expensive_nodes(PhaseIterGVN &igvn); @@ -1021,7 +1021,8 @@ class Compile : public Phase { _vector_reboxing_late_inlines.push(cg); } - void remove_useless_nodes (GrowableArray& node_list, Unique_Node_List &useful); + template::value)> + void remove_useless_nodes(GrowableArray& node_list, Unique_Node_List& useful); void remove_useless_late_inlines(GrowableArray* inlines, Unique_Node_List &useful); void remove_useless_late_inlines(GrowableArray* inlines, Node* dead); diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index d9ea82c03c1..c7a2698de12 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -3996,11 +3996,7 @@ void GraphKit::add_parse_predicate(Deoptimization::DeoptReason reason, const int return; } - Node* cont = _gvn.intcon(1); - Node* opaq = _gvn.transform(new Opaque1Node(C, cont)); - C->add_parse_predicate_opaq(opaq); - Node* bol = _gvn.transform(new Conv2BNode(opaq)); - ParsePredicateNode* parse_predicate = new ParsePredicateNode(control(), bol, reason); + ParsePredicateNode* parse_predicate = new ParsePredicateNode(control(), reason, &_gvn); _gvn.set_type(parse_predicate, parse_predicate->Value(&_gvn)); Node* if_false = _gvn.transform(new IfFalseNode(parse_predicate)); { diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index e10b7f9c5ad..b1192825379 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -800,7 +800,7 @@ bool IfNode::is_dominator_unc(CallStaticJavaNode* dom_unc, CallStaticJavaNode* u // Return projection that leads to an uncommon trap if any ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call) const { for (int i = 0; i < 2; i++) { - call = proj_out(i)->is_uncommon_trap_proj(Deoptimization::Reason_none); + call = proj_out(i)->is_uncommon_trap_proj(); if (call != nullptr) { return proj_out(i); } @@ -811,7 +811,7 @@ ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call) const { // Do this If and the dominating If both branch out to an uncommon trap bool IfNode::has_only_uncommon_traps(ProjNode* proj, ProjNode*& success, ProjNode*& fail, PhaseIterGVN* igvn) { ProjNode* otherproj = proj->other_if_proj(); - CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none); + CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(); if (otherproj->outcnt() == 1 && dom_unc != nullptr) { // We need to re-execute the folded Ifs after deoptimization from the merged traps @@ -1076,8 +1076,8 @@ Node* IfNode::merge_uncommon_traps(ProjNode* proj, ProjNode* success, ProjNode* ProjNode* otherproj = proj->other_if_proj(); - CallStaticJavaNode* unc = success->is_uncommon_trap_proj(Deoptimization::Reason_none); - CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(Deoptimization::Reason_none); + CallStaticJavaNode* unc = success->is_uncommon_trap_proj(); + CallStaticJavaNode* dom_unc = otherproj->is_uncommon_trap_proj(); if (unc != dom_unc) { Node* r = new RegionNode(3); @@ -1241,13 +1241,13 @@ bool IfNode::is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn) { if (proj == nullptr) { return false; } - CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(); if (unc != nullptr && proj->outcnt() <= 2) { if (proj->outcnt() == 1 || // Allow simple null check from LoadRange (is_cmp_with_loadrange(proj) && is_null_check(proj, igvn))) { - CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); - CallStaticJavaNode* dom_unc = proj->in(0)->in(0)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(); + CallStaticJavaNode* dom_unc = proj->in(0)->in(0)->as_Proj()->is_uncommon_trap_if_pattern(); assert(dom_unc != nullptr, "is_uncommon_trap_if_pattern returned null"); // reroute_side_effect_free_unc changes the state of this @@ -1278,9 +1278,9 @@ bool IfNode::is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn) { // where the first CmpI would have prevented it from executing: on a // trap, we need to restart execution at the state of the first CmpI void IfNode::reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn) { - CallStaticJavaNode* dom_unc = dom_proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* dom_unc = dom_proj->is_uncommon_trap_if_pattern(); ProjNode* otherproj = proj->other_if_proj(); - CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* unc = proj->is_uncommon_trap_if_pattern(); Node* call_proj = dom_unc->unique_ctrl_out(); Node* halt = call_proj->unique_ctrl_out(); @@ -1975,11 +1975,13 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { return dominated_by(prev_dom, igvn); } -ParsePredicateNode::ParsePredicateNode(Node* control, Node* bol, Deoptimization::DeoptReason deopt_reason) - : IfNode(control, bol, PROB_MAX, COUNT_UNKNOWN), - _deopt_reason(deopt_reason) { +ParsePredicateNode::ParsePredicateNode(Node* control, Deoptimization::DeoptReason deopt_reason, PhaseGVN* gvn) + : IfNode(control, gvn->intcon(1), PROB_MAX, COUNT_UNKNOWN), + _deopt_reason(deopt_reason), + _useless(false) { init_class_id(Class_ParsePredicate); - assert(bol->Opcode() == Op_Conv2B && bol->in(1) != nullptr && bol->in(1)->is_Opaque1(), "wrong boolean input"); + gvn->C->add_parse_predicate(this); + gvn->C->record_for_post_loop_opts_igvn(this); #ifdef ASSERT switch (deopt_reason) { case Deoptimization::Reason_predicate: @@ -1999,6 +2001,18 @@ Node* ParsePredicateNode::uncommon_trap() const { return uct_region_or_call; } +// Fold this node away once it becomes useless or at latest in post loop opts IGVN. +const Type* ParsePredicateNode::Value(PhaseGVN* phase) const { + if (phase->type(in(0)) == Type::TOP) { + return Type::TOP; + } + if (_useless || phase->C->post_loop_opts_phase()) { + return TypeTuple::IFTRUE; + } else { + return bottom_type(); + } +} + #ifndef PRODUCT void ParsePredicateNode::dump_spec(outputStream* st) const { st->print(" #"); diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index 6c655e6f137..d569bfcfab5 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -99,43 +99,43 @@ void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred, // We will create a region to guard the uct call if there is no one there. // The continuation projection (if_cont) of the new_iff is returned which // is an IfTrue projection. This code is also used to clone predicates to cloned loops. -IfProjNode* PhaseIdealLoop::create_new_if_for_predicate(IfProjNode* cont_proj, Node* new_entry, +IfProjNode* PhaseIdealLoop::create_new_if_for_predicate(ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason, const int opcode, const bool rewire_uncommon_proj_phi_inputs) { - assert(cont_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!"); - IfNode* iff = cont_proj->in(0)->as_If(); + assert(parse_predicate_proj->is_uncommon_trap_if_pattern(reason), "must be a uct if pattern!"); + ParsePredicateNode* parse_predicate = parse_predicate_proj->in(0)->as_ParsePredicate(); - ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); - Node *rgn = uncommon_proj->unique_ctrl_out(); - assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); + ProjNode* uncommon_proj = parse_predicate->proj_out(false); + Node* uct_region = uncommon_proj->unique_ctrl_out(); + assert(uct_region->is_Region() || uct_region->is_Call(), "must be a region or call uct"); uint proj_index = 1; // region's edge corresponding to uncommon_proj - if (!rgn->is_Region()) { // create a region to guard the call - assert(rgn->is_Call(), "must be call uct"); - CallNode* call = rgn->as_Call(); + if (!uct_region->is_Region()) { // create a region to guard the call + assert(uct_region->is_Call(), "must be call uct"); + CallNode* call = uct_region->as_Call(); IdealLoopTree* loop = get_loop(call); - rgn = new RegionNode(1); + uct_region = new RegionNode(1); Node* uncommon_proj_orig = uncommon_proj; uncommon_proj = uncommon_proj->clone()->as_Proj(); - register_control(uncommon_proj, loop, iff); - rgn->add_req(uncommon_proj); - register_control(rgn, loop, uncommon_proj); - _igvn.replace_input_of(call, 0, rgn); + register_control(uncommon_proj, loop, parse_predicate); + uct_region->add_req(uncommon_proj); + register_control(uct_region, loop, uncommon_proj); + _igvn.replace_input_of(call, 0, uct_region); // When called from beautify_loops() idom is not constructed yet. if (_idom != nullptr) { - set_idom(call, rgn, dom_depth(rgn)); + set_idom(call, uct_region, dom_depth(uct_region)); } // Move nodes pinned on the projection or whose control is set to // the projection to the region. - lazy_replace(uncommon_proj_orig, rgn); + lazy_replace(uncommon_proj_orig, uct_region); } else { // Find region's edge corresponding to uncommon_proj - for (; proj_index < rgn->req(); proj_index++) - if (rgn->in(proj_index) == uncommon_proj) break; - assert(proj_index < rgn->req(), "sanity"); + for (; proj_index < uct_region->req(); proj_index++) + if (uct_region->in(proj_index) == uncommon_proj) break; + assert(proj_index < uct_region->req(), "sanity"); } - Node* entry = iff->in(0); + Node* entry = parse_predicate->in(0); if (new_entry != nullptr) { // Cloning the predicate to new location. entry = new_entry; @@ -145,13 +145,13 @@ IfProjNode* PhaseIdealLoop::create_new_if_for_predicate(IfProjNode* cont_proj, N IfNode* new_iff = nullptr; switch (opcode) { case Op_If: - new_iff = new IfNode(entry, iff->in(1), iff->_prob, iff->_fcnt); + new_iff = new IfNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt); break; case Op_RangeCheck: - new_iff = new RangeCheckNode(entry, iff->in(1), iff->_prob, iff->_fcnt); + new_iff = new RangeCheckNode(entry, parse_predicate->in(1), parse_predicate->_prob, parse_predicate->_fcnt); break; case Op_ParsePredicate: - new_iff = new ParsePredicateNode(entry, iff->in(1), reason); + new_iff = new ParsePredicateNode(entry, reason, &_igvn); break; default: fatal("no other If variant here"); @@ -160,23 +160,19 @@ IfProjNode* PhaseIdealLoop::create_new_if_for_predicate(IfProjNode* cont_proj, N IfProjNode* if_cont = new IfTrueNode(new_iff); IfProjNode* if_uct = new IfFalseNode(new_iff); - if (cont_proj->is_IfFalse()) { - // Swap - IfProjNode* tmp = if_uct; if_uct = if_cont; if_cont = tmp; - } register_control(if_cont, lp, new_iff); - register_control(if_uct, get_loop(rgn), new_iff); + register_control(if_uct, get_loop(uct_region), new_iff); - _igvn.add_input_to(rgn, if_uct); + _igvn.add_input_to(uct_region, if_uct); // If rgn has phis add new edges which has the same // value as on original uncommon_proj pass. - assert(rgn->in(rgn->req() -1) == if_uct, "new edge should be last"); + assert(uct_region->in(uct_region->req() - 1) == if_uct, "new edge should be last"); bool has_phi = false; - for (DUIterator_Fast imax, i = rgn->fast_outs(imax); i < imax; i++) { - Node* use = rgn->fast_out(i); + for (DUIterator_Fast imax, i = uct_region->fast_outs(imax); i < imax; i++) { + Node* use = uct_region->fast_out(i); if (use->is_Phi() && use->outcnt() > 0) { - assert(use->in(0) == rgn, ""); + assert(use->in(0) == uct_region, ""); _igvn.rehash_node_delayed(use); Node* phi_input = use->in(proj_index); @@ -197,21 +193,21 @@ IfProjNode* PhaseIdealLoop::create_new_if_for_predicate(IfProjNode* cont_proj, N has_phi = true; } } - assert(!has_phi || rgn->req() > 3, "no phis when region is created"); + assert(!has_phi || uct_region->req() > 3, "no phis when region is created"); if (new_entry == nullptr) { // Attach if_cont to iff - _igvn.replace_input_of(iff, 0, if_cont); + _igvn.replace_input_of(parse_predicate, 0, if_cont); if (_idom != nullptr) { - set_idom(iff, if_cont, dom_depth(iff)); + set_idom(parse_predicate, if_cont, dom_depth(parse_predicate)); } } // When called from beautify_loops() idom is not constructed yet. if (_idom != nullptr) { - Node* ridom = idom(rgn); + Node* ridom = idom(uct_region); Node* nrdom = dom_lca_internal(ridom, new_iff); - set_idom(rgn, nrdom, dom_depth(rgn)); + set_idom(uct_region, nrdom, dom_depth(uct_region)); } return if_cont->as_IfProj(); @@ -303,24 +299,14 @@ void PhaseIdealLoop::rewire_inputs_of_clones_to_clones(Node* new_ctrl, Node* clo } } -IfProjNode* PhaseIdealLoop::clone_parse_predicate_to_unswitched_loop(ParsePredicateSuccessProj* predicate_proj, +IfProjNode* PhaseIdealLoop::clone_parse_predicate_to_unswitched_loop(ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason, const bool slow_loop) { - IfProjNode* new_predicate_proj = create_new_if_for_predicate(predicate_proj, new_entry, reason, Op_ParsePredicate, + IfProjNode* new_predicate_proj = create_new_if_for_predicate(parse_predicate_proj, new_entry, reason, Op_ParsePredicate, slow_loop); - IfNode* iff = new_predicate_proj->in(0)->as_If(); - Node* ctrl = iff->in(0); - - // Match original condition since predicate's projections could be swapped. - assert(predicate_proj->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); - Node* opq = new Opaque1Node(C, predicate_proj->in(0)->in(1)->in(1)->in(1)); - C->add_parse_predicate_opaq(opq); - Node* bol = new Conv2BNode(opq); - register_new_node(opq, ctrl); - register_new_node(bol, ctrl); - _igvn.hash_delete(iff); - iff->set_req(1, bol); + assert(new_predicate_proj->is_IfTrue(), "the success projection of a Parse Predicate is a true projection"); + ParsePredicateNode* parse_predicate = new_predicate_proj->in(0)->as_ParsePredicate(); return new_predicate_proj; } @@ -329,9 +315,11 @@ IfProjNode* PhaseIdealLoop::clone_parse_predicate_to_unswitched_loop(ParsePredic // cloned predicates. void PhaseIdealLoop::clone_assertion_predicates_to_unswitched_loop(IdealLoopTree* loop, const Node_List& old_new, Deoptimization::DeoptReason reason, - IfProjNode* old_predicate_proj, IfProjNode* iffast_pred, - IfProjNode* ifslow_pred) { - assert(iffast_pred->in(0)->is_If() && ifslow_pred->in(0)->is_If(), "sanity check"); + IfProjNode* old_predicate_proj, + ParsePredicateSuccessProj* fast_loop_parse_predicate_proj, + ParsePredicateSuccessProj* slow_loop_parse_predicate_proj) { + assert(fast_loop_parse_predicate_proj->in(0)->is_ParsePredicate() && + slow_loop_parse_predicate_proj->in(0)->is_ParsePredicate(), "sanity check"); // Only need to clone range check predicates as those can be changed and duplicated by inserting pre/main/post loops // and doing loop unrolling. Push the original predicates on a list to later process them in reverse order to keep the // original predicate order. @@ -350,9 +338,9 @@ void PhaseIdealLoop::clone_assertion_predicates_to_unswitched_loop(IdealLoopTree assert(predicate->is_Proj() && predicate->as_Proj()->is_IfProj(), "predicate must be a projection of an if node"); IfProjNode* predicate_proj = predicate->as_IfProj(); - IfProjNode* fast_proj = clone_assertion_predicate_for_unswitched_loops(iff, predicate_proj, reason, iffast_pred); + IfProjNode* fast_proj = clone_assertion_predicate_for_unswitched_loops(iff, predicate_proj, reason, fast_loop_parse_predicate_proj); assert(assertion_predicate_has_loop_opaque_node(fast_proj->in(0)->as_If()), "must find Assertion Predicate for fast loop"); - IfProjNode* slow_proj = clone_assertion_predicate_for_unswitched_loops(iff, predicate_proj, reason, ifslow_pred); + IfProjNode* slow_proj = clone_assertion_predicate_for_unswitched_loops(iff, predicate_proj, reason, slow_loop_parse_predicate_proj); assert(assertion_predicate_has_loop_opaque_node(slow_proj->in(0)->as_If()), "must find Assertion Predicate for slow loop"); // Update control dependent data nodes. @@ -378,14 +366,13 @@ void PhaseIdealLoop::clone_assertion_predicates_to_unswitched_loop(IdealLoopTree // Put all Assertion Predicate projections on a list, starting at 'predicate' and going up in the tree. If 'get_opaque' // is set, then the Opaque4 nodes of the Assertion Predicates are put on the list instead of the projections. void PhaseIdealLoop::get_assertion_predicates(Node* predicate, Unique_Node_List& list, bool get_opaque) { - IfNode* iff = predicate->in(0)->as_If(); - ProjNode* uncommon_proj = iff->proj_out(1 - predicate->as_Proj()->_con); + ParsePredicateNode* parse_predicate = predicate->in(0)->as_ParsePredicate(); + ProjNode* uncommon_proj = parse_predicate->proj_out(1 - predicate->as_Proj()->_con); Node* rgn = uncommon_proj->unique_ctrl_out(); assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct"); - assert(iff->in(1)->in(1)->Opcode() == Op_Opaque1, "unexpected predicate shape"); - predicate = iff->in(0); + predicate = parse_predicate->in(0); while (predicate != nullptr && predicate->is_Proj() && predicate->in(0)->is_If()) { - iff = predicate->in(0)->as_If(); + IfNode* iff = predicate->in(0)->as_If(); uncommon_proj = iff->proj_out(1 - predicate->as_Proj()->_con); if (uncommon_proj->unique_ctrl_out() != rgn) { break; @@ -408,12 +395,12 @@ void PhaseIdealLoop::get_assertion_predicates(Node* predicate, Unique_Node_List& // predicate again). IfProjNode* PhaseIdealLoop::clone_assertion_predicate_for_unswitched_loops(Node* iff, IfProjNode* predicate, Deoptimization::DeoptReason reason, - IfProjNode* output_proj) { - Node* bol = create_bool_from_template_assertion_predicate(iff, nullptr, nullptr, output_proj); - IfProjNode* if_proj = create_new_if_for_predicate(output_proj, nullptr, reason, iff->Opcode(), false); + ParsePredicateSuccessProj* parse_predicate_proj) { + Node* bol = create_bool_from_template_assertion_predicate(iff, nullptr, nullptr, parse_predicate_proj); + IfProjNode* if_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, iff->Opcode(), false); _igvn.replace_input_of(if_proj->in(0), 1, bol); - _igvn.replace_input_of(output_proj->in(0), 0, if_proj); - set_idom(output_proj->in(0), if_proj, dom_depth(if_proj)); + _igvn.replace_input_of(parse_predicate_proj->in(0), 0, if_proj); + set_idom(parse_predicate_proj->in(0), if_proj, dom_depth(if_proj)); return if_proj; } @@ -446,9 +433,13 @@ void PhaseIdealLoop::clone_loop_predication_predicates_to_unswitched_loop(IdealL IfProjNode*& iffast_pred, IfProjNode*& ifslow_pred) { if (predicate_block->has_parse_predicate()) { + // We currently only clone Assertion Predicates if there are Parse Predicates. This is not entirely correct and will + // be changed with the complete fix for Assertion Predicates. clone_parse_predicate_to_unswitched_loops(predicate_block, reason, iffast_pred, ifslow_pred); + assert(iffast_pred->in(0)->is_ParsePredicate() && ifslow_pred->in(0)->is_ParsePredicate(), + "must be success projections of the cloned Parse Predicates"); clone_assertion_predicates_to_unswitched_loop(loop, old_new, reason, predicate_block->parse_predicate_success_proj(), - iffast_pred, ifslow_pred); + iffast_pred->as_IfTrue(), ifslow_pred->as_IfTrue()); } } @@ -1156,7 +1147,7 @@ void PhaseIdealLoop::loop_predication_follow_branches(Node *n, IdealLoopTree *lo stack.push(in, 1); break; } else if (in->is_IfProj() && - in->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) && + in->as_Proj()->is_uncommon_trap_if_pattern() && (in->in(0)->Opcode() == Op_If || in->in(0)->Opcode() == Op_RangeCheck)) { if (pf.to(in) * loop_trip_cnt >= 1) { @@ -1305,19 +1296,20 @@ bool PhaseIdealLoop::loop_predication_impl_helper(IdealLoopTree* loop, IfProjNod // them by making a copy of them when splitting a loop into sub loops. The Assertion Predicates ensure that dead sub // loops are removed properly. IfProjNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj, - IfProjNode* predicate_proj, IfProjNode* upper_bound_proj, - int scale, Node* offset, Node* init, Node* limit, jint stride, + ParsePredicateSuccessProj* parse_predicate_proj, + IfProjNode* upper_bound_proj, const int scale, Node* offset, + Node* init, Node* limit, const jint stride, Node* rng, bool& overflow, Deoptimization::DeoptReason reason) { // First predicate for the initial value on first loop iteration Node* opaque_init = new OpaqueLoopInitNode(C, init); register_new_node(opaque_init, upper_bound_proj); - bool negate = (if_proj->_con != predicate_proj->_con); + bool negate = (if_proj->_con != parse_predicate_proj->_con); BoolNode* bol = rc_predicate(loop, upper_bound_proj, scale, offset, opaque_init, limit, stride, rng, (stride > 0) != (scale > 0), overflow); Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); // This will go away once loop opts are over C->add_template_assertion_predicate_opaq(opaque_bol); register_new_node(opaque_bol, upper_bound_proj); - IfProjNode* new_proj = create_new_if_for_predicate(predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode()); + IfProjNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode()); _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); assert(opaque_init->outcnt() > 0, "should be used"); @@ -1333,14 +1325,14 @@ IfProjNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL register_new_node(max_value, new_proj); // init + (current stride - initial stride) is within the loop so narrow its type by leveraging the type of the iv Phi max_value = new CastIINode(max_value, loop->_head->as_CountedLoop()->phi()->bottom_type()); - register_new_node(max_value, predicate_proj); + register_new_node(max_value, parse_predicate_proj); bol = rc_predicate(loop, new_proj, scale, offset, max_value, limit, stride, rng, (stride > 0) != (scale > 0), overflow); opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); C->add_template_assertion_predicate_opaq(opaque_bol); register_new_node(opaque_bol, new_proj); - new_proj = create_new_if_for_predicate(predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode()); + new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode()); _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); assert(max_value->outcnt() > 0, "should be used"); assert(assertion_predicate_has_loop_opaque_node(new_proj->in(0)->as_If()), "unexpected"); @@ -1350,13 +1342,7 @@ IfProjNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL // Insert Hoisted Check Predicates for null checks and range checks and additional Template Assertion Predicates for // range checks. -bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { - if (!UseLoopPredicate) return false; - - if (!loop->_head->is_Loop()) { - // Could be a simple region when irreducible loops are present. - return false; - } +bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree* loop) { LoopNode* head = loop->_head->as_Loop(); if (head->unique_ctrl_out()->is_NeverBranch()) { @@ -1436,7 +1422,7 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { IfProjNode* if_proj = n->as_IfProj(); IfNode* iff = if_proj->in(0)->as_If(); - CallStaticJavaNode* call = if_proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* call = if_proj->is_uncommon_trap_if_pattern(); if (call == nullptr) { if (loop->is_loop_exit(iff)) { // stop processing the remaining projs in the list because the execution of them @@ -1474,7 +1460,7 @@ bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) { while (if_proj_list.size() > 0) { Node* if_proj = if_proj_list.pop(); float f = pf.to(if_proj); - if (if_proj->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none) && + if (if_proj->as_Proj()->is_uncommon_trap_if_pattern() && f * loop_trip_cnt >= 1) { ParsePredicateSuccessProj* profiled_loop_parse_predicate_proj = profiled_loop_predicate_block->parse_predicate_success_proj(); @@ -1546,7 +1532,7 @@ bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) { } // self - if (!_irreducible && !tail()->is_top()) { + if (can_apply_loop_predication()) { hoisted |= phase->loop_predication_impl(this); } @@ -1556,3 +1542,7 @@ bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) { return hoisted; } + +bool IdealLoopTree::can_apply_loop_predication() { + return _head->is_Loop() && !_irreducible && !tail()->is_top(); +} diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 5107c6e9692..7bd92f33af7 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -177,7 +177,7 @@ Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) { // expensive nodes will notice the loop and skip over it to try to // move the node further up. if (ctl->is_CountedLoop() && ctl->in(1) != nullptr && ctl->in(1)->in(0) != nullptr && ctl->in(1)->in(0)->is_If()) { - if (!ctl->in(1)->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) { + if (!ctl->in(1)->as_Proj()->is_uncommon_trap_if_pattern()) { break; } next = idom(ctl->in(1)->in(0)); @@ -191,7 +191,7 @@ Node *PhaseIdealLoop::get_early_ctrl_for_expensive(Node *n, Node* earliest) { } else if (parent_ctl->is_CountedLoopEnd() && parent_ctl->as_CountedLoopEnd()->loopnode() != nullptr) { next = parent_ctl->as_CountedLoopEnd()->loopnode()->init_control(); } else if (parent_ctl->is_If()) { - if (!ctl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none)) { + if (!ctl->as_Proj()->is_uncommon_trap_if_pattern()) { break; } assert(idom(ctl) == parent_ctl, "strange"); @@ -350,11 +350,6 @@ void PhaseIdealLoop::insert_loop_limit_check_predicate(ParsePredicateSuccessProj Deoptimization::Reason_loop_limit_check, Op_If); Node* iff = new_predicate_proj->in(0); - assert(iff->Opcode() == Op_If, "bad graph shape"); - Node* conv = iff->in(1); - assert(conv->Opcode() == Op_Conv2B, "bad graph shape"); - Node* opaq = conv->in(1); - assert(opaq->Opcode() == Op_Opaque1, "bad graph shape"); cmp_limit = _igvn.register_new_node_with_optimizer(cmp_limit); bol = _igvn.register_new_node_with_optimizer(bol); set_subtree_ctrl(bol, false); @@ -564,19 +559,12 @@ Node* PhaseIdealLoop::loop_nest_replace_iv(Node* iv_to_replace, Node* inner_iv, void PhaseIdealLoop::add_parse_predicate(Deoptimization::DeoptReason reason, Node* inner_head, IdealLoopTree* loop, SafePointNode* sfpt) { if (!C->too_many_traps(reason)) { - Node* cont = _igvn.intcon(1); - Node* opaq = new Opaque1Node(C, cont); - _igvn.register_new_node_with_optimizer(opaq); - Node* bol = new Conv2BNode(opaq); - _igvn.register_new_node_with_optimizer(bol); - set_subtree_ctrl(bol, false); - ParsePredicateNode* iff = new ParsePredicateNode(inner_head->in(LoopNode::EntryControl), bol, reason); - register_control(iff, loop, inner_head->in(LoopNode::EntryControl)); - Node* if_false = new IfFalseNode(iff); - register_control(if_false, _ltree_root, iff); - Node* if_true = new IfTrueNode(iff); - register_control(if_true, loop, iff); - C->add_parse_predicate_opaq(opaq); + ParsePredicateNode* parse_predicate = new ParsePredicateNode(inner_head->in(LoopNode::EntryControl), reason, &_igvn); + register_control(parse_predicate, loop, inner_head->in(LoopNode::EntryControl)); + Node* if_false = new IfFalseNode(parse_predicate); + register_control(if_false, _ltree_root, parse_predicate); + Node* if_true = new IfTrueNode(parse_predicate); + register_control(if_true, loop, parse_predicate); int trap_request = Deoptimization::make_trap_request(reason, Deoptimization::Action_maybe_recompile); address call_addr = SharedRuntime::uncommon_trap_blob()->entry_point(); @@ -1089,7 +1077,7 @@ int PhaseIdealLoop::extract_long_range_checks(const IdealLoopTree* loop, jlong s Node* c = loop->_body.at(i); if (c->is_IfProj() && c->in(0)->is_RangeCheck()) { IfProjNode* if_proj = c->as_IfProj(); - CallStaticJavaNode* call = if_proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* call = if_proj->is_uncommon_trap_if_pattern(); if (call != nullptr) { Node* range = nullptr; Node* offset = nullptr; @@ -4052,78 +4040,107 @@ void PhaseIdealLoop::log_loop_tree() { } } -//---------------------collect_potentially_useful_predicates----------------------- -// Helper function to collect potentially useful predicates to prevent them from -// being eliminated by PhaseIdealLoop::eliminate_useless_predicates -void PhaseIdealLoop::collect_potentially_useful_predicates(IdealLoopTree* loop, Unique_Node_List &useful_predicates) { - if (loop->_child) { // child - collect_potentially_useful_predicates(loop->_child, useful_predicates); +// Eliminate all Parse and Template Assertion Predicates that are not associated with a loop anymore. The eliminated +// predicates will be removed during the next round of IGVN. +void PhaseIdealLoop::eliminate_useless_predicates() { + if (C->parse_predicate_count() == 0 && C->template_assertion_predicate_count() == 0) { + return; // No predicates left. } - // self (only loops that we can apply loop predication may use their predicates) - if (loop->_head->is_Loop() && - !loop->_irreducible && - !loop->tail()->is_top()) { - LoopNode* lpn = loop->_head->as_Loop(); - Node* entry = lpn->in(LoopNode::EntryControl); - const Predicates predicates(entry); - const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block(); - if (loop_limit_check_predicate_block->has_parse_predicate()) { // right pattern that can be used by loop predication - IfProjNode* parse_predicate_proj = loop_limit_check_predicate_block->parse_predicate_success_proj(); - assert(parse_predicate_proj->in(0)->in(1)->in(1)->Opcode() == Op_Opaque1, "must be"); - useful_predicates.push(parse_predicate_proj->in(0)->in(1)->in(1)); // good one - } - if (UseProfiledLoopPredicate) { - const PredicateBlock* profiled_loop_predicate_block = predicates.profiled_loop_predicate_block(); - if (profiled_loop_predicate_block->has_parse_predicate()) { // right pattern that can be used by loop predication - IfProjNode* parse_predicate_proj = profiled_loop_predicate_block->parse_predicate_success_proj(); - useful_predicates.push(parse_predicate_proj->in(0)->in(1)->in(1)); // good one - get_assertion_predicates(parse_predicate_proj, useful_predicates, true); - } - } + eliminate_useless_parse_predicates(); + eliminate_useless_template_assertion_predicates(); +} - if (UseLoopPredicate) { - const PredicateBlock* loop_predicate_block = predicates.loop_predicate_block(); - if (loop_predicate_block->has_parse_predicate()) { // right pattern that can be used by loop predication - IfProjNode* parse_predicate_proj = loop_predicate_block->parse_predicate_success_proj(); - useful_predicates.push(parse_predicate_proj->in(0)->in(1)->in(1)); // good one - get_assertion_predicates(parse_predicate_proj, useful_predicates, true); - } +// Eliminate all Parse Predicates that do not belong to a loop anymore by marking them useless. These will be removed +// during the next round of IGVN. +void PhaseIdealLoop::eliminate_useless_parse_predicates() { + mark_all_parse_predicates_useless(); + if (C->has_loops()) { + mark_loop_associated_parse_predicates_useful(); + } + add_useless_parse_predicates_to_igvn_worklist(); +} + +void PhaseIdealLoop::mark_all_parse_predicates_useless() const { + for (int i = 0; i < C->parse_predicate_count(); i++) { + C->parse_predicate(i)->mark_useless(); + } +} + +void PhaseIdealLoop::mark_loop_associated_parse_predicates_useful() { + for (LoopTreeIterator iterator(_ltree_root); !iterator.done(); iterator.next()) { + IdealLoopTree* loop = iterator.current(); + if (loop->can_apply_loop_predication()) { + mark_useful_parse_predicates_for_loop(loop); } } +} - if (loop->_next) { // sibling - collect_potentially_useful_predicates(loop->_next, useful_predicates); +void PhaseIdealLoop::mark_useful_parse_predicates_for_loop(IdealLoopTree* loop) { + Node* entry = loop->_head->in(LoopNode::EntryControl); + const Predicates predicates(entry); + ParsePredicateIterator iterator(predicates); + while (iterator.has_next()) { + iterator.next()->mark_useful(); } } -//------------------------eliminate_useless_predicates----------------------------- -// Eliminate all inserted predicates if they could not be used by loop predication. -// Note: it will also eliminates loop limits check predicate since it also uses -// Opaque1 node (see Parse::add_predicate()). -void PhaseIdealLoop::eliminate_useless_predicates() { - if (C->parse_predicate_count() == 0 && C->template_assertion_predicate_count() == 0) { - return; // no predicate left +void PhaseIdealLoop::add_useless_parse_predicates_to_igvn_worklist() { + for (int i = 0; i < C->parse_predicate_count(); i++) { + ParsePredicateNode* parse_predicate_node = C->parse_predicate(i); + if (parse_predicate_node->is_useless()) { + _igvn._worklist.push(parse_predicate_node); + } } +} - Unique_Node_List useful_predicates; // to store useful predicates + +// Eliminate all Template Assertion Predicates that do not belong to their originally associated loop anymore by +// replacing the Opaque4 node of the If node with true. These nodes will be removed during the next round of IGVN. +void PhaseIdealLoop::eliminate_useless_template_assertion_predicates() { + Unique_Node_List useful_predicates; if (C->has_loops()) { - collect_potentially_useful_predicates(_ltree_root->_child, useful_predicates); + collect_useful_template_assertion_predicates(useful_predicates); } + eliminate_useless_template_assertion_predicates(useful_predicates); +} - for (int i = C->parse_predicate_count(); i > 0; i--) { - Node* n = C->parse_predicate_opaque1_node(i - 1); - assert(n->Opcode() == Op_Opaque1, "must be"); - if (!useful_predicates.member(n)) { // not in the useful list - _igvn.replace_node(n, n->in(1)); - } +void PhaseIdealLoop::collect_useful_template_assertion_predicates(Unique_Node_List& useful_predicates) { + for (LoopTreeIterator iterator(_ltree_root); !iterator.done(); iterator.next()) { + IdealLoopTree* loop = iterator.current(); + if (loop->can_apply_loop_predication()) { + collect_useful_template_assertion_predicates_for_loop(loop, useful_predicates); + } } +} + +void PhaseIdealLoop::collect_useful_template_assertion_predicates_for_loop(IdealLoopTree* loop, + Unique_Node_List &useful_predicates) { + Node* entry = loop->_head->in(LoopNode::EntryControl); + const Predicates predicates(entry); + if (UseProfiledLoopPredicate) { + const PredicateBlock* profiled_loop_predicate_block = predicates.profiled_loop_predicate_block(); + if (profiled_loop_predicate_block->has_parse_predicate()) { + IfProjNode* parse_predicate_proj = profiled_loop_predicate_block->parse_predicate_success_proj(); + get_assertion_predicates(parse_predicate_proj, useful_predicates, true); + } + } + + if (UseLoopPredicate) { + const PredicateBlock* loop_predicate_block = predicates.loop_predicate_block(); + if (loop_predicate_block->has_parse_predicate()) { + IfProjNode* parse_predicate_proj = loop_predicate_block->parse_predicate_success_proj(); + get_assertion_predicates(parse_predicate_proj, useful_predicates, true); + } + } +} - for (int i = C->template_assertion_predicate_count(); i > 0; i--) { - Node* n = C->template_assertion_predicate_opaq_node(i - 1); - assert(n->Opcode() == Op_Opaque4, "must be"); - if (!useful_predicates.member(n)) { // not in the useful list - _igvn.replace_node(n, n->in(2)); +void PhaseIdealLoop::eliminate_useless_template_assertion_predicates(Unique_Node_List& useful_predicates) { + for (int i = 0; i < C->template_assertion_predicate_count(); i++) { + Node* opaque4 = C->template_assertion_predicate_opaq_node(i); + assert(opaque4->Opcode() == Op_Opaque4, "must be"); + if (!useful_predicates.member(opaque4)) { // not in the useful list + _igvn.replace_node(opaque4, opaque4->in(2)); } } } @@ -4561,7 +4578,7 @@ void PhaseIdealLoop::build_and_optimize() { } // Perform loop predication before iteration splitting - if (C->has_loops() && !C->major_progress() && (C->parse_predicate_count() > 0)) { + if (UseLoopPredicate && C->has_loops() && !C->major_progress() && (C->parse_predicate_count() > 0)) { _ltree_root->_child->loop_predication(this); } @@ -4614,7 +4631,8 @@ void PhaseIdealLoop::build_and_optimize() { // until no more loop optimizations could be done. // After that switch predicates off and do more loop optimizations. if (!C->major_progress() && (C->parse_predicate_count() > 0)) { - C->cleanup_parse_predicates(_igvn); + C->mark_parse_predicate_nodes_useless(_igvn); + assert(C->parse_predicate_count() == 0, "should be zero now"); if (TraceLoopOpts) { tty->print_cr("PredicatesOff"); } @@ -6096,7 +6114,7 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) { if (!new_ctrl->is_Proj()) { break; } - CallStaticJavaNode* call = new_ctrl->as_Proj()->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* call = new_ctrl->as_Proj()->is_uncommon_trap_if_pattern(); if (call == nullptr) { break; } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index b238de71a95..bb12e7b97d4 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -646,6 +646,7 @@ class IdealLoopTree : public ResourceObj { // Perform optimization to use the loop predicates for null checks and range checks. // Applies to any loop level (not just the innermost one) bool loop_predication( PhaseIdealLoop *phase); + bool can_apply_loop_predication(); // Perform iteration-splitting on inner loops. Split iterations to // avoid range checks or one-shot null checks. Returns false if the @@ -1330,8 +1331,9 @@ class PhaseIdealLoop : public PhaseTransform { bool* p_short_scale, int depth); // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted - IfProjNode* create_new_if_for_predicate(IfProjNode* cont_proj, Node* new_entry, Deoptimization::DeoptReason reason, - int opcode, bool rewire_uncommon_proj_phi_inputs = false); + IfProjNode* create_new_if_for_predicate(ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, + Deoptimization::DeoptReason reason, int opcode, + bool rewire_uncommon_proj_phi_inputs = false); private: // Helper functions for create_new_if_for_predicate() @@ -1362,15 +1364,27 @@ class PhaseIdealLoop : public PhaseTransform { void loop_predication_follow_branches(Node *c, IdealLoopTree *loop, float loop_trip_cnt, PathFrequency& pf, Node_Stack& stack, VectorSet& seen, Node_List& if_proj_list); - IfProjNode* add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj, IfProjNode* predicate_proj, + IfProjNode* add_template_assertion_predicate(IfNode* iff, IdealLoopTree* loop, IfProjNode* if_proj, + ParsePredicateSuccessProj* parse_predicate_proj, IfProjNode* upper_bound_proj, int scale, Node* offset, Node* init, Node* limit, jint stride, Node* rng, bool& overflow, Deoptimization::DeoptReason reason); Node* add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, Node* predicate_proj, int scale_con, Node* offset, Node* limit, jint stride_con, Node* value); // Helper function to collect predicate for eliminating the useless ones - void collect_potentially_useful_predicates(IdealLoopTree *loop, Unique_Node_List &predicate_opaque1); void eliminate_useless_predicates(); + + void eliminate_useless_parse_predicates(); + void mark_all_parse_predicates_useless() const; + void mark_loop_associated_parse_predicates_useful(); + static void mark_useful_parse_predicates_for_loop(IdealLoopTree* loop); + void add_useless_parse_predicates_to_igvn_worklist(); + + void eliminate_useless_template_assertion_predicates(); + void collect_useful_template_assertion_predicates(Unique_Node_List& useful_predicates); + static void collect_useful_template_assertion_predicates_for_loop(IdealLoopTree* loop, Unique_Node_List& useful_predicates); + void eliminate_useless_template_assertion_predicates(Unique_Node_List& useful_predicates); + void eliminate_useless_zero_trip_guard(); bool has_control_dependencies_from_predicates(LoopNode* head) const; @@ -1621,14 +1635,15 @@ class PhaseIdealLoop : public PhaseTransform { IfProjNode*& ifslow_pred); void clone_parse_predicate_to_unswitched_loops(const PredicateBlock* predicate_block, Deoptimization::DeoptReason reason, IfProjNode*& iffast_pred, IfProjNode*& ifslow_pred); - IfProjNode* clone_parse_predicate_to_unswitched_loop(ParsePredicateSuccessProj* predicate_proj, Node* new_entry, + IfProjNode* clone_parse_predicate_to_unswitched_loop(ParsePredicateSuccessProj* parse_predicate_proj, Node* new_entry, Deoptimization::DeoptReason reason, bool slow_loop); void clone_assertion_predicates_to_unswitched_loop(IdealLoopTree* loop, const Node_List& old_new, Deoptimization::DeoptReason reason, IfProjNode* old_predicate_proj, - IfProjNode* iffast_pred, IfProjNode* ifslow_pred); + ParsePredicateSuccessProj* fast_loop_parse_predicate_proj, + ParsePredicateSuccessProj* slow_loop_parse_predicate_proj); IfProjNode* clone_assertion_predicate_for_unswitched_loops(Node* iff, IfProjNode* predicate, Deoptimization::DeoptReason reason, - IfProjNode* output_proj); + ParsePredicateSuccessProj* parse_predicate_proj); static void check_cloned_parse_predicate_for_unswitching(const Node* new_entry, bool is_fast_loop) PRODUCT_RETURN; bool _created_loop_node; diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 80a90d7933d..a899f0b370f 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -2068,7 +2068,7 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, // make sure the Bool/Cmp input is cloned down to avoid a Phi between // the AllocateArray node and its ValidLengthTest input that could cause // split if to break. - if (use->is_If() || use->is_CMove() || C->is_predicate_opaq(use) || use->Opcode() == Op_Opaque4 || + if (use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque4 || (use->Opcode() == Op_AllocateArray && use->in(AllocateNode::ValidLengthTest) == old)) { // Since this code is highly unlikely, we lazily build the worklist // of such Nodes to go split. diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 6b950f33e71..37d3f756bf7 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -537,7 +537,7 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, Node *sfpt_ctl, BasicType } else if (mem->is_ArrayCopy()) { Node* ctl = mem->in(0); Node* m = mem->in(TypeFunc::Memory); - if (sfpt_ctl->is_Proj() && sfpt_ctl->as_Proj()->is_uncommon_trap_proj(Deoptimization::Reason_none)) { + if (sfpt_ctl->is_Proj() && sfpt_ctl->as_Proj()->is_uncommon_trap_proj()) { // pin the loads in the uncommon trap path ctl = sfpt_ctl; m = sfpt_mem; diff --git a/src/hotspot/share/opto/multnode.cpp b/src/hotspot/share/opto/multnode.cpp index 814f20ca224..904c9470b6d 100644 --- a/src/hotspot/share/opto/multnode.cpp +++ b/src/hotspot/share/opto/multnode.cpp @@ -184,9 +184,9 @@ uint ProjNode::ideal_reg() const { //-------------------------------is_uncommon_trap_proj---------------------------- // Return uncommon trap call node if proj is for "proj->[region->..]call_uct" // null otherwise -CallStaticJavaNode* ProjNode::is_uncommon_trap_proj(Deoptimization::DeoptReason reason) { - int path_limit = 10; - Node* out = this; +CallStaticJavaNode* ProjNode::is_uncommon_trap_proj(Deoptimization::DeoptReason reason) const { + const int path_limit = 10; + const Node* out = this; for (int ct = 0; ct < path_limit; ct++) { out = out->unique_ctrl_out_or_null(); if (out == nullptr) @@ -213,31 +213,14 @@ CallStaticJavaNode* ProjNode::is_uncommon_trap_proj(Deoptimization::DeoptReason // | // V // other_proj->[region->..]call_uct" -// null otherwise -// "must_reason_predicate" means the uct reason must be Reason_predicate -CallStaticJavaNode* ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) { - Node *in0 = in(0); - if (!in0->is_If()) return nullptr; - // Variation of a dead If node. - if (in0->outcnt() < 2) return nullptr; - IfNode* iff = in0->as_If(); - - // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate - if (reason != Deoptimization::Reason_none) { - if (iff->in(1)->Opcode() != Op_Conv2B || - iff->in(1)->in(1)->Opcode() != Op_Opaque1) { - return nullptr; - } +// or null otherwise. +CallStaticJavaNode* ProjNode::is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason) const { + Node* iff = in(0); + if (!iff->is_If() || iff->outcnt() < 2) { + // Not a projection of an If or variation of a dead If node. + return nullptr; } - - ProjNode* other_proj = iff->proj_out(1-_con); - CallStaticJavaNode* call = other_proj->is_uncommon_trap_proj(reason); - if (call != nullptr) { - assert(reason == Deoptimization::Reason_none || - Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list"); - return call; - } - return nullptr; + return other_if_proj()->is_uncommon_trap_proj(reason); } ProjNode* ProjNode::other_if_proj() const { diff --git a/src/hotspot/share/opto/multnode.hpp b/src/hotspot/share/opto/multnode.hpp index 09552508aa3..25dad70a50a 100644 --- a/src/hotspot/share/opto/multnode.hpp +++ b/src/hotspot/share/opto/multnode.hpp @@ -93,13 +93,13 @@ class ProjNode : public Node { // Return uncommon trap call node if proj is for "proj->[region->..]call_uct" // null otherwise - CallStaticJavaNode* is_uncommon_trap_proj(Deoptimization::DeoptReason reason); + CallStaticJavaNode* is_uncommon_trap_proj(Deoptimization::DeoptReason reason = Deoptimization::Reason_none) const; // Return uncommon trap call node for "if(test)-> proj -> ... // | // V // other_proj->[region->..]call_uct" // null otherwise - CallStaticJavaNode* is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason); + CallStaticJavaNode* is_uncommon_trap_if_pattern(Deoptimization::DeoptReason reason = Deoptimization::Reason_none) const; // Return other proj node when this is a If proj node ProjNode* other_if_proj() const; diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 527b0ba8938..44c37768cdc 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -508,6 +508,10 @@ Node *Node::clone() const { // If it is applicable, it will happen anyway when the cloned node is registered with IGVN. n->remove_flag(Node::NodeFlags::Flag_for_post_loop_opts_igvn); } + if (n->is_ParsePredicate()) { + C->add_parse_predicate(n->as_ParsePredicate()); + } + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); bs->register_potential_barrier_node(n); @@ -609,6 +613,9 @@ void Node::destruct(PhaseValues* phase) { if (Opcode() == Op_Opaque4) { compile->remove_template_assertion_predicate_opaq(this); } + if (is_ParsePredicate()) { + compile->remove_parse_predicate(as_ParsePredicate()); + } if (for_post_loop_opts_igvn()) { compile->remove_from_post_loop_opts_igvn(this); } diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 45ec2f3faa0..63e627070a1 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -69,7 +69,7 @@ ParsePredicateNode* ParsePredicate::init_parse_predicate(Node* parse_predicate_p } Deoptimization::DeoptReason RuntimePredicate::uncommon_trap_reason(IfProjNode* if_proj) { - CallStaticJavaNode* uct_call = if_proj->is_uncommon_trap_if_pattern(Deoptimization::Reason_none); + CallStaticJavaNode* uct_call = if_proj->is_uncommon_trap_if_pattern(); if (uct_call == nullptr) { return Deoptimization::Reason_none; } @@ -84,6 +84,30 @@ bool RuntimePredicate::is_success_proj(Node* node, Deoptimization::DeoptReason d } } +ParsePredicateIterator::ParsePredicateIterator(const Predicates& predicates) : _current_index(0) { + const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block(); + if (loop_limit_check_predicate_block->has_parse_predicate()) { + _parse_predicates.push(loop_limit_check_predicate_block->parse_predicate()); + } + if (UseProfiledLoopPredicate) { + const PredicateBlock* profiled_loop_predicate_block = predicates.profiled_loop_predicate_block(); + if (profiled_loop_predicate_block->has_parse_predicate()) { + _parse_predicates.push(profiled_loop_predicate_block->parse_predicate()); + } + } + if (UseLoopPredicate) { + const PredicateBlock* loop_predicate_block = predicates.loop_predicate_block(); + if (loop_predicate_block->has_parse_predicate()) { + _parse_predicates.push(loop_predicate_block->parse_predicate()); + } + } +} + +ParsePredicateNode* ParsePredicateIterator::next() { + assert(has_next(), "always check has_next() first"); + return _parse_predicates.at(_current_index++); +} + // Walk over all Regular Predicates of this block (if any) and return the first node not belonging to the block // anymore (i.e. entry to the first Regular Predicate in this block if any or `regular_predicate_proj` otherwise). Node* PredicateBlock::skip_regular_predicates(Node* regular_predicate_proj, Deoptimization::DeoptReason deopt_reason) { diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index 0652cea2992..0f5c8fe3264 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -355,4 +355,19 @@ class Predicates : public StackObj { return _entry != _loop_entry; } }; + +// This class iterates over the Parse Predicates of a loop. +class ParsePredicateIterator : public StackObj { + GrowableArray _parse_predicates; + int _current_index; + + public: + ParsePredicateIterator(const Predicates& predicates); + + bool has_next() const { + return _current_index < _parse_predicates.length(); + } + + ParsePredicateNode* next(); +}; #endif // SHARE_OPTO_PREDICATES_HPP From ed2b4673de6893047407c61f82b5e68741459876 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 5 Sep 2023 12:48:03 +0000 Subject: [PATCH 69/86] 8315499: build using devkit on Linux ppc64le RHEL puts path to devkit into libsplashscreen Reviewed-by: erikj --- make/autoconf/lib-x11.m4 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/make/autoconf/lib-x11.m4 b/make/autoconf/lib-x11.m4 index 97a3f24a2db..b1902a432a1 100644 --- a/make/autoconf/lib-x11.m4 +++ b/make/autoconf/lib-x11.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], X_CFLAGS= X_LIBS= else + x_libraries_orig="$x_libraries" if test "x${with_x}" = xno; then AC_MSG_ERROR([It is not possible to disable the use of X11. Remove the --without-x option.]) @@ -48,6 +49,7 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], fi if test "x$x_libraries" = xNONE; then x_libraries="${with_x}/lib" + x_libraries_orig="$x_libraries" fi else # Check if the user has specified sysroot, but not --with-x, --x-includes or --x-libraries. @@ -82,8 +84,8 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], AC_PATH_XTRA # AC_PATH_XTRA creates X_LIBS and sometimes adds -R flags. When cross compiling - # this doesn't make sense so we remove it. - if test "x$COMPILE_TYPE" = xcross; then + # this doesn't make sense so we remove it; same for sysroot (devkit). + if test "x$COMPILE_TYPE" = xcross || (test "x$SYSROOT" != "x" && test "x$x_libraries_orig" = xNONE); then X_LIBS=`$ECHO $X_LIBS | $SED 's/-R \{0,1\}[[^ ]]*//g'` fi From cef9fff0675c85906e134e4c0a8d2036860cd4b3 Mon Sep 17 00:00:00 2001 From: Wojciech Kudla Date: Tue, 5 Sep 2023 14:12:45 +0000 Subject: [PATCH 70/86] 8305507: Add support for grace period before AbortVMOnSafepointTimeout triggers Reviewed-by: dholmes, pchilanomate --- src/hotspot/share/runtime/globals.hpp | 4 ++ src/hotspot/share/runtime/safepoint.cpp | 2 +- .../TestAbortVMOnSafepointTimeout.java | 55 ++++++++++++++++++- 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 725ded4bd7a..4c2d19469ff 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -430,6 +430,10 @@ const int ObjectAlignmentInBytes = 8; product(bool, AbortVMOnSafepointTimeout, false, DIAGNOSTIC, \ "Abort upon failure to reach safepoint (see SafepointTimeout)") \ \ + product(uint64_t, AbortVMOnSafepointTimeoutDelay, 0, DIAGNOSTIC, \ + "Delay in milliseconds for option AbortVMOnSafepointTimeout") \ + range(0, max_jlong) \ + \ product(bool, AbortVMOnVMOperationTimeout, false, DIAGNOSTIC, \ "Abort upon failure to complete VM operation promptly") \ \ diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index c826119910b..266e6b54aca 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -808,7 +808,7 @@ void SafepointSynchronize::print_safepoint_timeout() { // To debug the long safepoint, specify both AbortVMOnSafepointTimeout & // ShowMessageBoxOnError. - if (AbortVMOnSafepointTimeout) { + if (AbortVMOnSafepointTimeout && (os::elapsedTime() * MILLIUNITS > AbortVMOnSafepointTimeoutDelay)) { // Send the blocking thread a signal to terminate and write an error file. for (JavaThreadIteratorWithHandle jtiwh; JavaThread *cur_thread = jtiwh.next(); ) { if (cur_thread->safepoint_state()->is_running()) { diff --git a/test/hotspot/jtreg/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java b/test/hotspot/jtreg/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java index e7e3cfca781..aadb61fd5b0 100644 --- a/test/hotspot/jtreg/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java +++ b/test/hotspot/jtreg/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java @@ -28,7 +28,8 @@ /* * @test TestAbortVMOnSafepointTimeout - * @summary Check if VM can kill thread which doesn't reach safepoint. + * @summary Check if VM can kill thread which doesn't reach safepoint, + * test grace period before AbortVMOnSafepointTimeout kicks in * @bug 8219584 8227528 * @requires vm.flagless * @library /testlibrary /test/lib @@ -39,7 +40,7 @@ public class TestAbortVMOnSafepointTimeout { - public static void main(String[] args) throws Exception { + public static void testThreadKilledOnSafepointTimeout() throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-Xbootclasspath/a:.", "-XX:+UnlockDiagnosticVMOptions", @@ -56,6 +57,31 @@ public static void main(String[] args) throws Exception { ); OutputAnalyzer output = new OutputAnalyzer(pb.start()); + verifyAbortVmApplied(output); + } + + public static void testGracePeriodAppliedBeforeVmAbort() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:+SafepointTimeout", + "-XX:+SafepointALot", + "-XX:+AbortVMOnSafepointTimeout", + "-XX:AbortVMOnSafepointTimeoutDelay=2500", + "-XX:SafepointTimeoutDelay=50", + "-XX:GuaranteedSafepointInterval=1", + "-XX:-CreateCoredumpOnCrash", + "-Xms64m", + "TestAbortVMOnSafepointTimeout$TestWithDelay" + ); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain(TestWithDelay.PRE_STALL_TEXT); + verifyAbortVmApplied(output); + } + + private static void verifyAbortVmApplied(OutputAnalyzer output) { output.shouldContain("Timed out while spinning to reach a safepoint."); if (Platform.isWindows()) { output.shouldContain("Safepoint sync time longer than"); @@ -68,6 +94,14 @@ public static void main(String[] args) throws Exception { output.shouldNotHaveExitValue(0); } + public static void main(String[] args) throws Exception { + // test basic AbortVMOnSafepointTimeout functionality + testThreadKilledOnSafepointTimeout(); + + // verify -XX:AbortVMOnSafepointTimeoutDelay functionality + testGracePeriodAppliedBeforeVmAbort(); + } + public static class Test { public static void main(String[] args) throws Exception { Integer waitTime = Integer.parseInt(args[0]); @@ -78,4 +112,21 @@ public static void main(String[] args) throws Exception { } } } + + public static class TestWithDelay { + + public static final String PRE_STALL_TEXT = "THE FOLLOWING STALL SHOULD BE CAPTURED"; + + public static void main(String[] args) throws Exception { + WhiteBox wb = WhiteBox.getWhiteBox(); + // induce a stall that should not be picked up before grace period + wb.waitUnsafe(999); + System.out.println(PRE_STALL_TEXT); + + // trigger safepoint timeout + while (true) { + wb.waitUnsafe(999); + } + } + } } From 969fcdb0de962b6eda7b362af010cb138e45afcf Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Tue, 5 Sep 2023 16:15:54 +0000 Subject: [PATCH 71/86] 8314191: C2 compilation fails with "bad AD file" Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/subnode.cpp | 4 ++ .../c2/MinValueStrideCountedLoop.java | 47 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/c2/MinValueStrideCountedLoop.java diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 1dcc8b045c2..c317759585a 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -1556,12 +1556,14 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) { // and "cmp (add X min_jint) c" into "cmpu X (c + min_jint)" if (cop == Op_CmpI && cmp1_op == Op_AddI && + !is_cloop_increment(cmp1) && phase->type(cmp1->in(2)) == TypeInt::MIN) { if (cmp2_op == Op_ConI) { Node* ncmp2 = phase->intcon(java_add(cmp2->get_int(), min_jint)); Node* ncmp = phase->transform(new CmpUNode(cmp1->in(1), ncmp2)); return new BoolNode(ncmp, _test._test); } else if (cmp2_op == Op_AddI && + !is_cloop_increment(cmp2) && phase->type(cmp2->in(2)) == TypeInt::MIN) { Node* ncmp = phase->transform(new CmpUNode(cmp1->in(1), cmp2->in(1))); return new BoolNode(ncmp, _test._test); @@ -1572,12 +1574,14 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) { // and "cmp (add X min_jlong) c" into "cmpu X (c + min_jlong)" if (cop == Op_CmpL && cmp1_op == Op_AddL && + !is_cloop_increment(cmp1) && phase->type(cmp1->in(2)) == TypeLong::MIN) { if (cmp2_op == Op_ConL) { Node* ncmp2 = phase->longcon(java_add(cmp2->get_long(), min_jlong)); Node* ncmp = phase->transform(new CmpULNode(cmp1->in(1), ncmp2)); return new BoolNode(ncmp, _test._test); } else if (cmp2_op == Op_AddL && + !is_cloop_increment(cmp2) && phase->type(cmp2->in(2)) == TypeLong::MIN) { Node* ncmp = phase->transform(new CmpULNode(cmp1->in(1), cmp2->in(1))); return new BoolNode(ncmp, _test._test); diff --git a/test/hotspot/jtreg/compiler/c2/MinValueStrideCountedLoop.java b/test/hotspot/jtreg/compiler/c2/MinValueStrideCountedLoop.java new file mode 100644 index 00000000000..7870e0ade6c --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/MinValueStrideCountedLoop.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package compiler.c2; + +/* + * @test + * @bug 8314191 + * @summary Loop increment should not be transformed into unsigned comparison + * + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,*MinValueStrideCountedLoop::test* + * compiler.c2.MinValueStrideCountedLoop + */ +public class MinValueStrideCountedLoop { + static int limit = 0; + static int res = 0; + + static void test() { + for (int i = 0; i >= limit + -2147483647; i += -2147483648) { + res += 42; + } + } + + public static void main(String[] args) { + test(); + } +} From ebe3127734ccb0f7cb8428ed4d61a794050eaf50 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Tue, 5 Sep 2023 17:48:43 +0000 Subject: [PATCH 72/86] 8315717: ProblemList serviceability/sa/TestHeapDumpForInvokeDynamic.java with ZGC Reviewed-by: thartmann, azvegint, kevinw --- test/hotspot/jtreg/ProblemList-zgc.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index d9863b4690b..89882754d8e 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -41,6 +41,8 @@ serviceability/sa/ClhsdbPstack.java#core 8248912 generic- serviceability/sa/TestSysProps.java 8302055 generic-all +serviceability/sa/TestHeapDumpForInvokeDynamic.java 8315646 generic-all + vmTestbase/gc/gctests/MemoryEaterMT/MemoryEaterMT.java 8289582 windows-x64 vmTestbase/nsk/monitoring/MemoryPoolMBean/isCollectionUsageThresholdExceeded/isexceeded002/TestDescription.java 8298302 generic-all From 939d7c5d8466f9e392beae2947a494ac28695cc1 Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Tue, 5 Sep 2023 17:51:12 +0000 Subject: [PATCH 73/86] 8161536: sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java fails with ProviderException Reviewed-by: mullan --- test/jdk/ProblemList.txt | 2 -- test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 5bf9284e3bb..7cca203bc30 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -582,8 +582,6 @@ com/sun/nio/sctp/SctpChannel/SocketOptionTests.java 8141694 linux-al # jdk_security -sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8161536 generic-all - sun/security/smartcardio/TestChannel.java 8039280 generic-all sun/security/smartcardio/TestConnect.java 8039280 generic-all sun/security/smartcardio/TestConnectAgain.java 8039280 generic-all diff --git a/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java b/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java index 43efcd5afbb..08b29fe6df1 100644 --- a/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java +++ b/test/jdk/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1" * ClientJSSEServerJSSE * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1" - * ClientJSSEServerJSSE sm policy + * -Djava.security.manager=allow ClientJSSEServerJSSE sm policy */ import java.security.Provider; From 1f4cdb327f46085d3134d1d1164fccac35904566 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 5 Sep 2023 20:56:09 +0000 Subject: [PATCH 74/86] 8315127: CDSMapTest fails with incorrect number of oop references Reviewed-by: ccheung --- .../jtreg/runtime/cds/CDSMapReader.java | 79 ++++++++++++++----- .../hotspot/jtreg/runtime/cds/CDSMapTest.java | 9 +-- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/CDSMapReader.java b/test/hotspot/jtreg/runtime/cds/CDSMapReader.java index 8ad53dc6596..78ba7f16735 100644 --- a/test/hotspot/jtreg/runtime/cds/CDSMapReader.java +++ b/test/hotspot/jtreg/runtime/cds/CDSMapReader.java @@ -24,26 +24,47 @@ import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; -import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; -// This is a simple parser for parsing the output of -// -// java -Xshare:dump -Xlog:cds+map=debug,cds+map+oops=trace:file=cds.map:none:filesize=0 -// -// Currently it just check the output related to JDK-8308903. -// I.e., each oop fields in the HeapObjects must point to a valid HeapObject. -// -// It can be extended to check for the other parts of the map file, or perform -// more analysis on the HeapObjects. +/* + +This is a simple parser for parsing the output of + + java -Xshare:dump -Xlog:cds+map=debug,cds+map+oops=trace:file=cds.map:none:filesize=0 + +The map file contains patterns like this for the heap objects: + +====================================================================== +0x00000000ffe00000: @@ Object (0xffe00000) java.lang.String + - klass: 'java/lang/String' 0x0000000800010220 + - fields (3 words): + - private 'hash' 'I' @12 0 (0x00000000) + - private final 'coder' 'B' @16 0 (0x00) + - private 'hashIsZero' 'Z' @17 true (0x01) + - injected 'flags' 'B' @18 1 (0x01) + - private final 'value' '[B' @20 0x00000000ffe00018 (0xffe00018) [B length: 0 +0x00000000ffe00018: @@ Object (0xffe00018) [B length: 0 + - klass: {type array byte} 0x00000008000024d8 +====================================================================== + +Currently this parser just check the output related to JDK-8308903. +I.e., each oop field must point to a valid HeapObject. For example, the 'value' field +in the String must point to a valid byte array. + +This parser can be extended to check for the other parts of the map file, or perform +more analysis on the HeapObjects. + +*/ + public class CDSMapReader { public static class MapFile { ArrayList heapObjects = new ArrayList<>(); HashMap oopToObject = new HashMap<>(); HashMap narrowOopToObject = new HashMap<>(); + public int stringCount = 0; void add(HeapObject heapObject) { heapObjects.add(heapObject); @@ -51,6 +72,9 @@ void add(HeapObject heapObject) { if (heapObject.address.narrowOop != 0) { narrowOopToObject.put(heapObject.address.narrowOop, heapObject); } + if (heapObject.className.equals("java.lang.String")) { + stringCount ++; + } } public int heapObjectCount() { @@ -184,7 +208,6 @@ private static HeapObject parseHeapObjectImpl(String className, String oop, Stri if ((m = match(line, fieldsWordsPattern)) == null) { throw new RuntimeException("Expected field size info"); } - // TODO: read all the array elements while (true) { nextLine(); if (line == null || !line.startsWith(" - ")) { @@ -233,6 +256,7 @@ static String nextLine() throws IOException { public static MapFile read(String fileName) { mapFile = new MapFile(); + lineCount = 0; try (BufferedReader r = new BufferedReader(new FileReader(fileName))) { reader = r; @@ -254,7 +278,8 @@ public static MapFile read(String fileName) { throw new RuntimeException(t); } finally { System.out.println("Parsed " + lineCount + " lines in " + fileName); - System.out.println("Found " + mapFile.heapObjectCount() + " heap objects"); + System.out.println("Found " + mapFile.heapObjectCount() + " heap objects (" + + mapFile.stringCount + " strings)"); mapFile = null; reader = null; line = null; @@ -270,8 +295,9 @@ private static void mustContain(HashMap allObjects, Field fiel } // Check that each oop fields in the HeapObjects must point to a valid HeapObject. - public static int validate(MapFile mapFile) { - int count = 0; + public static void validate(MapFile mapFile) { + int count1 = 0; + int count2 = 0; for (HeapObject heapObject : mapFile.heapObjects) { if (heapObject.fields != null) { for (Field field : heapObject.fields) { @@ -281,17 +307,32 @@ public static int validate(MapFile mapFile) { // Is this test actually doing something? // To see how an invalidate pointer may be found, change oop in the // following line to oop+1 - mustContain(mapFile.oopToObject, field, oop, false); - count ++; + if (oop != 0) { + mustContain(mapFile.oopToObject, field, oop, false); + count1 ++; + } if (narrowOop != 0) { mustContain(mapFile.narrowOopToObject, field, narrowOop, true); - count ++; + count2 ++; } } } } - System.out.println("Checked " + count + " oop field references"); - return count; + System.out.println("Found " + count1 + " non-null oop field references (normal)"); + System.out.println("Found " + count2 + " non-null oop field references (narrow)"); + + if (mapFile.heapObjectCount() > 0) { + // heapObjectCount() may be zero if the selected GC doesn't support heap object archiving. + if (mapFile.stringCount <= 0) { + throw new RuntimeException("CDS map file should contain at least one string"); + } + if (count1 < mapFile.stringCount) { + throw new RuntimeException("CDS map file seems incorrect: " + mapFile.heapObjectCount() + + " objects (" + mapFile.stringCount + " strings). Each string should" + + " have one non-null oop field but we found only " + count1 + + " non-null oop field references"); + } + } } public static void main(String args[]) { diff --git a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java index c2a53cac42d..fbc98fef1d6 100644 --- a/test/hotspot/jtreg/runtime/cds/CDSMapTest.java +++ b/test/hotspot/jtreg/runtime/cds/CDSMapTest.java @@ -33,8 +33,6 @@ import jdk.test.lib.cds.CDSOptions; import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.Platform; -import java.io.FileInputStream; -import java.io.IOException; import java.util.ArrayList; public class CDSMapTest { @@ -76,11 +74,6 @@ static void dump(ArrayList args, String... more) throws Exception { CDSTestUtils.createArchiveAndCheck(opts); CDSMapReader.MapFile mapFile = CDSMapReader.read(mapName); - int oopFieldCount = CDSMapReader.validate(mapFile); - if (mapFile.heapObjectCount() > 0 && oopFieldCount < 10000) { - // heapObjectCount() may be zero if the selected GC doesn't support heap object archiving. - throw new RuntimeException("CDS map file seems incorrect: " + mapFile.heapObjectCount() + - " objects but only " + oopFieldCount + " oop field references"); - } + CDSMapReader.validate(mapFile); } } From aba89f20bfce4de5ef034fed30b3b461fc715ba5 Mon Sep 17 00:00:00 2001 From: Tobias Hotz Date: Tue, 5 Sep 2023 22:08:20 +0000 Subject: [PATCH 75/86] 8312213: Remove unnecessary TEST instructions on x86 when flags reg will already be set Reviewed-by: jvernee, dlong --- src/hotspot/cpu/x86/peephole_x86_64.cpp | 104 ++++++++++ src/hotspot/cpu/x86/peephole_x86_64.hpp | 2 + src/hotspot/cpu/x86/x86.ad | 14 +- src/hotspot/cpu/x86/x86_64.ad | 95 ++++++++- src/hotspot/share/adlc/adlparse.cpp | 41 ++++ src/hotspot/share/adlc/adlparse.hpp | 2 + src/hotspot/share/adlc/forms.hpp | 2 + src/hotspot/share/adlc/formsopt.hpp | 1 + src/hotspot/share/adlc/formssel.cpp | 30 +++ src/hotspot/share/adlc/formssel.hpp | 22 ++ src/hotspot/share/adlc/output_c.cpp | 28 ++- .../c2/irTests/TestTestRemovalPeephole.java | 183 +++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 10 + .../vm/compiler/x86/TestRemovalPeephole.java | 193 ++++++++++++++++++ 14 files changed, 720 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/TestTestRemovalPeephole.java create mode 100644 test/micro/org/openjdk/bench/vm/compiler/x86/TestRemovalPeephole.java diff --git a/src/hotspot/cpu/x86/peephole_x86_64.cpp b/src/hotspot/cpu/x86/peephole_x86_64.cpp index ab58c566ea4..8c956aeb053 100644 --- a/src/hotspot/cpu/x86/peephole_x86_64.cpp +++ b/src/hotspot/cpu/x86/peephole_x86_64.cpp @@ -26,6 +26,7 @@ #ifdef COMPILER2 #include "peephole_x86_64.hpp" +#include "adfiles/ad_x86.hpp" // This function transforms the shapes // mov d, s1; add d, s2 into @@ -132,6 +133,109 @@ bool lea_coalesce_helper(Block* block, int block_index, PhaseCFG* cfg_, PhaseReg return true; } +// This helper func takes a condition and returns the flags that need to be set for the condition +// It uses the same flags as the test instruction, so if the e.g. the overflow bit is required, +// this func returns clears_overflow, as that is what the test instruction does and what the downstream path expects +juint map_condition_to_required_test_flags(Assembler::Condition condition) { + switch (condition) { + case Assembler::Condition::zero: // Same value as equal + case Assembler::Condition::notZero: // Same value as notEqual + return Node::PD::Flag_sets_zero_flag; + case Assembler::Condition::less: + case Assembler::Condition::greaterEqual: + return Node::PD::Flag_sets_sign_flag | Node::PD::Flag_clears_overflow_flag; + case Assembler::Condition::lessEqual: + case Assembler::Condition::greater: + return Node::PD::Flag_sets_sign_flag | Node::PD::Flag_clears_overflow_flag | Node::PD::Flag_sets_zero_flag; + case Assembler::Condition::below: // Same value as carrySet + case Assembler::Condition::aboveEqual: // Same value as carryClear + return Node::PD::Flag_clears_carry_flag; + case Assembler::Condition::belowEqual: + case Assembler::Condition::above: + return Node::PD::Flag_clears_carry_flag | Node::PD::Flag_sets_zero_flag; + case Assembler::Condition::overflow: + case Assembler::Condition::noOverflow: + return Node::PD::Flag_clears_overflow_flag; + case Assembler::Condition::negative: + case Assembler::Condition::positive: + return Node::PD::Flag_sets_sign_flag; + case Assembler::Condition::parity: + case Assembler::Condition::noParity: + return Node::PD::Flag_sets_parity_flag; + default: + ShouldNotReachHere(); + return 0; + } +} + + +// This function removes the TEST instruction when it detected shapes likes AND r1, r2; TEST r1, r1 +// It checks the required EFLAGS for the downstream instructions of the TEST +// and removes the TEST if the preceding instructions already sets all these flags +bool Peephole::test_may_remove(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, + MachNode* (*new_root)(), uint inst0_rule) { + MachNode* test_to_check = block->get_node(block_index)->as_Mach(); + assert(test_to_check->rule() == inst0_rule, "sanity"); + + Node* inst1 = test_to_check->in(1); + // Only remove test if the block order is inst1 -> MachProjNode (because the node to match must specify KILL cr) -> test_to_check + // So inst1 must be at index - 2 + if (block_index < 2 || block->get_node(block_index - 2) != inst1) { + return false; + } + if (inst1 != nullptr) { + MachNode* prevNode = inst1->isa_Mach(); + if (prevNode != nullptr) { + // Includes other flags as well, but that doesn't matter here + juint all_node_flags = prevNode->flags(); + if (all_node_flags == 0) { + // We can return early - there is no way the test can be removed, the preceding node does not set any flags + return false; + } + juint required_flags = 0; + // Search for the uses of the node and compute which flags are required + for (DUIterator_Fast imax, i = test_to_check->fast_outs(imax); i < imax; i++) { + MachNode* node_out = test_to_check->fast_out(i)->isa_Mach(); + bool found_correct_oper = false; + for (uint16_t j = 0; j < node_out->_num_opnds; ++j) { + MachOper* operand = node_out->_opnds[j]; + if (operand->opcode() == cmpOp_rule || operand->opcode() == cmpOpU_rule) { + auto condition = static_cast(operand->ccode()); + juint flags_for_inst = map_condition_to_required_test_flags(condition); + required_flags = required_flags | flags_for_inst; + found_correct_oper = true; + break; + } + } + if (!found_correct_oper) { + // We could not find one the required flags for one of the dependencies. Keep the test as it might set flags needed for that node + return false; + } + } + assert(required_flags != 0, "No flags required, should be impossible!"); + bool sets_all_required_flags = (required_flags & ~all_node_flags) == 0; + if (sets_all_required_flags) { + // All flags are covered are clear to remove this test + MachProjNode* machProjNode = block->get_node(block_index - 1)->isa_MachProj(); + assert(machProjNode != nullptr, "Expected a MachProj node here!"); + assert(ra_->get_reg_first(machProjNode) == ra_->get_reg_first(test_to_check), "Test must operate on the same register as its replacement"); + + // Remove the original test node and replace it with the pseudo test node. The AND node already sets ZF + test_to_check->replace_by(machProjNode); + + // Modify the block + test_to_check->set_removed(); + block->remove_node(block_index); + + // Modify the control flow + cfg_->map_node_to_block(test_to_check, nullptr); + return true; + } + } + } + return false; +} + bool Peephole::lea_coalesce_reg(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, MachNode* (*new_root)(), uint inst0_rule) { return lea_coalesce_helper(block, block_index, cfg_, ra_, new_root, inst0_rule, false); diff --git a/src/hotspot/cpu/x86/peephole_x86_64.hpp b/src/hotspot/cpu/x86/peephole_x86_64.hpp index 65227820173..deb53f0dfd7 100644 --- a/src/hotspot/cpu/x86/peephole_x86_64.hpp +++ b/src/hotspot/cpu/x86/peephole_x86_64.hpp @@ -34,6 +34,8 @@ class Peephole { MachNode* (*new_root)(), uint inst0_rule); static bool lea_coalesce_imm(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, MachNode* (*new_root)(), uint inst0_rule); + static bool test_may_remove(Block* block, int block_index, PhaseCFG* cfg_, PhaseRegAlloc* ra_, + MachNode* (*new_root)(), uint inst0_rule); }; #endif // CPU_X86_PEEPHOLE_X86_64_HPP diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 61ab92326b2..a7a982edd07 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1254,8 +1254,18 @@ static inline bool is_clz_non_subword_predicate_evex(BasicType bt, int vlen_byte class Node::PD { public: enum NodeFlags { - Flag_intel_jcc_erratum = Node::_last_flag << 1, - _last_flag = Flag_intel_jcc_erratum + Flag_intel_jcc_erratum = Node::_last_flag << 1, + Flag_sets_carry_flag = Node::_last_flag << 2, + Flag_sets_parity_flag = Node::_last_flag << 3, + Flag_sets_zero_flag = Node::_last_flag << 4, + Flag_sets_overflow_flag = Node::_last_flag << 5, + Flag_sets_sign_flag = Node::_last_flag << 6, + Flag_clears_carry_flag = Node::_last_flag << 7, + Flag_clears_parity_flag = Node::_last_flag << 8, + Flag_clears_zero_flag = Node::_last_flag << 9, + Flag_clears_overflow_flag = Node::_last_flag << 10, + Flag_clears_sign_flag = Node::_last_flag << 11, + _last_flag = Flag_clears_sign_flag }; }; diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 16733dbe1d1..5b1e206ae9a 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -7649,7 +7649,7 @@ instruct addI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (AddI dst src)); effect(KILL cr); - + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addl $dst, $src\t# int" %} ins_encode %{ __ addl($dst$$Register, $src$$Register); @@ -7661,6 +7661,7 @@ instruct addI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) %{ match(Set dst (AddI dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addl $dst, $src\t# int" %} ins_encode %{ @@ -7673,6 +7674,7 @@ instruct addI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (AddI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); // XXX format %{ "addl $dst, $src\t# int" %} @@ -7686,6 +7688,7 @@ instruct addI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (AddI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); // XXX format %{ "addl $dst, $src\t# int" %} @@ -7699,6 +7702,8 @@ instruct addI_mem_imm(memory dst, immI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (AddI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); + ins_cost(125); // XXX format %{ "addl $dst, $src\t# int" %} @@ -7819,6 +7824,7 @@ instruct addL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (AddL dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addq $dst, $src\t# long" %} ins_encode %{ @@ -7831,6 +7837,7 @@ instruct addL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) %{ match(Set dst (AddL dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addq $dst, $src\t# long" %} ins_encode %{ @@ -7843,6 +7850,7 @@ instruct addL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (AddL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); // XXX format %{ "addq $dst, $src\t# long" %} @@ -7856,6 +7864,7 @@ instruct addL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (AddL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); // XXX format %{ "addq $dst, $src\t# long" %} @@ -7869,6 +7878,7 @@ instruct addL_mem_imm(memory dst, immL32 src, rFlagsReg cr) %{ match(Set dst (StoreL dst (AddL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(125); // XXX format %{ "addq $dst, $src\t# long" %} @@ -7989,6 +7999,7 @@ instruct addP_rReg(rRegP dst, rRegL src, rFlagsReg cr) %{ match(Set dst (AddP dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addq $dst, $src\t# ptr" %} ins_encode %{ @@ -8001,6 +8012,7 @@ instruct addP_rReg_imm(rRegP dst, immL32 src, rFlagsReg cr) %{ match(Set dst (AddP dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "addq $dst, $src\t# ptr" %} ins_encode %{ @@ -8554,6 +8566,7 @@ instruct subI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (SubI dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "subl $dst, $src\t# int" %} ins_encode %{ @@ -8566,6 +8579,7 @@ instruct subI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (SubI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); format %{ "subl $dst, $src\t# int" %} @@ -8579,6 +8593,7 @@ instruct subI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (SubI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); format %{ "subl $dst, $src\t# int" %} @@ -8592,6 +8607,7 @@ instruct subL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (SubL dst src)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); format %{ "subq $dst, $src\t# long" %} ins_encode %{ @@ -8604,6 +8620,7 @@ instruct subL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (SubL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); format %{ "subq $dst, $src\t# long" %} @@ -8617,6 +8634,7 @@ instruct subL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (SubL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); ins_cost(150); format %{ "subq $dst, $src\t# long" %} @@ -8643,6 +8661,7 @@ instruct negI_rReg(rRegI dst, immI_0 zero, rFlagsReg cr) %{ match(Set dst (SubI zero dst)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negl $dst\t# int" %} ins_encode %{ @@ -8655,6 +8674,7 @@ instruct negI_rReg_2(rRegI dst, rFlagsReg cr) %{ match(Set dst (NegI dst)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negl $dst\t# int" %} ins_encode %{ @@ -8667,6 +8687,7 @@ instruct negI_mem(memory dst, immI_0 zero, rFlagsReg cr) %{ match(Set dst (StoreI dst (SubI zero (LoadI dst)))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negl $dst\t# int" %} ins_encode %{ @@ -8679,6 +8700,7 @@ instruct negL_rReg(rRegL dst, immL0 zero, rFlagsReg cr) %{ match(Set dst (SubL zero dst)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negq $dst\t# long" %} ins_encode %{ @@ -8691,6 +8713,7 @@ instruct negL_rReg_2(rRegL dst, rFlagsReg cr) %{ match(Set dst (NegL dst)); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negq $dst\t# int" %} ins_encode %{ @@ -8703,6 +8726,7 @@ instruct negL_mem(memory dst, immL0 zero, rFlagsReg cr) %{ match(Set dst (StoreL dst (SubL zero (LoadL dst)))); effect(KILL cr); + flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag); format %{ "negq $dst\t# long" %} ins_encode %{ @@ -9184,6 +9208,7 @@ instruct sarI_rReg_CL(rRegI dst, rcx_RegI shift, rFlagsReg cr) predicate(!VM_Version::supports_bmi2()); match(Set dst (RShiftI dst shift)); effect(KILL cr); + format %{ "sarl $dst, $shift" %} ins_encode %{ __ sarl($dst$$Register); @@ -9838,6 +9863,7 @@ instruct andI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (AndI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andl $dst, $src\t# int" %} ins_encode %{ @@ -9914,6 +9940,7 @@ instruct andI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) %{ match(Set dst (AndI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andl $dst, $src\t# int" %} ins_encode %{ @@ -9927,6 +9954,7 @@ instruct andI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (AndI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andl $dst, $src\t# int" %} @@ -9941,6 +9969,7 @@ instruct andB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreB dst (AndI (LoadB dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andb $dst, $src\t# byte" %} @@ -9954,6 +9983,7 @@ instruct andI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (AndI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andl $dst, $src\t# int" %} @@ -9968,6 +9998,7 @@ instruct andI_mem_imm(memory dst, immI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (AndI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "andl $dst, $src\t# int" %} @@ -9982,6 +10013,7 @@ instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1 match(Set dst (AndI (XorI src1 minus_1) (LoadI src2))); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "andnl $dst, $src1, $src2" %} @@ -9996,6 +10028,7 @@ instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1 match(Set dst (AndI (XorI src1 minus_1) src2)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andnl $dst, $src1, $src2" %} @@ -10009,6 +10042,7 @@ instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI_0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndI (SubI imm_zero src) src)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsil $dst, $src" %} @@ -10022,6 +10056,7 @@ instruct blsiI_rReg_mem(rRegI dst, memory src, immI_0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) )); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsil $dst, $src" %} @@ -10037,6 +10072,7 @@ instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsmskl $dst, $src" %} @@ -10052,6 +10088,7 @@ instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) match(Set dst (XorI (AddI src minus_1) src)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsmskl $dst, $src" %} @@ -10067,6 +10104,7 @@ instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) match(Set dst (AndI (AddI src minus_1) src) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsrl $dst, $src" %} @@ -10082,6 +10120,7 @@ instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsrl $dst, $src" %} @@ -10099,6 +10138,7 @@ instruct orI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (OrI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orl $dst, $src\t# int" %} ins_encode %{ @@ -10112,6 +10152,7 @@ instruct orI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) %{ match(Set dst (OrI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orl $dst, $src\t# int" %} ins_encode %{ @@ -10125,6 +10166,7 @@ instruct orI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (OrI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orl $dst, $src\t# int" %} @@ -10139,6 +10181,7 @@ instruct orB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreB dst (OrI (LoadB dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orb $dst, $src\t# byte" %} @@ -10152,6 +10195,7 @@ instruct orI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (OrI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orl $dst, $src\t# int" %} @@ -10166,6 +10210,7 @@ instruct orI_mem_imm(memory dst, immI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (OrI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "orl $dst, $src\t# int" %} @@ -10181,6 +10226,7 @@ instruct xorI_rReg(rRegI dst, rRegI src, rFlagsReg cr) %{ match(Set dst (XorI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "xorl $dst, $src\t# int" %} ins_encode %{ @@ -10205,6 +10251,7 @@ instruct xorI_rReg_imm(rRegI dst, immI src, rFlagsReg cr) %{ match(Set dst (XorI dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "xorl $dst, $src\t# int" %} ins_encode %{ @@ -10218,6 +10265,7 @@ instruct xorI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) %{ match(Set dst (XorI dst (LoadI src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorl $dst, $src\t# int" %} @@ -10232,6 +10280,7 @@ instruct xorB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreB dst (XorI (LoadB dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorb $dst, $src\t# byte" %} @@ -10245,6 +10294,7 @@ instruct xorI_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (XorI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorl $dst, $src\t# int" %} @@ -10259,6 +10309,7 @@ instruct xorI_mem_imm(memory dst, immI src, rFlagsReg cr) %{ match(Set dst (StoreI dst (XorI (LoadI dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "xorl $dst, $src\t# int" %} @@ -10277,6 +10328,7 @@ instruct andL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (AndL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andq $dst, $src\t# long" %} ins_encode %{ @@ -10316,6 +10368,7 @@ instruct andL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) %{ match(Set dst (AndL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andq $dst, $src\t# long" %} ins_encode %{ @@ -10329,6 +10382,7 @@ instruct andL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (AndL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andq $dst, $src\t# long" %} @@ -10343,6 +10397,7 @@ instruct andL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (AndL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "andq $dst, $src\t# long" %} @@ -10357,6 +10412,7 @@ instruct andL_mem_imm(memory dst, immL32 src, rFlagsReg cr) %{ match(Set dst (StoreL dst (AndL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "andq $dst, $src\t# long" %} @@ -10388,6 +10444,7 @@ instruct andnL_rReg_rReg_mem(rRegL dst, rRegL src1, memory src2, immL_M1 minus_1 match(Set dst (AndL (XorL src1 minus_1) (LoadL src2))); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "andnq $dst, $src1, $src2" %} @@ -10402,6 +10459,7 @@ instruct andnL_rReg_rReg_rReg(rRegL dst, rRegL src1, rRegL src2, immL_M1 minus_1 match(Set dst (AndL (XorL src1 minus_1) src2)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "andnq $dst, $src1, $src2" %} @@ -10415,6 +10473,7 @@ instruct blsiL_rReg_rReg(rRegL dst, rRegL src, immL0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndL (SubL imm_zero src) src)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsiq $dst, $src" %} @@ -10428,6 +10487,7 @@ instruct blsiL_rReg_mem(rRegL dst, memory src, immL0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) )); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsiq $dst, $src" %} @@ -10443,6 +10503,7 @@ instruct blsmskL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsmskq $dst, $src" %} @@ -10458,6 +10519,7 @@ instruct blsmskL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) match(Set dst (XorL (AddL src minus_1) src)); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsmskq $dst, $src" %} @@ -10473,6 +10535,7 @@ instruct blsrL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) match(Set dst (AndL (AddL src minus_1) src) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); format %{ "blsrq $dst, $src" %} @@ -10488,6 +10551,7 @@ instruct blsrL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) ); predicate(UseBMI1Instructions); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); ins_cost(125); format %{ "blsrq $dst, $src" %} @@ -10505,6 +10569,7 @@ instruct orL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (OrL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orq $dst, $src\t# long" %} ins_encode %{ @@ -10517,6 +10582,7 @@ instruct orL_rReg(rRegL dst, rRegL src, rFlagsReg cr) instruct orL_rReg_castP2X(rRegL dst, any_RegP src, rFlagsReg cr) %{ match(Set dst (OrL dst (CastP2X src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orq $dst, $src\t# long" %} ins_encode %{ @@ -10531,6 +10597,7 @@ instruct orL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) %{ match(Set dst (OrL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "orq $dst, $src\t# long" %} ins_encode %{ @@ -10544,6 +10611,7 @@ instruct orL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (OrL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orq $dst, $src\t# long" %} @@ -10558,6 +10626,7 @@ instruct orL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (OrL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "orq $dst, $src\t# long" %} @@ -10572,6 +10641,7 @@ instruct orL_mem_imm(memory dst, immL32 src, rFlagsReg cr) %{ match(Set dst (StoreL dst (OrL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "orq $dst, $src\t# long" %} @@ -10604,6 +10674,7 @@ instruct xorL_rReg(rRegL dst, rRegL src, rFlagsReg cr) %{ match(Set dst (XorL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "xorq $dst, $src\t# long" %} ins_encode %{ @@ -10628,6 +10699,7 @@ instruct xorL_rReg_imm(rRegL dst, immL32 src, rFlagsReg cr) %{ match(Set dst (XorL dst src)); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); format %{ "xorq $dst, $src\t# long" %} ins_encode %{ @@ -10641,6 +10713,7 @@ instruct xorL_rReg_mem(rRegL dst, memory src, rFlagsReg cr) %{ match(Set dst (XorL dst (LoadL src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorq $dst, $src\t# long" %} @@ -10655,6 +10728,7 @@ instruct xorL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (XorL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(150); format %{ "xorq $dst, $src\t# long" %} @@ -10669,6 +10743,7 @@ instruct xorL_mem_imm(memory dst, immL32 src, rFlagsReg cr) %{ match(Set dst (StoreL dst (XorL (LoadL dst) src))); effect(KILL cr); + flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); ins_cost(125); format %{ "xorq $dst, $src\t# long" %} @@ -13863,6 +13938,24 @@ peephole peepreplace (leaL_rReg_immI2_peep()); %} +// These peephole rules matches instructions which set flags and are followed by a testI/L_reg +// The test instruction is redudanent in case the downstream instuctions (like JCC or CMOV) only use flags that are already set by the previous instruction + +//int variant +peephole +%{ + peepmatch (testI_reg); + peepprocedure (test_may_remove); +%} + +//long variant +peephole +%{ + peepmatch (testL_reg); + peepprocedure (test_may_remove); +%} + + //----------SMARTSPILL RULES--------------------------------------------------- // These must follow all instruction definitions as they use the names // defined in the instructions definitions. diff --git a/src/hotspot/share/adlc/adlparse.cpp b/src/hotspot/share/adlc/adlparse.cpp index 0ab306118d6..57c6b0c5a99 100644 --- a/src/hotspot/share/adlc/adlparse.cpp +++ b/src/hotspot/share/adlc/adlparse.cpp @@ -229,6 +229,7 @@ void ADLParser::instr_parse(void) { else if (!strcmp(ident, "opcode")) instr->_opcode = opcode_parse(instr); else if (!strcmp(ident, "size")) instr->_size = size_parse(instr); else if (!strcmp(ident, "effect")) effect_parse(instr); + else if (!strcmp(ident, "flag")) instr->_flag = flag_parse(instr); else if (!strcmp(ident, "expand")) instr->_exprule = expand_parse(instr); else if (!strcmp(ident, "rewrite")) instr->_rewrule = rewrite_parse(); else if (!strcmp(ident, "constraint")) { @@ -4126,6 +4127,46 @@ void ADLParser::effect_parse(InstructForm *instr) { } +//-------------------------------flag_parse------------------------------------ +Flag* ADLParser::flag_parse(InstructForm *instr) { + char* ident = nullptr; + Flag* result = nullptr; + + skipws(); // Skip whitespace + if (_curchar != '(') { + parse_err(SYNERR, "missing '(' in flag definition\n"); + return nullptr; + } + do { + next_char(); + skipws(); + if (_curchar == ')') break; + + ident = get_ident(); + if (ident == nullptr) { + parse_err(SYNERR, "flag name expected at %c\n", _curchar); + return nullptr; + } + Flag* newflag = new Flag(ident); + if (result == nullptr) result = newflag; + else result->append_flag(newflag); + if (_AD._adl_debug > 1) fprintf(stderr, "\tFlag Name: %s\n", ident); + skipws(); + } while (_curchar == ','); + if (_curchar != ')') parse_err(SYNERR, "missing ')'\n"); + else { + next_char(); // set current character position past the close paren + } + + // Debug Stuff + if (_curchar != ';') { + parse_err(SYNERR, "missing ';' in Flag definition\n"); + } + // Skip ';' + next_char(); + return result; +} + //------------------------------expand_parse----------------------------------- ExpandRule* ADLParser::expand_parse(InstructForm *instr) { char *ident, *ident2; diff --git a/src/hotspot/share/adlc/adlparse.hpp b/src/hotspot/share/adlc/adlparse.hpp index 2d244fdf4cb..e5873ef29c7 100644 --- a/src/hotspot/share/adlc/adlparse.hpp +++ b/src/hotspot/share/adlc/adlparse.hpp @@ -47,6 +47,7 @@ class Encode; class Attribute; class Effect; class ExpandRule; +class Flag; class RewriteRule; class Constraint; class ConstructRule; @@ -177,6 +178,7 @@ class ADLParser { FormatRule *format_parse(void); // Parse format rule FormatRule *template_parse(void); // Parse format rule void effect_parse(InstructForm *instr); // Parse effect rule + Flag *flag_parse(InstructForm *instr); // Parse flag rule ExpandRule *expand_parse(InstructForm *instr); // Parse expand rule RewriteRule *rewrite_parse(void); // Parse rewrite rule Constraint *constraint_parse(void); // Parse constraint rule diff --git a/src/hotspot/share/adlc/forms.hpp b/src/hotspot/share/adlc/forms.hpp index eb0b1acfe15..c3dd85eb98b 100644 --- a/src/hotspot/share/adlc/forms.hpp +++ b/src/hotspot/share/adlc/forms.hpp @@ -54,6 +54,7 @@ class MatchRule; class Attribute; class Effect; class ExpandRule; +class Flag; class RewriteRule; class ConstructRule; class FormatRule; @@ -237,6 +238,7 @@ class Form { EXP, REW, EFF, + FLG, RDEF, RCL, ACL, diff --git a/src/hotspot/share/adlc/formsopt.hpp b/src/hotspot/share/adlc/formsopt.hpp index 467076eb1b7..1a2b5dadd30 100644 --- a/src/hotspot/share/adlc/formsopt.hpp +++ b/src/hotspot/share/adlc/formsopt.hpp @@ -44,6 +44,7 @@ class MatchRule; class Attribute; class Effect; class ExpandRule; +class Flag; class RewriteRule; class ConstructRule; class FormatRule; diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index be4ee3a3acf..92f12e275a0 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -52,6 +52,7 @@ InstructForm::InstructForm(const char *id, bool ideal_only) _format = nullptr; _peephole = nullptr; _ins_pipe = nullptr; + _flag = nullptr; _uniq_idx = nullptr; _num_uniq = 0; _cisc_spill_operand = Not_cisc_spillable;// Which operand may cisc-spill @@ -86,6 +87,7 @@ InstructForm::InstructForm(const char *id, InstructForm *instr, MatchRule *rule) _format = instr->_format; _peephole = instr->_peephole; _ins_pipe = instr->_ins_pipe; + _flag = instr->_flag; _uniq_idx = instr->_uniq_idx; _num_uniq = instr->_num_uniq; _cisc_spill_operand = Not_cisc_spillable; // Which operand may cisc-spill @@ -1893,6 +1895,34 @@ void Effect::output(FILE *fp) { // Write info to output files fprintf(fp,"Effect: %s\n", (_name?_name:"")); } +//---------------------------------Flag---------------------------------------- +Flag::Flag(const char *name) : _name(name), _next(nullptr) { + _ftype = Form::FLG; +} + +Flag::~Flag() { +} + +void Flag::append_flag(Flag *next_flag) { + if( _next == nullptr ) { + _next = next_flag; + } else { + _next->append_flag( next_flag ); + } +} + +Flag* Flag::next() { + return _next; +} + +void Flag::dump() { + output(stderr); +} + +void Flag::output(FILE *fp) { // Write info to output files + fprintf(fp,"Flag: %s\n", (_name?_name:"")); +} + //------------------------------ExpandRule------------------------------------- ExpandRule::ExpandRule() : _expand_instrs(), _newopconst(cmpstr, hashstr, Form::arena) { diff --git a/src/hotspot/share/adlc/formssel.hpp b/src/hotspot/share/adlc/formssel.hpp index 2036f7ed895..a55dcb73622 100644 --- a/src/hotspot/share/adlc/formssel.hpp +++ b/src/hotspot/share/adlc/formssel.hpp @@ -45,6 +45,7 @@ class MatchRule; class Attribute; class Effect; class ExpandRule; +class Flag; class RewriteRule; class ConstructRule; class FormatRule; @@ -108,6 +109,7 @@ class InstructForm : public Form { FormatRule *_format; // Format for assembly generation Peephole *_peephole; // List of peephole rules for instruction const char *_ins_pipe; // Instruction Scheduling description class + Flag *_flag; // List of Flags that should be set by default for this node uint *_uniq_idx; // Indexes of unique operands uint _uniq_idx_length; // Length of _uniq_idx array @@ -515,6 +517,26 @@ class ExpandRule : public Form { void output(FILE *fp); // Write info to output files }; +//---------------------------------Flag---------------------------------------- +class Flag : public Form { +private: + Flag* _next; +public: + const char *_name; // Name of the flag (See Node:: or Node::Pd:: + + // Public Methods + Flag(const char *name); // Constructor + ~Flag(); // Destructor + + // Append a flag rule for the same instruction + void append_flag(Flag *next_flag); + + Flag* next(); + + void dump(); // Debug printer + void output(FILE *fp); // Write info to output files +}; + //------------------------------RewriteRule------------------------------------ class RewriteRule : public Form { private: diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index 5276987eec4..d243589db44 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -1469,10 +1469,14 @@ void ArchDesc::definePeephole(FILE *fp, InstructForm *node) { // End of scope for this peephole's constraints fprintf(fp, " }\n"); } else { - const char* replace_inst = nullptr; - preplace->next_instruction(replace_inst); - // Generate the target instruction - fprintf(fp, " auto replacing = [](){ return static_cast(new %sNode()); };\n", replace_inst); + if (preplace != nullptr) { + const char *replace_inst = nullptr; + preplace->next_instruction(replace_inst); + // Generate the target instruction + fprintf(fp, " auto replacing = [](){ return static_cast(new %sNode()); };\n", replace_inst); + } else { + fprintf(fp, " auto replacing = nullptr;\n"); + } // Call the precedure fprintf(fp, " bool replacement = Peephole::%s(block, block_index, cfg_, ra_, replacing", pprocedure->name()); @@ -4010,6 +4014,22 @@ void ArchDesc::buildMachNode(FILE *fp_cpp, InstructForm *inst, const char *inden fprintf(fp_cpp, " );\n"); // ##### } + if (inst->_flag != nullptr) { + Flag* node = inst->_flag; + const char* prefix = "Node::"; + bool node_flags_set = false; + do { + if (!node_flags_set) { + fprintf(fp_cpp, "%s node->add_flag(%s%s", indent, prefix, node->_name); + node_flags_set = true; + } else { + fprintf(fp_cpp, " | %s%s", prefix, node->_name); + } + } while ((node = node->next()) != nullptr); + if (node_flags_set) { + fprintf(fp_cpp, ");\n"); + } + } // Fill in the bottom_type where requested if (inst->captures_bottom_type(_globalNames)) { diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestTestRemovalPeephole.java b/test/hotspot/jtreg/compiler/c2/irTests/TestTestRemovalPeephole.java new file mode 100644 index 00000000000..359493d86f4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestTestRemovalPeephole.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.irTests; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; +import java.util.Random; +import jdk.test.lib.Utils; + +/* + * @test + * @summary Test that unnessercary test instructions are not present in the final code + * @bug 8312213 + * @library /test/lib / + * @requires vm.compiler2.enabled + * @requires os.arch == "x86_64" | os.arch == "amd64" + * @run driver compiler.c2.irTests.TestTestRemovalPeephole + */ +public class TestTestRemovalPeephole { + static volatile boolean field; + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntAddtionEquals0(int x, int y) { + int result = x + y; + if (result == 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntAddtionNotEquals0(int x, int y) { + int result = x + y; + if (result != 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongAddtionEquals0(long x, long y) { + long result = x + y; + if (result == 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongAddtionNotEquals0(long x, long y) { + long result = x + y; + if (result != 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntOrEquals0(int x, int y) { + int result = x | y; + if (result == 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntOrNotEquals0(int x, int y) { + int result = x | y; + if (result != 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongOrEquals0(long x, long y) { + long result = x | y; + if (result == 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongOrNotEquals0(long x, long y) { + long result = x | y; + if (result != 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testIntOrGreater0(int x, int y) { + int result = x | y; + if (result > 0) { + field = true; + return true; + } + return false; + } + + @Test + @Arguments({Argument.RANDOM_EACH, Argument.RANDOM_EACH}) + @IR(failOn = {IRNode.X86_TESTI_REG, IRNode.X86_TESTL_REG}, phase = CompilePhase.FINAL_CODE) + public boolean testLongOrGreater0(long x, long y) { + long result = x | y; + if (result > 0) { + field = true; + return true; + } + return false; + } + + @DontCompile + public void assertResult(int x, int y) { + Asserts.assertEQ((x + y) == 0, testIntAddtionEquals0(x, y)); + Asserts.assertEQ((x + y) != 0, testIntAddtionNotEquals0(x, y)); + Asserts.assertEQ((x | y) == 0, testIntOrEquals0(x, y)); + Asserts.assertEQ((x | y) != 0, testIntOrNotEquals0(x, y)); + Asserts.assertEQ((x | y) > 0, testIntOrGreater0(x, y)); + } + + @DontCompile + public void assertResult(long x, long y) { + Asserts.assertEQ((x + y) == 0, testLongAddtionEquals0(x, y)); + Asserts.assertEQ((x + y) != 0, testLongAddtionNotEquals0(x, y)); + Asserts.assertEQ((x | y) == 0, testLongOrEquals0(x, y)); + Asserts.assertEQ((x | y) != 0, testLongOrNotEquals0(x, y)); + Asserts.assertEQ((x | y) > 0, testLongOrGreater0(x, y)); + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 3e2db1541dd..66dcc097d2c 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2119,6 +2119,16 @@ public class IRNode { machOnlyNameRegex(X86_LOCK_XADDL, "xaddL"); } + public static final String X86_TESTI_REG = PREFIX + "X86_TESTI_REG" + POSTFIX; + static { + machOnlyNameRegex(X86_TESTI_REG, "testI_reg"); + } + + public static final String X86_TESTL_REG = PREFIX + "X86_TESTL_REG" + POSTFIX; + static { + machOnlyNameRegex(X86_TESTL_REG, "testL_reg"); + } + /* * Utility methods to set up IR_NODE_MAPPINGS. */ diff --git a/test/micro/org/openjdk/bench/vm/compiler/x86/TestRemovalPeephole.java b/test/micro/org/openjdk/bench/vm/compiler/x86/TestRemovalPeephole.java new file mode 100644 index 00000000000..415abca5a01 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/x86/TestRemovalPeephole.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.compiler.x86; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 2) +@Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) +@State(Scope.Thread) +public class TestRemovalPeephole { + long[] valuesLong1; + long[] valuesLong2; + int[] valuesInt1; + int[] valuesInt2; + long valueLong1; + long valueLong2; + int valueInt1; + int valueInt2; + + @Setup + public void setup() { + Random random = new Random(42); + valuesLong1 = new long[128]; + valuesLong2 = new long[128]; + for (int i = 0; i < valuesLong1.length; i++) { + valuesLong1[i] = random.nextLong(); + } + for (int i = 0; i < valuesLong2.length; i++) { + valuesLong2[i] = random.nextLong(); + } + + valuesInt1 = new int[128]; + valuesInt2 = new int[128]; + for (int i = 0; i < valuesInt1.length; i++) { + valuesInt1[i] = random.nextInt(); + } + for (int i = 0; i < valuesInt2.length; i++) { + valuesInt2[i] = random.nextInt(); + } + valueLong1 = random.nextLong(); + valueLong2 = random.nextLong(); + valueInt1 = random.nextInt(); + valueInt2 = random.nextInt(); + } + + @Benchmark + public void benchmarkAndTestFusableInt(Blackhole bh) { + for (int i = 0; i < valuesInt1.length; i++) { + int value1 = valuesInt1[i]; + int value2 = valuesInt2[i]; + int withAnd1 = value1 & 0xF; + int withAnd2 = value2 & 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + } + + @Benchmark + public void benchmarkAndTestFusableLong(Blackhole bh) { + for (int i = 0; i < valuesLong1.length; i++) { + long value1 = valuesLong1[i]; + long value2 = valuesLong2[i]; + long withAnd1 = value1 & 0xFFFFFFFFFFL; + long withAnd2 = value2 & 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + } + + @Benchmark + public void benchmarkOrTestFusableInt(Blackhole bh) { + for (int i = 0; i < valuesInt1.length; i++) { + int value1 = valuesInt1[i]; + int value2 = valuesInt2[i]; + int withAnd1 = value1 | 0xF; + int withAnd2 = value2 | 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + } + + @Benchmark + public void benchmarkOrTestFusableLong(Blackhole bh) { + for (int i = 0; i < valuesLong1.length; i++) { + long value1 = valuesLong1[i]; + long value2 = valuesLong2[i]; + long withAnd1 = value1 | 0xFFFFFFFFFFL; + long withAnd2 = value2 | 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + } + + @Benchmark + public void benchmarkXorTestFusableInt(Blackhole bh) { + for (int i = 0; i < valuesInt1.length; i++) { + int value1 = valuesInt1[i]; + int value2 = valuesInt2[i]; + int withAnd1 = value1 ^ 0xF; + int withAnd2 = value2 ^ 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + } + + @Benchmark + public void benchmarkXorTestFusableLong(Blackhole bh) { + for (int i = 0; i < valuesLong1.length; i++) { + long value1 = valuesLong1[i]; + long value2 = valuesLong2[i]; + long withAnd1 = value1 ^ 0xFFFFFFFFFFL; + long withAnd2 = value2 ^ 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + } + + + @Benchmark + public void benchmarkAndTestFusableIntSingle(Blackhole bh) { + int withAnd1 = valueInt1 & 0xF; + int withAnd2 = valueInt2 & 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + + @Benchmark + public void benchmarkAndTestFusableLongSingle(Blackhole bh) { + long withAnd1 = valueLong1 & 0xFFFFFFFFFFL; + long withAnd2 = valueLong2 & 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + + @Benchmark + public void benchmarkOrTestFusableIntSingle(Blackhole bh) { + int withAnd1 = valueInt1 | 0xF; + int withAnd2 = valueInt2 | 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + + @Benchmark + public void benchmarkOrTestFusableLongSingle(Blackhole bh) { + long withAnd1 = valueLong1 | 0xFFFFFFFFFFL; + long withAnd2 = valueLong2 | 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } + + @Benchmark + public void benchmarkXorTestFusableIntSingle(Blackhole bh) { + int withAnd1 = valueInt1 ^ 0xF; + int withAnd2 = valueInt2 ^ 0xF; + + bh.consume(withAnd1 > 0x0 && withAnd2 > 0x0 && withAnd1 < 0xF && withAnd2 < 0xF); + } + + @Benchmark + public void benchmarkXorTestFusableLongSingle(Blackhole bh) { + long withAnd1 = valueLong1 ^ 0xFFFFFFFFFFL; + long withAnd2 = valueLong2 ^ 0xFFFFFFFFFFL; + + bh.consume(withAnd1 > 0x0L && withAnd2 > 0x0L && withAnd1 < 0xFFFFFFFFFFL && withAnd2 < 0xFFFFFFFFFFL); + } +} From d3ee704b28c2d587dc0c8479c7e0dd12ebbe6c12 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Tue, 5 Sep 2023 22:46:15 +0000 Subject: [PATCH 76/86] 8315563: Remove references to JDK-8226420 from problem list Reviewed-by: kevinw, cjplummer --- test/jdk/ProblemList.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 7cca203bc30..ccd202775c0 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -722,9 +722,9 @@ java/util/concurrent/ExecutorService/CloseTest.java 8288899 macosx-a # svc_tools -sun/tools/jstatd/TestJstatdDefaults.java 8081569,8226420 windows-all -sun/tools/jstatd/TestJstatdRmiPort.java 8226420,8251259,8293577 generic-all -sun/tools/jstatd/TestJstatdServer.java 8081569,8226420 windows-all +sun/tools/jstatd/TestJstatdDefaults.java 8081569 windows-all +sun/tools/jstatd/TestJstatdRmiPort.java 8251259,8293577 generic-all +sun/tools/jstatd/TestJstatdServer.java 8081569 windows-all sun/tools/jstat/jstatLineCounts1.sh 8268211 linux-aarch64 sun/tools/jstat/jstatLineCounts2.sh 8268211 linux-aarch64 From 7a08e6bdd63c2b4d6283c0c45820024199a4614e Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Tue, 5 Sep 2023 23:08:25 +0000 Subject: [PATCH 77/86] 8313575: Refactor PKCS11Test tests Reviewed-by: valeriep --- test/jdk/sun/security/pkcs11/PKCS11Test.java | 82 +------------------ .../pkcs11/Provider/MultipleLogins.sh | 2 - .../sun/security/pkcs11/nss/p11-deimos.txt | 14 ---- .../rsa/TestP11KeyFactoryGetRSAKeySpec.java | 4 +- 4 files changed, 4 insertions(+), 98 deletions(-) delete mode 100644 test/jdk/sun/security/pkcs11/nss/p11-deimos.txt diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index fe1b894f236..5a619ec59b5 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -183,45 +183,14 @@ public static void main(PKCS11Test test, String[] args) throws Exception { Provider[] oldProviders = Security.getProviders(); try { System.out.println("Beginning test run " + test.getClass().getName() + "..."); - boolean skippedDefault = false; - boolean skippedNSS = false; - boolean skippedDeimos = false; - - // Use separate try-catch for each test to allow all test run - try { - testDefault(test); - } catch (SkippedException se) { - System.out.println("testDefault: Skipped"); - skippedDefault = true; - se.printStackTrace(System.out); - } - - try { - testNSS(test); - } catch (SkippedException se) { - System.out.println("testNSS: Skipped"); - skippedNSS = true; - se.printStackTrace(System.out); - } - - try { - testDeimos(test); - } catch (SkippedException se) { - System.out.println("testDeimos: Skipped"); - skippedDeimos = true; - se.printStackTrace(System.out); - } - - if (skippedDefault && skippedNSS && skippedDeimos) { - throw new SkippedException("All tests are skipped, check logs"); - } + testNSS(test); } finally { // NOTE: Do not place a 'return' in any finally block // as it will suppress exceptions and hide test failures. Provider[] newProviders = Security.getProviders(); boolean found = true; - // Do not restore providers if nothing changed. This is especailly + // Do not restore providers if nothing changed. This is especially // useful for ./Provider/Login.sh, where a SecurityManager exists. if (oldProviders.length == newProviders.length) { found = false; @@ -243,51 +212,6 @@ public static void main(PKCS11Test test, String[] args) throws Exception { } } - public static void testDeimos(PKCS11Test test) throws Exception { - System.out.println("===> testDeimos: Starting test run"); - if ("true".equals(System.getProperty("NO_DEIMOS"))) { - System.out.println("Skip Deimos software as test configured with NO_DEIMOS"); - return; - } - - if (!new File("/opt/SUNWconn/lib/libpkcs11.so").isFile()) { - throw new SkippedException("testDeimos: \"/opt/SUNWconn/lib/libpkcs11.so\" " + - "file required for Deimos not found"); - } - - String base = getBase(); - String p11config = base + SEP + "nss" + SEP + "p11-deimos.txt"; - Provider p = getSunPKCS11(p11config); - test.premain(p); - System.out.println("testDeimos: Completed"); - } - - // Run test for default configured PKCS11 providers (if any) - public static void testDefault(PKCS11Test test) throws Exception { - System.out.println("===> testDefault: Starting test run"); - boolean foundPKCS11 = false; - - if ("true".equals(System.getProperty("NO_DEFAULT"))) { - System.out.println("Skip default provider as test configured with NO_DEFAULT"); - return; - } - - Provider[] providers = Security.getProviders(); - for (Provider p : providers) { - if (p.getName().startsWith("SunPKCS11-")) { - foundPKCS11 = true; - test.premain(p); - } - } - - if (!foundPKCS11) { - throw new SkippedException("testDefault: Skip default test as SunPKCS11 " + - "provider is not configured"); - } - - System.out.println("testDefault: Completed"); - } - public static String getBase() throws Exception { if (PKCS11_BASE != null) { return PKCS11_BASE; @@ -973,8 +897,6 @@ T[] concat(T[] a, T[] b) { protected void setCommonSystemProps() { System.setProperty("java.security.debug", "true"); - System.setProperty("NO_DEIMOS", "true"); - System.setProperty("NO_DEFAULT", "true"); System.setProperty("CUSTOM_DB_DIR", TEST_CLASSES); } diff --git a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh index 273f44bbb7d..00dafabd03c 100644 --- a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh +++ b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh @@ -120,8 +120,6 @@ TEST_ARGS="${TESTVMOPTS} -classpath ${TESTCLASSPATH} \ --add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED \ -DCUSTOM_DB_DIR=${TESTCLASSES} \ -DCUSTOM_P11_CONFIG=${TESTSRC}${FS}MultipleLogins-nss.txt \ - -DNO_DEFAULT=true \ - -DNO_DEIMOS=true \ -Dtest.src=${TESTSRC} \ -Dtest.classes=${TESTCLASSES} \ -Djava.security.debug=${DEBUG}" diff --git a/test/jdk/sun/security/pkcs11/nss/p11-deimos.txt b/test/jdk/sun/security/pkcs11/nss/p11-deimos.txt deleted file mode 100644 index 813930022c7..00000000000 --- a/test/jdk/sun/security/pkcs11/nss/p11-deimos.txt +++ /dev/null @@ -1,14 +0,0 @@ -# -# -# -# Configuration to run unit tests with the Deimos (SCA1000) software -# - -name = Deimos - -#showInfo = true - -library = /opt/SUNWconn/lib/libpkcs11.so - -attributes = compatibility - diff --git a/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java b/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java index 2babc77e37a..cc9a07d3608 100644 --- a/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java +++ b/test/jdk/sun/security/pkcs11/rsa/TestP11KeyFactoryGetRSAKeySpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -39,7 +39,7 @@ * @library /test/lib .. * @run main/othervm TestP11KeyFactoryGetRSAKeySpec * @run main/othervm -Djava.security.manager=allow TestP11KeyFactoryGetRSAKeySpec sm rsakeys.ks.policy - * @run main/othervm -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt -DNO_DEIMOS=true -DNO_DEFAULT=true TestP11KeyFactoryGetRSAKeySpec + * @run main/othervm -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt TestP11KeyFactoryGetRSAKeySpec * @modules jdk.crypto.cryptoki */ From 5cbff2460812fee707f9d96ab00a628d1ce3fbef Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 6 Sep 2023 00:02:54 +0000 Subject: [PATCH 78/86] 8315406: [REDO] serviceability/jdwp/AllModulesCommandTest.java ignores VM flags Reviewed-by: cjplummer, dcubed --- .../jdwp/AllModulesCommandTest.java | 8 +-- .../serviceability/jdwp/DebuggeeLauncher.java | 60 ++++--------------- .../serviceability/jdwp/StreamHandler.java | 5 +- 3 files changed, 13 insertions(+), 60 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jdwp/AllModulesCommandTest.java b/test/hotspot/jtreg/serviceability/jdwp/AllModulesCommandTest.java index 3c799f6e54d..28fdeec3219 100644 --- a/test/hotspot/jtreg/serviceability/jdwp/AllModulesCommandTest.java +++ b/test/hotspot/jtreg/serviceability/jdwp/AllModulesCommandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,12 +72,6 @@ public void onDebuggeeSendingCompleted() { jdwpLatch.countDown(); } - @Override - public void onDebuggeeError(String message) { - System.err.println("Debuggee error: '" + message + "'"); - System.exit(1); - } - private void doJdwp() throws Exception { try { // Establish JDWP socket connection diff --git a/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java b/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java index 5c3d01ec2dc..2d03d2f418f 100644 --- a/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java +++ b/test/hotspot/jtreg/serviceability/jdwp/DebuggeeLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,9 @@ */ import java.util.StringTokenizer; -import jdk.test.lib.JDKToolFinder; import jdk.test.lib.JDWP; import static jdk.test.lib.Asserts.assertFalse; +import jdk.test.lib.process.ProcessTools; /** * Launches the debuggee with the necessary JDWP options and handles the output @@ -45,21 +45,14 @@ public interface Listener { */ void onDebuggeeSendingCompleted(); - /** - * Callback to handle any debuggee error - * - * @param line line from the debuggee's stderr - */ - void onDebuggeeError(String line); } private int jdwpPort = -1; - private static final String CLS_DIR = System.getProperty("test.classes", "").trim(); private static final String DEBUGGEE = "AllModulesCommandTestDebuggee"; + private static final String JDWP_OPT = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0"; + private Process p; private final Listener listener; - private StreamHandler inputHandler; - private StreamHandler errorHandler; /** * @param listener the listener we report the debuggee events to @@ -70,36 +63,20 @@ public DebuggeeLauncher(Listener listener) { /** * Starts the debuggee with the necessary JDWP options and handles the - * debuggee's stdout and stderr outputs + * debuggee's stdout output. stderr might contain jvm output, which is just printed to the log. * * @throws Throwable */ public void launchDebuggee() throws Throwable { - ProcessBuilder pb = new ProcessBuilder(getCommand()); + ProcessBuilder pb = ProcessTools.createTestJvm(JDWP_OPT, DEBUGGEE); p = pb.start(); - inputHandler = new StreamHandler(p.getInputStream(), this); - errorHandler = new StreamHandler(p.getErrorStream(), this); + StreamHandler inputHandler = new StreamHandler(p.getInputStream(), this); + StreamHandler errorHandler = new StreamHandler(p.getErrorStream(), l -> System.out.println("[stderr]: " + l)); inputHandler.start(); errorHandler.start(); } - /** - * Command to start the debuggee with the JDWP options and using the JDK - * under test - * - * @return the command - */ - private String[] getCommand() { - return new String[]{ - JDKToolFinder.getTestJDKTool("java"), - getJdwpOptions(), - "-cp", - CLS_DIR, - DEBUGGEE - }; - } - /** * Terminates the debuggee */ @@ -109,15 +86,6 @@ public void terminateDebuggee() { } } - /** - * Debuggee JDWP options - * - * @return the JDWP options to start the debuggee with - */ - private static String getJdwpOptions() { - return "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0"; - } - /** * Gets JDWP port debuggee is listening on. * @@ -129,16 +97,8 @@ public int getJdwpPort() { } @Override - public void onStringRead(StreamHandler handler, String line) { - if (handler.equals(errorHandler)) { - terminateDebuggee(); - listener.onDebuggeeError(line); - } else { - processDebuggeeOutput(line); - } - } - - private void processDebuggeeOutput(String line) { + public void onStringRead(String line) { + System.out.println("[stdout]: " + line); if (jdwpPort == -1) { JDWP.ListenAddress addr = JDWP.parseListenAddress(line); if (addr != null) { diff --git a/test/hotspot/jtreg/serviceability/jdwp/StreamHandler.java b/test/hotspot/jtreg/serviceability/jdwp/StreamHandler.java index 257f66a66a9..2822a91a8ce 100644 --- a/test/hotspot/jtreg/serviceability/jdwp/StreamHandler.java +++ b/test/hotspot/jtreg/serviceability/jdwp/StreamHandler.java @@ -37,10 +37,9 @@ public class StreamHandler implements Runnable { public interface Listener { /** * Called when a line has been read from the process output stream - * @param handler this StreamHandler * @param s the line */ - void onStringRead(StreamHandler handler, String s); + void onStringRead(String s); } private final ExecutorService executor; @@ -71,7 +70,7 @@ public void run() { BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line; while ((line = br.readLine()) != null) { - listener.onStringRead(this, line); + listener.onStringRead(line); } } catch (Exception x) { throw new RuntimeException(x); From 5d3fdc1750645455d64a341e1437f779ba3fd20c Mon Sep 17 00:00:00 2001 From: Vladimir Kempik Date: Wed, 6 Sep 2023 06:49:10 +0000 Subject: [PATCH 79/86] 8315612: RISC-V: intrinsic for unsignedMultiplyHigh Reviewed-by: fyang --- src/hotspot/cpu/riscv/riscv.ad | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index d03dc843c2b..1cca3ef9f37 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -6864,6 +6864,21 @@ instruct mulHiL_rReg(iRegLNoSp dst, iRegL src1, iRegL src2) ins_pipe(lmul_reg_reg); %} +instruct umulHiL_rReg(iRegLNoSp dst, iRegL src1, iRegL src2) +%{ + match(Set dst (UMulHiL src1 src2)); + ins_cost(IMUL_COST); + format %{ "mulhu $dst, $src1, $src2\t# umulhi, #@umulHiL_rReg" %} + + ins_encode %{ + __ mulhu(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(lmul_reg_reg); +%} + // Integer Divide instruct divI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ From a258fc443f6a119a122814f6c69e489ed0513856 Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Wed, 6 Sep 2023 07:19:53 +0000 Subject: [PATCH 80/86] 8315648: Add test for JDK-8309979 changes Reviewed-by: cjplummer --- test/hotspot/jtreg/serviceability/sa/ClhsdbDumpclass.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpclass.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpclass.java index 6621e19e03c..e2d7073552e 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpclass.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbDumpclass.java @@ -92,6 +92,7 @@ public static void main(String[] args) throws Exception { // containing only methods with sequential control flows. // But the class used here (LingeredApp) is not such a case. out.shouldContain("StackMapTable:"); + out.shouldContain("BootstrapMethods:"); out.shouldNotContain("Error:"); } catch (SkippedException se) { throw se; From ba1a46392f0b9c77c64278f82513aaf51f5c9b1b Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 6 Sep 2023 07:25:22 +0000 Subject: [PATCH 81/86] 8315377: C2: assert(u->find_out_with(Op_AddP) == nullptr) failed: more than 2 chained AddP nodes? Reviewed-by: chagedorn, kvn, thartmann --- src/hotspot/share/opto/loopnode.hpp | 2 + src/hotspot/share/opto/loopopts.cpp | 35 ++++++--- .../TestSinkingMoreThan2AddPNodes.java | 75 +++++++++++++++++++ 3 files changed, 100 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestSinkingMoreThan2AddPNodes.java diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index bb12e7b97d4..6638558ad5d 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1738,6 +1738,8 @@ class PhaseIdealLoop : public PhaseTransform { bool clone_cmp_loadklass_down(Node* n, const Node* blk1, const Node* blk2); bool at_relevant_ctrl(Node* n, const Node* blk1, const Node* blk2); + + void update_addp_chain_base(Node* x, Node* old_base, Node* new_base); }; diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index a899f0b370f..b8f7a92c0d9 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1677,9 +1677,10 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { assert(!n_loop->is_member(get_loop(x_ctrl)), "should have moved out of loop"); register_new_node(x, x_ctrl); - // Chain of AddP: (AddP base (AddP base )) must keep the same base after sinking so: - // 1- We don't add a CastPP here when the first one is sunk so if the second one is not, their bases remain - // the same. + // Chain of AddP nodes: (AddP base (AddP base (AddP base ))) + // All AddP nodes must keep the same base after sinking so: + // 1- We don't add a CastPP here until the last one of the chain is sunk: if part of the chain is not sunk, + // their bases remain the same. // (see 2- below) assert(!x->is_AddP() || !x->in(AddPNode::Address)->is_AddP() || x->in(AddPNode::Address)->in(AddPNode::Base) == x->in(AddPNode::Base) || @@ -1704,16 +1705,10 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { register_new_node(cast, x_ctrl); } x->replace_edge(in, cast); - // Chain of AddP: - // 2- A CastPP of the base is only added now that both AddP nodes are sunk + // Chain of AddP nodes: + // 2- A CastPP of the base is only added now that all AddP nodes are sunk if (x->is_AddP() && k == AddPNode::Base) { - for (DUIterator_Fast imax, i = x->fast_outs(imax); i < imax; i++) { - Node* u = x->fast_out(i); - if (u->is_AddP() && u->in(AddPNode::Base) == n->in(AddPNode::Base)) { - _igvn.replace_input_of(u, AddPNode::Base, cast); - assert(u->find_out_with(Op_AddP) == nullptr, "more than 2 chained AddP nodes?"); - } - } + update_addp_chain_base(x, n->in(AddPNode::Base), cast); } break; } @@ -1728,6 +1723,22 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { } } +void PhaseIdealLoop::update_addp_chain_base(Node* x, Node* old_base, Node* new_base) { + ResourceMark rm; + Node_List wq; + wq.push(x); + while (wq.size() != 0) { + Node* n = wq.pop(); + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* u = n->fast_out(i); + if (u->is_AddP() && u->in(AddPNode::Base) == old_base) { + _igvn.replace_input_of(u, AddPNode::Base, new_base); + wq.push(u); + } + } + } +} + // Compute the early control of a node by following its inputs until we reach // nodes that are pinned. Then compute the LCA of the control of all pinned nodes. Node* PhaseIdealLoop::compute_early_ctrl(Node* n, Node* n_ctrl) { diff --git a/test/hotspot/jtreg/compiler/loopopts/TestSinkingMoreThan2AddPNodes.java b/test/hotspot/jtreg/compiler/loopopts/TestSinkingMoreThan2AddPNodes.java new file mode 100644 index 00000000000..42cc4c77401 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestSinkingMoreThan2AddPNodes.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8315377 + * @requires vm.compiler2.enabled + * @summary C2: assert(u->find_out_with(Op_AddP) == nullptr) failed: more than 2 chained AddP nodes? + * @library /test/lib + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestSinkingMoreThan2AddPNodes::test TestSinkingMoreThan2AddPNodes + * + */ + +import jdk.test.lib.Utils; + +public class TestSinkingMoreThan2AddPNodes { + public static void main(String[] strArr) throws Exception { + Thread t = new Thread(new Runnable() { + public void run() { + test(); + } + }); + t.setDaemon(true); + t.start(); + Thread.sleep(Utils.adjustTimeout(500)); + } + + static void test() { + double dArr[] = new double[10]; + int i4 = 5, i11, i12 = 2, iArr[] = new int[400]; + long l1; + byte by1 = 0; + short s1 = 8; + + for (int i = 0; i < iArr.length; i++) { + iArr[i] = (i % 2 == 0) ? 23 : 34; + } + + for (i11 = 10; i11 > 9; ) { + l1 = 1; + do { + try { + i4 = 6 % i4; + i12 = iArr[(int) l1]; + } catch (ArithmeticException a_e) { + } + by1 += 8; + iArr = iArr; + } while (++l1 < 11); + } + + long meth_res = i12; + } +} + From a01b3fb8e912eadd309e7036995656dd609629b2 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Wed, 6 Sep 2023 07:51:14 +0000 Subject: [PATCH 82/86] 8288660: JavaDoc should be more helpful if it doesn't recognize a tag Reviewed-by: jjg --- .../com/sun/tools/javac/api/JavacTrees.java | 8 +- .../formats/html/taglets/TagletManager.java | 19 +-- .../toolkit/resources/doclets.properties | 4 +- .../jdk/javadoc/internal/doclint/Checker.java | 11 +- .../jdk/javadoc/internal/doclint/DocLint.java | 28 +++- .../javadoc/internal/doclint/Messages.java | 19 ++- .../doclint/resources/doclint.properties | 4 +- .../doclet/testSnippetTag/TestSnippetTag.java | 4 +- .../testUknownTags/TestUnknownTags.java | 138 +++++++++++++++++- .../tools/doclint/CustomTagTest.java | 2 +- .../langtools/tools/doclint/CustomTagTest.out | 6 +- .../tools/doclint/CustomTagTestWithOption.out | 2 +- 12 files changed, 213 insertions(+), 32 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index f93119d16b7..c0dce830d9e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1174,13 +1174,17 @@ public void printMessage(Diagnostic.Kind kind, CharSequence msg, printMessage(kind, msg, ((DCTree) t).pos((DCDocComment) c), root); } + public void printMessage(Diagnostic.Kind kind, CharSequence msg) { + printMessage(kind, msg, (JCDiagnostic.DiagnosticPosition) null, null); + } + private void printMessage(Diagnostic.Kind kind, CharSequence msg, JCDiagnostic.DiagnosticPosition pos, com.sun.source.tree.CompilationUnitTree root) { JavaFileObject oldSource = null; JavaFileObject newSource = null; - newSource = root.getSourceFile(); + newSource = root == null ? null : root.getSourceFile(); if (newSource == null) { pos = null; } else { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletManager.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletManager.java index ed3727fd5bb..804704528ce 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletManager.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletManager.java @@ -64,6 +64,7 @@ import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.doclint.DocLint; import static com.sun.source.doctree.DocTree.Kind.AUTHOR; import static com.sun.source.doctree.DocTree.Kind.EXCEPTION; @@ -123,13 +124,6 @@ public class TagletManager { */ private final Set standardTags; - /** - * Keep track of standard tags in lowercase to compare for better - * error messages when a tag like {@code @docRoot} is mistakenly spelled - * lowercase {@code @docroot}. - */ - private final Set standardTagsLowercase; - /** * Keep track of overridden standard tags. */ @@ -185,7 +179,6 @@ public TagletManager(HtmlConfiguration config) { overriddenStandardTags = new HashSet<>(); potentiallyConflictingTags = new HashSet<>(); standardTags = new HashSet<>(); - standardTagsLowercase = new HashSet<>(); unseenCustomTags = new HashSet<>(); allTaglets = new LinkedHashMap<>(); this.config = config; @@ -363,10 +356,12 @@ public void checkTags(Element element, Iterable trees) { if (!allTaglets.containsKey(name)) { if (!config.isDocLintSyntaxGroupEnabled()) { var ch = utils.getCommentHelper(element); - if (standardTagsLowercase.contains(Utils.toLowerCase(name))) { - messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTagLowercase", ch.getTagName(tag)); + List suggestions = DocLint.suggestSimilar(allTaglets.keySet(), name); + if (!suggestions.isEmpty()) { + messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTagWithHint", + String.join(", ", suggestions)); // TODO: revisit after 8041488 } else { - messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTag", ch.getTagName(tag)); + messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTag"); } } continue; // unknown tag @@ -660,7 +655,6 @@ private void addStandardTaglet(Taglet taglet) { String name = taglet.getName(); allTaglets.put(name, taglet); standardTags.add(name); - standardTagsLowercase.add(Utils.toLowerCase(name)); } private void addStandardTaglet(Taglet taglet, DocTree.Kind alias) { @@ -668,7 +662,6 @@ private void addStandardTaglet(Taglet taglet, DocTree.Kind alias) { String name = alias.tagName; allTaglets.put(name, taglet); standardTags.add(name); - standardTagsLowercase.add(Utils.toLowerCase(name)); } public boolean isKnownCustomTag(String tagName) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index 41a0394579a..ddc639133ff 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -116,8 +116,8 @@ doclet.Since=Since: doclet.Throws=Throws: doclet.Version=Version: doclet.Factory=Factory: -doclet.UnknownTag={0} is an unknown tag. -doclet.UnknownTagLowercase={0} is an unknown tag -- same as a known tag except for case. +doclet.UnknownTag=unknown tag. Unregistered custom tag? +doclet.UnknownTagWithHint=unknown tag. Mistyped @{0} or an unregistered custom tag? doclet.inheritDocBadSupertype=cannot find the overridden method doclet.inheritDocWithinInappropriateTag=@inheritDoc cannot be used within this tag doclet.inheritDocNoDoc=overridden methods do not document exception type {0} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index a0fad5a0e7d..b097866a2d8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -1147,8 +1147,15 @@ private void checkUnknownTag(DocTree tree, String tagName) { || k == DocTree.Kind.UNKNOWN_INLINE_TAG; assert !getStandardTags().contains(tagName); // report an unknown tag only if custom tags are set, see 8314213 - if (env.customTags != null && !env.customTags.contains(tagName)) - env.messages.error(SYNTAX, tree, "dc.tag.unknown", tagName); + if (env.customTags != null && !env.customTags.contains(tagName)) { + var suggestions = DocLint.suggestSimilar(env.customTags, tagName); + if (suggestions.isEmpty()) { + env.messages.error(SYNTAX, tree, "dc.unknown.javadoc.tag"); + } else { + env.messages.error(SYNTAX, tree, "dc.unknown.javadoc.tag.with.hint", + String.join(", ", suggestions)); // TODO: revisit after 8041488 + } + } } private Set getStandardTags() { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java index f6c6df22c63..0139f95b74b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.Queue; @@ -61,6 +63,7 @@ import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; +import com.sun.tools.javac.util.StringUtils.DamerauLevenshteinDistance; /** * Multi-function entry point for the doc check utility. @@ -373,6 +376,29 @@ public void reportStats(PrintWriter out) { Env env; Checker checker; + public static List suggestSimilar(Collection knownTags, String unknownTag) { + final double MIN_SIMILARITY = 2.0 / 3; + record Pair(String tag, double similarity) { } + return knownTags.stream() + .distinct() // filter duplicates in known, otherwise they will result in duplicates in suggested + .map(t -> new Pair(t, similarity(t, unknownTag))) + .sorted(Comparator.comparingDouble(Pair::similarity).reversed() /* more similar first */) + // .peek(p -> System.out.printf("%.3f, (%s ~ %s)%n", p.similarity, p.tag, unknownTag)) // debug + .takeWhile(p -> Double.compare(p.similarity, MIN_SIMILARITY) >= 0) + .map(Pair::tag) + .toList(); + } + + // a value in [0, 1] range: the closer the value is to 1, the more similar + // the strings are + private static double similarity(String a, String b) { + // Normalize the distance so that similarity between "x" and "y" is + // less than that of "ax" and "ay". Use the greater of two lengths + // as normalizer, as it's an upper bound for the distance. + return 1.0 - ((double) DamerauLevenshteinDistance.of(a, b)) + / Math.max(a.length(), b.length()); + } + public boolean isValidOption(String opt) { if (opt.equals(XMSGS_OPTION)) return true; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Messages.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Messages.java index 2d3be96d7f2..7d38e511d03 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Messages.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Messages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import com.sun.source.doctree.DocTree; import com.sun.source.tree.Tree; +import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.util.StringUtils; import jdk.javadoc.internal.doclint.Env.AccessKind; @@ -96,6 +97,10 @@ void warning(Group group, DocTree tree, String code, Object... args) { report(group, Diagnostic.Kind.WARNING, tree, code, args); } + void note(Group group, String code, Object... args) { + report(group, Diagnostic.Kind.NOTE, code, args); + } + void setOptions(String opts) { options.setOptions(opts); } @@ -112,6 +117,18 @@ void reportStats(PrintWriter out) { stats.report(out); } + protected void report(Group group, Diagnostic.Kind dkind, String code, Object... args) { + if (options.isEnabled(group, env.currAccess)) { + if (dkind == Diagnostic.Kind.WARNING && env.suppressWarnings(group)) { + return; + } + String msg = (code == null) ? (String) args[0] : localize(code, args); + ((JavacTrees) env.trees).printMessage(dkind, msg); + + stats.record(group, dkind, code); + } + } + protected void report(Group group, Diagnostic.Kind dkind, DocTree tree, String code, Object... args) { if (options.isEnabled(group, env.currAccess)) { if (dkind == Diagnostic.Kind.WARNING && env.suppressWarnings(group)) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/resources/doclint.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/resources/doclint.properties index f199b181c37..5b70ddb03ae 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/resources/doclint.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/resources/doclint.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -84,6 +84,8 @@ dc.tag.p.in.pre= unexpected use of

inside

 element
 dc.tag.requires.heading = heading not found for 
 dc.tag.self.closing = self-closing element not allowed
 dc.tag.start.unmatched = end tag missing: 
+dc.unknown.javadoc.tag = unknown tag. Unregistered custom tag?
+dc.unknown.javadoc.tag.with.hint = unknown tag. Mistyped @{0} or an unregistered custom tag?
 dc.tag.unknown = unknown tag: {0}
 dc.tag.not.supported.html5 = tag not supported in HTML5: {0}
 dc.text.not.allowed = text not allowed in <{0}> element
diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java
index 70b0397c121..b7b54dfdb26 100644
--- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java
+++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -664,7 +664,7 @@ public void testNegativeInlineTagUnknownTag(Path base) throws IOException {
                 "-sourcepath", srcDir.toString(),
                 "pkg");
         checkExit(Exit.ERROR);
-        long actual = Pattern.compile("error: unknown tag: snippet:")
+        long actual = Pattern.compile("error: unknown tag. Mistyped @snippet")
                 .matcher(getOutput(Output.OUT)).results().count();
         checking("Number of errors");
         int expected = unknownTags.size();
diff --git a/test/langtools/jdk/javadoc/doclet/testUknownTags/TestUnknownTags.java b/test/langtools/jdk/javadoc/doclet/testUknownTags/TestUnknownTags.java
index d036e605d56..ea5cb9b74b3 100644
--- a/test/langtools/jdk/javadoc/doclet/testUknownTags/TestUnknownTags.java
+++ b/test/langtools/jdk/javadoc/doclet/testUknownTags/TestUnknownTags.java
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8314448
+ * @bug 8314448 8288660
  * @library /tools/lib ../../lib
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -33,6 +33,9 @@
  */
 
 import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.regex.Pattern;
 
 import javadoc.tester.JavadocTester;
 import toolbox.ToolBox;
@@ -68,7 +71,7 @@ public class MyClass { }
                     "x");
             new OutputChecker(Output.OUT)
                     .setExpectFound(true)
-                    .checkUnique("unknown tag");
+                    .checkUnique(Pattern.compile("unknown tag."));
         }
         // DocLint is default
         javadoc("-d", base.resolve("out").toString(),
@@ -76,7 +79,7 @@ public class MyClass { }
                 "x");
         new OutputChecker(Output.OUT)
                 .setExpectFound(true)
-                .checkUnique("unknown tag");
+                .checkUnique(Pattern.compile("unknown tag."));
     }
 
     // Disabled simple tags are treated as known tags, but aren't checked
@@ -103,4 +106,133 @@ public class MyClass extends RuntimeException { }
         checkOutput(Output.OUT, false, "Tag @myDisabledTag cannot be used in class documentation");
         checkOutput(Output.OUT, true, "Tag @myEnabledTag cannot be used in class documentation");
     }
+
+    // This tests two assertions:
+    //
+    //   - the "helpful note" is output exactly once,
+    //   - some typos have fix suggestions, and
+    //   - there's no difference between inline and block tags as
+    //     far as the diagnostic output is concerned
+    @Test
+    public void testSimilarTags(Path base) throws Exception {
+        var src = base.resolve("src");
+        // put some tags as inline in the main description, so that they are
+        // not parsed as contents of the immediately preceding unknown
+        // block tags
+        tb.writeJavaFiles(src, """
+                package x;
+
+                /**
+                 * {@cod}
+                 * {@codejdk.net.hosts.file}
+                 * {@coe}
+                 * {@cpde}
+                 * {@ocde}
+                 * {@ode}
+                 *
+                 * @auther
+                 *
+                 * @Depricated
+                 * @deprecation
+                 *
+                 * @DocRoot
+                 * @dccRoot
+                 * @docroot
+                 *
+                 * @ecception
+                 * @excception
+                 * @exceptbion
+                 * @exceptino
+                 * @exceptions
+                 * @exceptoin
+                 * @execption
+                 *
+                 * @implnote
+                 *
+                 * @inheritdoc
+                 * @inherotDoc
+                 * @inheretdoc
+                 * @inhertitDoc
+                 *
+                 * @jvm
+                 * @jmvs
+                 *
+                 * @Link
+                 * @linK
+                 * @linbk
+                 * @lini
+                 * @linke
+                 * @linked
+                 *
+                 * @linkplan
+                 *
+                 * @params
+                 * @pararm
+                 * @parasm
+                 * @parem
+                 * @parm
+                 * @parma
+                 * @praam
+                 * @prarm
+                 *
+                 * @Return
+                 * @eturn
+                 * @result
+                 * @retrun
+                 * @retuen
+                 * @retun
+                 * @retunr
+                 * @retur
+                 * @returns
+                 * @returnss
+                 * @retursn
+                 * @rturn
+                 *
+                 * @See
+                 * @gsee
+                 *
+                 * @serialdata
+                 *
+                 * @sinc
+                 * @sine
+                 *
+                 * @systemproperty
+                 *
+                 * @thows
+                 * @thrown
+                 * @throwss
+                 */
+                public class MyClass { }
+                """);
+        // don't check exit status: we don't care if it's an error or warning
+
+        // DocLint is explicit
+        int i = 0;
+        for (var check : new String[]{":all", ":none", "", null}) {
+            var outputDir = "out-DocLint-" + i++; // use separate output directories
+
+            var args = new ArrayList();
+            if (check != null) // check == null means DocLint is default
+                args.add("-Xdoclint" + check);
+            args.addAll(Arrays.asList(
+                    "-d", base.resolve(outputDir).toString(),
+                    "-tag", "apiNote:a:API Note:",
+                    "-tag", "implSpec:a:Implementation Requirements:",
+                    "-tag", "implNote:a:Implementation Note:",
+                    "-tag", "jls:a:JLS", // this tag isn't exactly that of JDK, for simplicity reasons
+                    "-tag", "jvms:a:JVMS", // this tag isn't exactly that of JDK, for simplicity reasons
+                    "--source-path", src.toString(),
+                    "x"));
+
+            javadoc(args.toArray(new String[]{}));
+
+            new OutputChecker(Output.OUT)
+                    .setExpectFound(true)
+                    .setExpectOrdered(false)
+                    .check("author", "code", "deprecated", "docRoot",
+                            "exception", "implNote", "inheritDoc", "jvms",
+                            "link", "linkplain", "param", "return", "see",
+                            "serialData", "since", "systemProperty", "throws");
+        }
+    }
 }
diff --git a/test/langtools/tools/doclint/CustomTagTest.java b/test/langtools/tools/doclint/CustomTagTest.java
index 416839807c6..7ced9d71568 100644
--- a/test/langtools/tools/doclint/CustomTagTest.java
+++ b/test/langtools/tools/doclint/CustomTagTest.java
@@ -1,6 +1,6 @@
 /*
  * @test /nodynamiccopyright/
- * @bug 8006248 8028318
+ * @bug 8006248 8028318 8288660
  * @summary DocLint should report unknown tags
  * @modules jdk.javadoc/jdk.javadoc.internal.doclint
  * @build DocLintTester
diff --git a/test/langtools/tools/doclint/CustomTagTest.out b/test/langtools/tools/doclint/CustomTagTest.out
index 729a550e426..6ce0367cccc 100644
--- a/test/langtools/tools/doclint/CustomTagTest.out
+++ b/test/langtools/tools/doclint/CustomTagTest.out
@@ -1,10 +1,10 @@
-CustomTagTest.java:15: error: unknown tag: customTag
+CustomTagTest.java:15: error: unknown tag. Unregistered custom tag?
  * @customTag Text for a custom tag.
    ^
-CustomTagTest.java:16: error: unknown tag: custom.tag
+CustomTagTest.java:16: error: unknown tag. Unregistered custom tag?
  * @custom.tag Text for another custom tag.
    ^
-CustomTagTest.java:17: error: unknown tag: unknownTag
+CustomTagTest.java:17: error: unknown tag. Unregistered custom tag?
  * @unknownTag Text for an unknown tag.
    ^
 3 errors
diff --git a/test/langtools/tools/doclint/CustomTagTestWithOption.out b/test/langtools/tools/doclint/CustomTagTestWithOption.out
index 340f5a8a440..4b5a1706d31 100644
--- a/test/langtools/tools/doclint/CustomTagTestWithOption.out
+++ b/test/langtools/tools/doclint/CustomTagTestWithOption.out
@@ -1,4 +1,4 @@
-CustomTagTest.java:17: error: unknown tag: unknownTag
+CustomTagTest.java:17: error: unknown tag. Unregistered custom tag?
  * @unknownTag Text for an unknown tag.
    ^
 1 error

From f6c203e61620dc130b8c366f824e6923fca52e82 Mon Sep 17 00:00:00 2001
From: Martin Doerr 
Date: Wed, 6 Sep 2023 08:26:48 +0000
Subject: [PATCH 83/86] 8314949: linux PPC64 Big Endian: Implementation of
 Foreign Function & Memory API

Reviewed-by: mcimadamore, jvernee
---
 src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp    |   2 +-
 .../classes/jdk/internal/foreign/CABI.java    |   5 +
 .../internal/foreign/abi/AbstractLinker.java  |   4 +-
 .../jdk/internal/foreign/abi/Binding.java     | 109 +++++++++++++++++-
 .../foreign/abi/BindingSpecializer.java       |  23 ++++
 .../foreign/abi/CallingSequenceBuilder.java   |   6 +
 .../jdk/internal/foreign/abi/SharedUtils.java |   2 +
 .../foreign/abi/ppc64/ABIv1CallArranger.java  |  37 ++++++
 .../foreign/abi/ppc64/ABIv2CallArranger.java  |   8 +-
 .../foreign/abi/ppc64/CallArranger.java       |  58 ++++++++--
 .../abi/ppc64/linux/LinuxPPC64Linker.java     |  65 +++++++++++
 11 files changed, 303 insertions(+), 16 deletions(-)
 create mode 100644 src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv1CallArranger.java
 create mode 100644 src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.java

diff --git a/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp b/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp
index 6e10aacaad1..9e689bccab1 100644
--- a/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp
+++ b/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp
@@ -47,7 +47,7 @@ bool ABIDescriptor::is_volatile_reg(FloatRegister reg) const {
 }
 
 bool ForeignGlobals::is_foreign_linker_supported() {
-#ifdef ABI_ELFv2
+#ifdef LINUX
   return true;
 #else
   return false;
diff --git a/src/java.base/share/classes/jdk/internal/foreign/CABI.java b/src/java.base/share/classes/jdk/internal/foreign/CABI.java
index d376a196333..5f8a30017c2 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/CABI.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/CABI.java
@@ -39,6 +39,7 @@ public enum CABI {
     LINUX_AARCH_64,
     MAC_OS_AARCH_64,
     WIN_AARCH_64,
+    LINUX_PPC_64,
     LINUX_PPC_64_LE,
     LINUX_RISCV_64,
     LINUX_S390,
@@ -74,6 +75,10 @@ private static CABI computeCurrent() {
                     // The Linux ABI follows the standard AAPCS ABI
                     return LINUX_AARCH_64;
                 }
+            } else if (arch.equals("ppc64")) {
+                if (OperatingSystem.isLinux()) {
+                    return LINUX_PPC_64;
+                }
             } else if (arch.equals("ppc64le")) {
                 if (OperatingSystem.isLinux()) {
                     return LINUX_PPC_64_LE;
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java
index 8a322cdcf7a..e0c5c5575fc 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java
@@ -30,6 +30,7 @@
 import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
 import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker;
 import jdk.internal.foreign.abi.fallback.FallbackLinker;
+import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64Linker;
 import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker;
 import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
 import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker;
@@ -60,7 +61,8 @@
 
 public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker,
                                                                       SysVx64Linker, WindowsAArch64Linker,
-                                                                      Windowsx64Linker, LinuxPPC64leLinker,
+                                                                      Windowsx64Linker,
+                                                                      LinuxPPC64Linker, LinuxPPC64leLinker,
                                                                       LinuxRISCV64Linker, LinuxS390Linker,
                                                                       FallbackLinker {
 
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java b/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java
index 008c6683528..da288d51406 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java
@@ -276,6 +276,18 @@ static Dup dup() {
         return Dup.INSTANCE;
     }
 
+    static ShiftLeft shiftLeft(int shiftAmount) {
+        if (shiftAmount <= 0)
+            throw new IllegalArgumentException("shiftAmount must be positive");
+        return new ShiftLeft(shiftAmount);
+    }
+
+    static ShiftRight shiftRight(int shiftAmount) {
+        if (shiftAmount <= 0)
+            throw new IllegalArgumentException("shiftAmount must be positive");
+        return new ShiftRight(shiftAmount);
+    }
+
     static Binding cast(Class fromType, Class toType) {
         if (fromType == int.class) {
             if (toType == boolean.class) {
@@ -286,6 +298,8 @@ static Binding cast(Class fromType, Class toType) {
                 return Cast.INT_TO_SHORT;
             } else if (toType == char.class) {
                 return Cast.INT_TO_CHAR;
+            } else if (toType == long.class) {
+                return Cast.INT_TO_LONG;
             }
         } else if (toType == int.class) {
             if (fromType == boolean.class) {
@@ -296,6 +310,24 @@ static Binding cast(Class fromType, Class toType) {
                 return Cast.SHORT_TO_INT;
             } else if (fromType == char.class) {
                 return Cast.CHAR_TO_INT;
+            } else if (fromType == long.class) {
+                return Cast.LONG_TO_INT;
+            }
+        } else if (fromType == long.class) {
+            if (toType == byte.class) {
+                return Cast.LONG_TO_BYTE;
+            } else if (toType == short.class) {
+                return Cast.LONG_TO_SHORT;
+            } else if (toType == char.class) {
+                return Cast.LONG_TO_CHAR;
+            }
+        } else if (toType == long.class) {
+            if (fromType == byte.class) {
+                return Cast.BYTE_TO_LONG;
+            } else if (fromType == short.class) {
+                return Cast.SHORT_TO_LONG;
+            } else if (fromType == char.class) {
+                return Cast.CHAR_TO_LONG;
             }
         }
         throw new IllegalArgumentException("Unknown conversion: " + fromType + " -> " + toType);
@@ -387,6 +419,24 @@ public Binding.Builder dup() {
             return this;
         }
 
+        // Converts to long if needed then shifts left by the given number of Bytes.
+        public Binding.Builder shiftLeft(int shiftAmount, Class type) {
+            if (type != long.class) {
+                bindings.add(Binding.cast(type, long.class));
+            }
+            bindings.add(Binding.shiftLeft(shiftAmount));
+            return this;
+        }
+
+        // Shifts right by the given number of Bytes then converts from long if needed.
+        public Binding.Builder shiftRight(int shiftAmount, Class type) {
+            bindings.add(Binding.shiftRight(shiftAmount));
+            if (type != long.class) {
+                bindings.add(Binding.cast(long.class, type));
+            }
+            return this;
+        }
+
         public List build() {
             return List.copyOf(bindings);
         }
@@ -670,6 +720,52 @@ public void interpret(Deque stack, StoreFunc storeFunc,
         }
     }
 
+    /**
+     * ShiftLeft([shiftAmount])
+     *   Shifts the Bytes on the top of the operand stack (64 bit unsigned).
+     *   Shifts left by the given number of Bytes.
+     */
+    record ShiftLeft(int shiftAmount) implements Binding {
+
+        @Override
+        public void verify(Deque> stack) {
+            Class last = stack.pop();
+            SharedUtils.checkType(last, long.class);
+            stack.push(long.class);
+        }
+
+        @Override
+        public void interpret(Deque stack, StoreFunc storeFunc,
+                              LoadFunc loadFunc, SegmentAllocator allocator) {
+            long l = (long) stack.pop();
+            l <<= (shiftAmount * Byte.SIZE);
+            stack.push(l);
+        }
+    }
+
+    /**
+     * ShiftRight([shiftAmount])
+     *   Shifts the Bytes on the top of the operand stack (64 bit unsigned).
+     *   Shifts right by the given number of Bytes.
+     */
+    record ShiftRight(int shiftAmount) implements Binding {
+
+        @Override
+        public void verify(Deque> stack) {
+            Class last = stack.pop();
+            SharedUtils.checkType(last, long.class);
+            stack.push(long.class);
+        }
+
+        @Override
+        public void interpret(Deque stack, StoreFunc storeFunc,
+                              LoadFunc loadFunc, SegmentAllocator allocator) {
+            long l = (long) stack.pop();
+            l >>>= (shiftAmount * Byte.SIZE);
+            stack.push(l);
+        }
+    }
+
     /**
      * CAST([fromType], [toType])
      *   Pop a [fromType] from the stack, convert it to [toType], and push the resulting
@@ -690,10 +786,21 @@ public void interpret(Deque stack, StoreFunc storeFunc,
         INT_TO_BYTE(int.class, byte.class),
         INT_TO_CHAR(int.class, char.class),
         INT_TO_SHORT(int.class, short.class),
+        INT_TO_LONG(int.class, long.class),
+
         BOOLEAN_TO_INT(boolean.class, int.class),
         BYTE_TO_INT(byte.class, int.class),
         CHAR_TO_INT(char.class, int.class),
-        SHORT_TO_INT(short.class, int.class);
+        SHORT_TO_INT(short.class, int.class),
+        LONG_TO_INT(long.class, int.class),
+
+        LONG_TO_BYTE(long.class, byte.class),
+        LONG_TO_SHORT(long.class, short.class),
+        LONG_TO_CHAR(long.class, char.class),
+
+        BYTE_TO_LONG(byte.class, long.class),
+        SHORT_TO_LONG(short.class, long.class),
+        CHAR_TO_LONG(char.class, long.class);
 
         private final Class fromType;
         private final Class toType;
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java
index b447bd31b48..3855a49c389 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java
@@ -39,6 +39,8 @@
 import jdk.internal.foreign.abi.Binding.Cast;
 import jdk.internal.foreign.abi.Binding.Copy;
 import jdk.internal.foreign.abi.Binding.Dup;
+import jdk.internal.foreign.abi.Binding.ShiftLeft;
+import jdk.internal.foreign.abi.Binding.ShiftRight;
 import jdk.internal.foreign.abi.Binding.UnboxAddress;
 import jdk.internal.foreign.abi.Binding.VMLoad;
 import jdk.internal.foreign.abi.Binding.VMStore;
@@ -463,6 +465,8 @@ private void doBindings(List bindings) {
                 case BoxAddress boxAddress   -> emitBoxAddress(boxAddress);
                 case UnboxAddress unused     -> emitUnboxAddress();
                 case Dup unused              -> emitDupBinding();
+                case ShiftLeft shiftLeft     -> emitShiftLeft(shiftLeft);
+                case ShiftRight shiftRight   -> emitShiftRight(shiftRight);
                 case Cast cast               -> emitCast(cast);
             }
         }
@@ -725,6 +729,20 @@ private void emitDupBinding() {
         pushType(dupType);
     }
 
+    private void emitShiftLeft(ShiftLeft shiftLeft) {
+        popType(long.class);
+        cb.constantInstruction(shiftLeft.shiftAmount() * Byte.SIZE);
+        cb.lshl();
+        pushType(long.class);
+    }
+
+    private void emitShiftRight(ShiftRight shiftRight) {
+        popType(long.class);
+        cb.constantInstruction(shiftRight.shiftAmount() * Byte.SIZE);
+        cb.lushr();
+        pushType(long.class);
+    }
+
     private void emitCast(Cast cast) {
         Class fromType = cast.fromType();
         Class toType = cast.toType();
@@ -744,6 +762,11 @@ private void emitCast(Cast cast) {
             case INT_TO_BYTE -> cb.i2b();
             case INT_TO_CHAR -> cb.i2c();
             case INT_TO_SHORT -> cb.i2s();
+            case BYTE_TO_LONG, CHAR_TO_LONG, SHORT_TO_LONG, INT_TO_LONG -> cb.i2l();
+            case LONG_TO_BYTE -> { cb.l2i(); cb.i2b(); }
+            case LONG_TO_SHORT -> { cb.l2i(); cb.i2s(); }
+            case LONG_TO_CHAR -> { cb.l2i(); cb.i2c(); }
+            case LONG_TO_INT -> cb.l2i();
             case BOOLEAN_TO_INT, BYTE_TO_INT, CHAR_TO_INT, SHORT_TO_INT -> {
                 // no-op in bytecode
             }
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java
index 65f08b75a39..2683dc4542f 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java
@@ -32,6 +32,8 @@
 import jdk.internal.foreign.abi.Binding.Cast;
 import jdk.internal.foreign.abi.Binding.Copy;
 import jdk.internal.foreign.abi.Binding.Dup;
+import jdk.internal.foreign.abi.Binding.ShiftLeft;
+import jdk.internal.foreign.abi.Binding.ShiftRight;
 import jdk.internal.foreign.abi.Binding.UnboxAddress;
 import jdk.internal.foreign.abi.Binding.VMLoad;
 import jdk.internal.foreign.abi.Binding.VMStore;
@@ -220,6 +222,8 @@ static boolean isUnbox(Binding binding) {
             case Copy         unused -> true;
             case UnboxAddress unused -> true;
             case Dup          unused -> true;
+            case ShiftLeft    unused -> true;
+            case ShiftRight   unused -> true;
             case Cast         unused -> true;
 
             case VMLoad       unused -> false;
@@ -254,6 +258,8 @@ static boolean isBox(Binding binding) {
             case Allocate     unused -> true;
             case BoxAddress   unused -> true;
             case Dup          unused -> true;
+            case ShiftLeft    unused -> true;
+            case ShiftRight   unused -> true;
             case Cast         unused -> true;
 
             case VMStore      unused -> false;
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java
index 92d10a1dbdf..24892a50b0f 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java
@@ -33,6 +33,7 @@
 import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
 import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker;
 import jdk.internal.foreign.abi.fallback.FallbackLinker;
+import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64Linker;
 import jdk.internal.foreign.abi.ppc64.linux.LinuxPPC64leLinker;
 import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64Linker;
 import jdk.internal.foreign.abi.s390.linux.LinuxS390Linker;
@@ -241,6 +242,7 @@ public static Linker getSystemLinker() {
             case LINUX_AARCH_64 -> LinuxAArch64Linker.getInstance();
             case MAC_OS_AARCH_64 -> MacOsAArch64Linker.getInstance();
             case WIN_AARCH_64 -> WindowsAArch64Linker.getInstance();
+            case LINUX_PPC_64 -> LinuxPPC64Linker.getInstance();
             case LINUX_PPC_64_LE -> LinuxPPC64leLinker.getInstance();
             case LINUX_RISCV_64 -> LinuxRISCV64Linker.getInstance();
             case LINUX_S390 -> LinuxS390Linker.getInstance();
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv1CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv1CallArranger.java
new file mode 100644
index 00000000000..a32d4796337
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv1CallArranger.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023 SAP SE. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 jdk.internal.foreign.abi.ppc64;
+
+/**
+ * PPC64 CallArranger specialized for ABI v1.
+ */
+public class ABIv1CallArranger extends CallArranger {
+
+    @Override
+    protected boolean useABIv2() {
+        return false;
+    }
+}
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv2CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv2CallArranger.java
index c31204e8671..2a13daed0bd 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv2CallArranger.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/ABIv2CallArranger.java
@@ -25,11 +25,13 @@
  */
 package jdk.internal.foreign.abi.ppc64;
 
-import jdk.internal.foreign.abi.ppc64.CallArranger;
-
 /**
  * PPC64 CallArranger specialized for ABI v2.
  */
 public class ABIv2CallArranger extends CallArranger {
-    // Currently no specific content, but CallArranger detects usage of ABIv2 for this class.
+
+    @Override
+    protected boolean useABIv2() {
+        return true;
+    }
 }
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java
index 6c26d67ae99..53adf5c9028 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java
@@ -35,7 +35,6 @@
 import jdk.internal.foreign.abi.LinkerOptions;
 import jdk.internal.foreign.abi.SharedUtils;
 import jdk.internal.foreign.abi.VMStorage;
-import jdk.internal.foreign.abi.ppc64.ABIv2CallArranger;
 
 import java.lang.foreign.AddressLayout;
 import java.lang.foreign.FunctionDescriptor;
@@ -62,7 +61,7 @@
  * public constants CallArranger.ABIv1/2.
  */
 public abstract class CallArranger {
-    final boolean useABIv2 = (this instanceof ABIv2CallArranger);
+    final boolean useABIv2 = useABIv2();
 
     private static final int STACK_SLOT_SIZE = 8;
     private static final int MAX_COPY_SIZE = 8;
@@ -90,8 +89,14 @@ private record HfaRegs(VMStorage[] first, VMStorage[] second) {}
 
     protected CallArranger() {}
 
+    public static final CallArranger ABIv1 = new ABIv1CallArranger();
     public static final CallArranger ABIv2 = new ABIv2CallArranger();
 
+    /**
+     * Select ABI version
+     */
+    protected abstract boolean useABIv2();
+
     public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall) {
         return getBindings(mt, cDesc, forUpcall, LinkerOptions.empty());
     }
@@ -214,11 +219,23 @@ VMStorage nextStorage(int type, boolean is32Bit) {
             return reg;
         }
 
+        /* The struct is split into 8-byte chunks, and those chunks are passed in registers or on the stack.
+           ABIv1 requires shifting if the struct occupies more than one 8-byte chunk and the last one is not full.
+           Here's an example for passing an 11 byte struct with ABIv1:
+        offset         : 0 .... 32 ..... 64 ..... 96 .... 128
+        values         : xxxxxxxx|yyyyyyyy|zzzzzz??|????????   (can't touch bits 96..128)
+        Load into int  :                  V        +--------+
+                                          |                 |
+                                          +--------+        |
+                                                   V        V
+        In register    :                   ????????|??zzzzzz   (LSBs are zz...z)
+        Shift left     :                   zzzzzz00|00000000   (LSBs are 00...0)
+        Write long     :                  V                 V
+        Result         : xxxxxxxx|yyyyyyyy|zzzzzz00|00000000
+        */
+
         // Regular struct, no HFA.
         VMStorage[] structAlloc(MemoryLayout layout) {
-            // TODO: Big Endian can't pass partially used slots correctly in some cases with:
-            // !useABIv2 && layout.byteSize() > 8 && layout.byteSize() % 8 != 0
-
             // Allocate enough gp slots (regs and stack) such that the struct fits in them.
             int numChunks = (int) Utils.alignUp(layout.byteSize(), MAX_COPY_SIZE) / MAX_COPY_SIZE;
             VMStorage[] result = new VMStorage[numChunks];
@@ -332,16 +349,26 @@ List getBindings(Class carrier, MemoryLayout layout) {
                 case STRUCT_REGISTER -> {
                     assert carrier == MemorySegment.class;
                     VMStorage[] regs = storageCalculator.structAlloc(layout);
+                    final boolean isLargeABIv1Struct = !useABIv2 && layout.byteSize() > MAX_COPY_SIZE;
                     long offset = 0;
                     for (VMStorage storage : regs) {
                         // Last slot may be partly used.
                         final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE);
+                        int shiftAmount = 0;
                         Class type = SharedUtils.primitiveCarrierForSize(size, false);
                         if (offset + size < layout.byteSize()) {
                             bindings.dup();
+                        } else if (isLargeABIv1Struct) {
+                            // Last slot requires shift.
+                            shiftAmount = MAX_COPY_SIZE - (int) size;
+                        }
+                        bindings.bufferLoad(offset, type, (int) size);
+                        if (shiftAmount != 0) {
+                            bindings.shiftLeft(shiftAmount, type)
+                                    .vmStore(storage, long.class);
+                        } else {
+                            bindings.vmStore(storage, type);
                         }
-                        bindings.bufferLoad(offset, type, (int) size)
-                                .vmStore(storage, type);
                         offset += size;
                     }
                 }
@@ -410,14 +437,25 @@ List getBindings(Class carrier, MemoryLayout layout) {
                     assert carrier == MemorySegment.class;
                     bindings.allocate(layout);
                     VMStorage[] regs = storageCalculator.structAlloc(layout);
+                    final boolean isLargeABIv1Struct = !useABIv2 && layout.byteSize() > MAX_COPY_SIZE;
                     long offset = 0;
                     for (VMStorage storage : regs) {
                         // Last slot may be partly used.
                         final long size = Math.min(layout.byteSize() - offset, MAX_COPY_SIZE);
+                        int shiftAmount = 0;
                         Class type = SharedUtils.primitiveCarrierForSize(size, false);
-                        bindings.dup()
-                                .vmLoad(storage, type)
-                                .bufferStore(offset, type, (int) size);
+                        if (isLargeABIv1Struct && offset + size >= layout.byteSize()) {
+                            // Last slot requires shift.
+                            shiftAmount = MAX_COPY_SIZE - (int) size;
+                        }
+                        bindings.dup();
+                        if (shiftAmount != 0) {
+                            bindings.vmLoad(storage, long.class)
+                                    .shiftRight(shiftAmount, type);
+                        } else {
+                            bindings.vmLoad(storage, type);
+                        }
+                        bindings.bufferStore(offset, type, (int) size);
                         offset += size;
                     }
                 }
diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.java
new file mode 100644
index 00000000000..150687d4078
--- /dev/null
+++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/linux/LinuxPPC64Linker.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023 SAP SE. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 jdk.internal.foreign.abi.ppc64.linux;
+
+import jdk.internal.foreign.abi.AbstractLinker;
+import jdk.internal.foreign.abi.LinkerOptions;
+import jdk.internal.foreign.abi.ppc64.CallArranger;
+
+import java.lang.foreign.FunctionDescriptor;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+import java.nio.ByteOrder;
+
+public final class LinuxPPC64Linker extends AbstractLinker {
+
+    public static LinuxPPC64Linker getInstance() {
+        final class Holder {
+            private static final LinuxPPC64Linker INSTANCE = new LinuxPPC64Linker();
+        }
+
+        return Holder.INSTANCE;
+    }
+
+    private LinuxPPC64Linker() {
+        // Ensure there is only one instance
+    }
+
+    @Override
+    protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDescriptor function, LinkerOptions options) {
+        return CallArranger.ABIv1.arrangeDowncall(inferredMethodType, function, options);
+    }
+
+    @Override
+    protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
+        return CallArranger.ABIv1.arrangeUpcall(targetType, function, options);
+    }
+
+    @Override
+    protected ByteOrder linkerByteOrder() {
+        return ByteOrder.BIG_ENDIAN;
+    }
+}

From cfc148930b6ace3e3ee298d7ac82aefbc652d447 Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev 
Date: Wed, 6 Sep 2023 08:27:11 +0000
Subject: [PATCH 84/86] 8315579: SPARC64 builds are broken after JDK-8304913

Reviewed-by: rriggs, phh
---
 .../share/classes/jdk/internal/util/Architecture.java | 11 ++++++++++-
 .../jdk/internal/util/PlatformProps.java.template     |  1 +
 test/jdk/jdk/internal/util/ArchTest.java              |  2 ++
 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/java.base/share/classes/jdk/internal/util/Architecture.java b/src/java.base/share/classes/jdk/internal/util/Architecture.java
index e0c16b655f9..1c5cb36d7e2 100644
--- a/src/java.base/share/classes/jdk/internal/util/Architecture.java
+++ b/src/java.base/share/classes/jdk/internal/util/Architecture.java
@@ -52,7 +52,8 @@ public enum Architecture {
     PPC64(64, ByteOrder.BIG_ENDIAN),
     PPC64LE(64, ByteOrder.LITTLE_ENDIAN),
     MIPSEL(32, ByteOrder.LITTLE_ENDIAN),
-    MIPS64EL(64, ByteOrder.LITTLE_ENDIAN)
+    MIPS64EL(64, ByteOrder.LITTLE_ENDIAN),
+    SPARCV9(64, ByteOrder.BIG_ENDIAN),
     ;
 
     private final int addrSize;
@@ -202,6 +203,14 @@ public static boolean isMIPS64EL() {
         return PlatformProps.TARGET_ARCH_IS_MIPS64EL;
     }
 
+    /**
+     * {@return {@code true} if the current architecture is SPARCV9}
+     */
+    @ForceInline
+    public static boolean isSPARCV9() {
+        return PlatformProps.TARGET_ARCH_IS_SPARCV9;
+    }
+
     /**
      * {@return the current architecture}
      */
diff --git a/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template b/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template
index d5f0b601bc8..d4d300322a4 100644
--- a/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template
+++ b/src/java.base/share/classes/jdk/internal/util/PlatformProps.java.template
@@ -63,4 +63,5 @@ class PlatformProps {
     static final boolean TARGET_ARCH_IS_PPC64LE = "@@OPENJDK_TARGET_CPU@@" == "ppc64le";
     static final boolean TARGET_ARCH_IS_MIPSEL  = "@@OPENJDK_TARGET_CPU@@" == "mipsel";
     static final boolean TARGET_ARCH_IS_MIPS64EL= "@@OPENJDK_TARGET_CPU@@" == "mips64el";
+    static final boolean TARGET_ARCH_IS_SPARCV9 = "@@OPENJDK_TARGET_CPU@@" == "sparcv9";
 }
diff --git a/test/jdk/jdk/internal/util/ArchTest.java b/test/jdk/jdk/internal/util/ArchTest.java
index 281721a7bbf..f75b2bb8801 100644
--- a/test/jdk/jdk/internal/util/ArchTest.java
+++ b/test/jdk/jdk/internal/util/ArchTest.java
@@ -39,6 +39,7 @@
 import static jdk.internal.util.Architecture.X86;
 import static jdk.internal.util.Architecture.MIPSEL;
 import static jdk.internal.util.Architecture.MIPS64EL;
+import static jdk.internal.util.Architecture.SPARCV9;
 
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -85,6 +86,7 @@ private static Stream archParams() {
                 Arguments.of("riscv64", RISCV64, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isRISCV64()),
                 Arguments.of("s390", S390, 64, ByteOrder.BIG_ENDIAN, Architecture.isS390()),
                 Arguments.of("s390x", S390, 64, ByteOrder.BIG_ENDIAN, Architecture.isS390()),
+                Arguments.of("sparcv9", SPARCV9, 64, ByteOrder.BIG_ENDIAN, Architecture.isSPARCV9()),
                 Arguments.of("x64", X64, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isX64()),
                 Arguments.of("x86", X86, 32, ByteOrder.LITTLE_ENDIAN, Architecture.isX86()),
                 Arguments.of("x86_64", X64, 64, ByteOrder.LITTLE_ENDIAN, Architecture.isX64())

From 62a953f40224589bb72864427181f69da526d391 Mon Sep 17 00:00:00 2001
From: Albert Mingkun Yang 
Date: Wed, 6 Sep 2023 09:36:18 +0000
Subject: [PATCH 85/86] 8315689: G1: Remove unused init_hash_seed

Reviewed-by: tschatzl
---
 src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
index 0ce2c7a961a..19bb1712e54 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
@@ -635,8 +635,6 @@ class G1CMTask : public TerminatorTerminator {
     // The regular clock call is called once the number of visited
     // references reaches this limit
     refs_reached_period           = 1024,
-    // Initial value for the hash seed, used in the work stealing code
-    init_hash_seed                = 17
   };
 
   G1CMObjArrayProcessor       _objArray_processor;

From 024133b089d911dcc3ea70dfdaa6b150b14a9eb4 Mon Sep 17 00:00:00 2001
From: singhnitin 
Date: Wed, 6 Sep 2023 11:36:13 +0000
Subject: [PATCH 86/86] 8311964: Some jtreg tests failing on x86 with error
 'unrecognized VM options' (C2 flags)

Reviewed-by: dhanalla, thartmann
---
 .../jtreg/compiler/loopopts/TestBackedgeLoadArrayFillMain.java   | 1 +
 .../loopopts/TestInfiniteLoopWithUnmergedBackedgesMain.java      | 1 +
 .../compiler/rangechecks/TestRangeCheckCmpUOverflowVsSub.java    | 1 +
 3 files changed, 3 insertions(+)

diff --git a/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFillMain.java b/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFillMain.java
index 878c04ecd83..e956a9d0915 100644
--- a/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFillMain.java
+++ b/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFillMain.java
@@ -28,6 +28,7 @@
  * @summary ArrayFill: if store is on backedge, last iteration is not to be executed.
  * @library /test/lib
  * @compile TestBackedgeLoadArrayFill.jasm
+ * @requires vm.compiler2.enabled
  * @run main/othervm
  *      -XX:CompileCommand=compileonly,TestBackedgeLoadArrayFill*::test*
  *      -XX:-TieredCompilation -Xcomp -XX:+OptimizeFill
diff --git a/test/hotspot/jtreg/compiler/loopopts/TestInfiniteLoopWithUnmergedBackedgesMain.java b/test/hotspot/jtreg/compiler/loopopts/TestInfiniteLoopWithUnmergedBackedgesMain.java
index 9379814b5ff..75b107e0e4b 100644
--- a/test/hotspot/jtreg/compiler/loopopts/TestInfiniteLoopWithUnmergedBackedgesMain.java
+++ b/test/hotspot/jtreg/compiler/loopopts/TestInfiniteLoopWithUnmergedBackedgesMain.java
@@ -26,6 +26,7 @@
  * @bug 8296412
  * @compile TestInfiniteLoopWithUnmergedBackedges.jasm
  * @summary Infinite loops may not have the backedges merged, before we call IdealLoopTree::check_safepts
+ * @requires vm.compiler2.enabled
  * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:-LoopUnswitching
  *      -XX:CompileCommand=compileonly,TestInfiniteLoopWithUnmergedBackedges::test*
  *      TestInfiniteLoopWithUnmergedBackedgesMain
diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCmpUOverflowVsSub.java b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCmpUOverflowVsSub.java
index 76a6d075c06..66cc87b6e4b 100644
--- a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCmpUOverflowVsSub.java
+++ b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCmpUOverflowVsSub.java
@@ -25,6 +25,7 @@
  * @test
  * @bug 8299959
  * @summary In CmpU::Value, the sub computation may be narrower than the overflow computation.
+ * @requires vm.compiler2.enabled
  *
  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressCCP -Xcomp -XX:-TieredCompilation
  *                   -XX:CompileCommand=compileonly,compiler.rangechecks.TestRangeCheckCmpUOverflowVsSub::test