diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk index c59e685bf4f3f..b6a0a8d5d6fd5 100644 --- a/make/InitSupport.gmk +++ b/make/InitSupport.gmk @@ -501,9 +501,12 @@ else # $(HAS_SPEC)=true # Failure logs are only supported for "parallel" main targets, not the # (trivial) sequential make targets (such as clean and reconfigure), # since the failure-logs directory creation will conflict with clean. + # We also make sure the javatmp directory exists, which is needed if a java + # process (like javac) is using java.io.tmpdir. define PrepareFailureLogs $(RM) -r $(MAKESUPPORT_OUTPUTDIR)/failure-logs 2> /dev/null && \ $(MKDIR) -p $(MAKESUPPORT_OUTPUTDIR)/failure-logs + $(MKDIR) -p $(JAVA_TMP_DIR) $(RM) $(MAKESUPPORT_OUTPUTDIR)/exit-with-error 2> /dev/null endef diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index 7ce4038f6412c..7ef1aee861ab8 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -353,6 +353,8 @@ BUNDLES_OUTPUTDIR = $(OUTPUTDIR)/bundles TESTMAKE_OUTPUTDIR = $(OUTPUTDIR)/test-make MAKESUPPORT_OUTPUTDIR = $(OUTPUTDIR)/make-support +JAVA_TMP_DIR = $(SUPPORT_OUTPUTDIR)/javatmp + # This does not get overridden in a bootcycle build CONFIGURESUPPORT_OUTPUTDIR := @CONFIGURESUPPORT_OUTPUTDIR@ BUILDJDK_OUTPUTDIR = $(OUTPUTDIR)/buildjdk @@ -634,7 +636,8 @@ STATIC_BUILD := @STATIC_BUILD@ STRIPFLAGS := @STRIPFLAGS@ -JAVA_FLAGS := @JAVA_FLAGS@ +JAVA_FLAGS_TMPDIR := -Djava.io.tmpdir=$(JAVA_TMP_DIR) +JAVA_FLAGS := @JAVA_FLAGS@ $(JAVA_FLAGS_TMPDIR) JAVA_FLAGS_BIG := @JAVA_FLAGS_BIG@ JAVA_FLAGS_SMALL := @JAVA_FLAGS_SMALL@ BUILD_JAVA_FLAGS_SMALL := @BUILD_JAVA_FLAGS_SMALL@ diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 259c1834da330..1503c86aff1df 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -197,7 +197,7 @@ define SetupJavaCompilationBody ifeq ($$($1_COMPILER), bootjdk) # Javac server is not available when using the bootjdk compiler. - $1_JAVAC_CMD := $$(JAVAC) + $1_JAVAC_CMD := $$(JAVAC) -J$$(JAVA_FLAGS_TMPDIR) ifeq ($$($1_SMALL_JAVA), true) $1_FLAGS += $$(addprefix -J, $$(JAVA_FLAGS_SMALL)) @@ -211,7 +211,7 @@ define SetupJavaCompilationBody $1_TARGET_RELEASE := $$(TARGET_RELEASE_BOOTJDK) endif else ifeq ($$($1_COMPILER), buildjdk) - $1_JAVAC_CMD := $$(BUILD_JAVAC) + $1_JAVAC_CMD := $$(BUILD_JAVAC) -J$$(JAVA_FLAGS_TMPDIR) ifeq ($$($1_TARGET_RELEASE), ) # If unspecified, default to the new jdk we're building diff --git a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/FileTreeCreator.java b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/FileTreeCreator.java index 385903e676ff7..f8fd111587cd9 100644 --- a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/FileTreeCreator.java +++ b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/FileTreeCreator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -54,7 +54,7 @@ public FileTreeCreator(Path startDir, Vector allConfigs, WinGammaPl attributes.push(new DirAttributes()); } - public class DirAttributes { + public static class DirAttributes { private HashSet ignores; private HashSet disablePch; diff --git a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java index 921eaeee764da..1b930ca752777 100644 --- a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java +++ b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java @@ -151,6 +151,17 @@ public static void main(String ... args) throws Throwable { LOGGER.log(Level.FINE, "New Date: " + newDate + " - old: " + oldDate); + // Pull SwitchBootstraps and associated classes into the classlist + record A(int a) { } + record B(int b) { } + Object o = new A(4711); + int value = switch (o) { + case A a -> a.a; + case B b -> b.b; + default -> 17; + }; + LOGGER.log(Level.FINE, "Value: " + value); + // The Striped64$Cell is loaded rarely only when there's a contention among // multiple threads performing LongAdder.increment(). This results in // an inconsistency in the classlist between builds (see JDK-8295951). diff --git a/make/jdk/src/classes/build/tools/intpoly/FieldGen.java b/make/jdk/src/classes/build/tools/intpoly/FieldGen.java index a65150ac421b5..234f5cfce0d26 100644 --- a/make/jdk/src/classes/build/tools/intpoly/FieldGen.java +++ b/make/jdk/src/classes/build/tools/intpoly/FieldGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -778,7 +778,7 @@ private String generate(FieldParams params) throws IOException { result.appendLine("}"); result.appendLine("@Override"); - result.appendLine("protected void mult(long[] a, long[] b, long[] r) {"); + result.appendLine("protected int mult(long[] a, long[] b, long[] r) {"); result.incrIndent(); for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { result.appendIndent(); @@ -804,6 +804,9 @@ private String generate(FieldParams params) throws IOException { } } result.append(");\n"); + result.appendIndent(); + result.append("return 0;"); + result.appendLine(); result.decrIndent(); result.appendLine("}"); @@ -833,7 +836,7 @@ private String generate(FieldParams params) throws IOException { // } // } result.appendLine("@Override"); - result.appendLine("protected void square(long[] a, long[] r) {"); + result.appendLine("protected int square(long[] a, long[] r) {"); result.incrIndent(); for (int i = 0; i < 2 * params.getNumLimbs() - 1; i++) { result.appendIndent(); @@ -874,6 +877,9 @@ private String generate(FieldParams params) throws IOException { } } result.append(");\n"); + result.appendIndent(); + result.append("return 0;"); + result.appendLine(); result.decrIndent(); result.appendLine("}"); diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index 4a6232afbe0b9..7b65e89610e04 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -109,6 +109,8 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \ --add-exports java.base/jdk.internal.vm=ALL-UNNAMED \ --add-exports java.base/sun.invoke.util=ALL-UNNAMED \ --add-exports java.base/sun.security.util=ALL-UNNAMED \ + --add-exports java.base/sun.security.util.math=ALL-UNNAMED \ + --add-exports java.base/sun.security.util.math.intpoly=ALL-UNNAMED \ --enable-preview \ -XDsuppressNotes \ -processor org.openjdk.jmh.generators.BenchmarkProcessor, \ diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index 6c2b12fc7a8f2..073d992235517 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -269,21 +269,6 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, // verify_tlab(); } -void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1) { - assert(t1->is_valid(), "need temp reg"); - - __ ldr(t1, Address(rthread, in_bytes(JavaThread::allocated_bytes_offset()))); - if (var_size_in_bytes->is_valid()) { - __ add(t1, t1, var_size_in_bytes); - } else { - __ add(t1, t1, con_size_in_bytes); - } - __ str(t1, Address(rthread, in_bytes(JavaThread::allocated_bytes_offset()))); -} - static volatile uint32_t _patching_epoch = 0; address BarrierSetAssembler::patching_epoch_addr() { diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp index 8dc475e0597a1..d0e2aa9588827 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp @@ -44,11 +44,6 @@ enum class NMethodPatchingType { }; class BarrierSetAssembler: public CHeapObj { -private: - void incr_allocated_bytes(MacroAssembler* masm, - Register var_size_in_bytes, int con_size_in_bytes, - Register t1 = noreg); - public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, Register src, Register dst, Register count, RegSet saved_regs) {} diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index fe4df9b8c0d1a..5db29729239d3 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -109,18 +109,13 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, assert_different_registers(obj, pre_val, tmp1, tmp2); assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - Address in_progress(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset())); Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset())); // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ ldrw(tmp1, in_progress); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldrb(tmp1, in_progress); - } - __ cbzw(tmp1, done); + Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); + __ ldrb(tmp1, gc_state); + __ tbz(tmp1, ShenandoahHeap::MARKING_BITPOS, done); // Do we need to load the previous value? if (obj != noreg) { diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp index a4e7f35ec81fa..ea19730673cb6 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp @@ -159,46 +159,6 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, Regi __ str(obj_end, Address(Rthread, JavaThread::tlab_top_offset())); } -void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, RegisterOrConstant size_in_bytes, Register tmp) { - // Bump total bytes allocated by this thread - Label done; - - // Borrow the Rthread for alloc counter - Register Ralloc = Rthread; - __ add(Ralloc, Ralloc, in_bytes(JavaThread::allocated_bytes_offset())); - __ ldr(tmp, Address(Ralloc)); - __ adds(tmp, tmp, size_in_bytes); - __ str(tmp, Address(Ralloc), cc); - __ b(done, cc); - - // Increment the high word and store single-copy atomically (that is an unlikely scenario on typical embedded systems as it means >4GB has been allocated) - // To do so ldrd/strd instructions used which require an even-odd pair of registers. Such a request could be difficult to satisfy by - // allocating those registers on a higher level, therefore the routine is ready to allocate a pair itself. - Register low, high; - // Select ether R0/R1 or R2/R3 - - if (size_in_bytes.is_register() && (size_in_bytes.as_register() == R0 || size_in_bytes.as_register() == R1)) { - low = R2; - high = R3; - } else { - low = R0; - high = R1; - } - __ push(RegisterSet(low, high)); - - __ ldrd(low, Address(Ralloc)); - __ adds(low, low, size_in_bytes); - __ adc(high, high, 0); - __ strd(low, Address(Ralloc)); - - __ pop(RegisterSet(low, high)); - - __ bind(done); - - // Unborrow the Rthread - __ sub(Rthread, Ralloc, in_bytes(JavaThread::allocated_bytes_offset())); -} - void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp index ae51a054540c6..60021390ea26f 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp @@ -40,12 +40,6 @@ enum class NMethodPatchingType { }; class BarrierSetAssembler: public CHeapObj { -private: - void incr_allocated_bytes(MacroAssembler* masm, - RegisterOrConstant size_in_bytes, - Register tmp -); - public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, Register addr, Register count, int callee_saved_regs) {} diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 219aeaf316d87..9da5a2c658009 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -183,7 +183,7 @@ void C1_MacroAssembler::try_allocate( Register obj, // result: pointer to object after successful allocation Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise int con_size_in_bytes, // object size in bytes if known at compile time - Register t1, // temp register, must be global register for incr_allocated_bytes + Register t1, // temp register Register t2, // temp register Label& slow_case // continuation point if fast allocation fails ) { diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 701cd5cf637e9..000d4510c0796 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2209,9 +2209,6 @@ void MacroAssembler::tlab_allocate( std(new_top, in_bytes(JavaThread::tlab_top_offset()), R16_thread); //verify_tlab(); not implemented } -void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2) { - unimplemented("incr_allocated_bytes"); -} address MacroAssembler::emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc) { diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 92db8a86b42ff..5a628674da144 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -626,7 +626,6 @@ class MacroAssembler: public Assembler { Register t1, // temp register Label& slow_case // continuation point if fast allocation fails ); - void incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2); enum { trampoline_stub_size = 6 * 4 }; address emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc = noreg); diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index ff55951bd7d7b..b0249ac3344b7 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -656,39 +656,35 @@ class Assembler : public AbstractAssembler { #undef INSN -#define INSN(NAME, op) \ - void NAME(Register Rd, const int32_t offset) { \ - guarantee(is_simm21(offset) && ((offset % 2) == 0), "offset is invalid."); \ - unsigned insn = 0; \ - patch((address)&insn, 6, 0, op); \ - patch_reg((address)&insn, 7, Rd); \ - patch((address)&insn, 19, 12, (uint32_t)((offset >> 12) & 0xff)); \ - patch((address)&insn, 20, (uint32_t)((offset >> 11) & 0x1)); \ - patch((address)&insn, 30, 21, (uint32_t)((offset >> 1) & 0x3ff)); \ - patch((address)&insn, 31, (uint32_t)((offset >> 20) & 0x1)); \ - emit(insn); \ + private: + // All calls and jumps must go via MASM. + // Format J-type + void _jal(Register Rd, const int32_t offset) { + guarantee(is_simm21(offset) && ((offset % 2) == 0), "offset is invalid."); + unsigned insn = 0; + patch((address)&insn, 6, 0, 0b1101111); + patch_reg((address)&insn, 7, Rd); + patch((address)&insn, 19, 12, (uint32_t)((offset >> 12) & 0xff)); + patch((address)&insn, 20, (uint32_t)((offset >> 11) & 0x1)); + patch((address)&insn, 30, 21, (uint32_t)((offset >> 1) & 0x3ff)); + patch((address)&insn, 31, (uint32_t)((offset >> 20) & 0x1)); + emit(insn); } - INSN(jal, 0b1101111); - -#undef INSN - -#define INSN(NAME, op, funct) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - guarantee(is_simm12(offset), "offset is invalid."); \ - unsigned insn = 0; \ - patch((address)&insn, 6, 0, op); \ - patch_reg((address)&insn, 7, Rd); \ - patch((address)&insn, 14, 12, funct); \ - patch_reg((address)&insn, 15, Rs); \ - int32_t val = offset & 0xfff; \ - patch((address)&insn, 31, 20, val); \ - emit(insn); \ + // Format I-type + void _jalr(Register Rd, Register Rs, const int32_t offset) { + guarantee(is_simm12(offset), "offset is invalid."); + unsigned insn = 0; + patch((address)&insn, 6, 0, 0b1100111); + patch_reg((address)&insn, 7, Rd); + patch((address)&insn, 14, 12, 0b000); + patch_reg((address)&insn, 15, Rs); + int32_t val = offset & 0xfff; + patch((address)&insn, 31, 20, val); + emit(insn); } - INSN(_jalr, 0b1100111, 0b000); - -#undef INSN + public: enum barrier { i = 0b1000, o = 0b0100, r = 0b0010, w = 0b0001, @@ -2294,21 +2290,23 @@ enum Nf { #undef INSN -#define INSN(NAME, funct4, op) \ - void NAME(Register Rs1) { \ - assert_cond(Rs1 != x0); \ - uint16_t insn = 0; \ - c_patch((address)&insn, 1, 0, op); \ - c_patch_reg((address)&insn, 2, x0); \ - c_patch_reg((address)&insn, 7, Rs1); \ - c_patch((address)&insn, 15, 12, funct4); \ - emit_int16(insn); \ + private: + // All calls and jumps must go via MASM. + // Format CR, c.jr/c.jalr + // Note C instruction can't be changed, i.e. relocation patching. + template + void c_cr_if(Register Rs1) { + assert_cond(Rs1 != x0); + uint16_t insn = 0; + c_patch((address)&insn, 1, 0, FunctionType); + c_patch_reg((address)&insn, 2, x0); + c_patch_reg((address)&insn, 7, Rs1); + c_patch((address)&insn, 15, 12, InstructionType); + emit_int16(insn); } - INSN(c_jr, 0b1000, 0b10); - INSN(c_jalr, 0b1001, 0b10); - -#undef INSN + void c_jr(Register Rs1) { c_cr_if<0b1000, 0b10>(Rs1); } + void c_jalr(Register Rs1) { c_cr_if<0b1001, 0b10>(Rs1); } typedef void (Assembler::* j_c_insn)(address dest); typedef void (Assembler::* compare_and_branch_c_insn)(Register Rs1, address dest); @@ -2331,35 +2329,36 @@ enum Nf { } } -#define INSN(NAME, funct3, op) \ - void NAME(int32_t offset) { \ - assert(is_simm12(offset) && ((offset % 2) == 0), "invalid encoding"); \ - uint16_t insn = 0; \ - c_patch((address)&insn, 1, 0, op); \ - c_patch((address)&insn, 2, 2, (offset & nth_bit(5)) >> 5); \ - c_patch((address)&insn, 5, 3, (offset & right_n_bits(4)) >> 1); \ - c_patch((address)&insn, 6, 6, (offset & nth_bit(7)) >> 7); \ - c_patch((address)&insn, 7, 7, (offset & nth_bit(6)) >> 6); \ - c_patch((address)&insn, 8, 8, (offset & nth_bit(10)) >> 10); \ - c_patch((address)&insn, 10, 9, (offset & right_n_bits(10)) >> 8); \ - c_patch((address)&insn, 11, 11, (offset & nth_bit(4)) >> 4); \ - c_patch((address)&insn, 12, 12, (offset & nth_bit(11)) >> 11); \ - c_patch((address)&insn, 15, 13, funct3); \ - emit_int16(insn); \ - } \ - void NAME(address dest) { \ - assert_cond(dest != nullptr); \ - int64_t distance = dest - pc(); \ - assert(is_simm12(distance) && ((distance % 2) == 0), "invalid encoding"); \ - c_j(distance); \ - } \ - void NAME(Label &L) { \ - wrap_label(L, &Assembler::NAME); \ + // Format CJ, c.j (c.jal) + // Note C instruction can't be changed, i.e. relocation patching. + void c_j(int32_t offset) { + assert(is_simm12(offset) && ((offset % 2) == 0), "invalid encoding"); + uint16_t insn = 0; + c_patch((address)&insn, 1, 0, 0b01); + c_patch((address)&insn, 2, 2, (offset & nth_bit(5)) >> 5); + c_patch((address)&insn, 5, 3, (offset & right_n_bits(4)) >> 1); + c_patch((address)&insn, 6, 6, (offset & nth_bit(7)) >> 7); + c_patch((address)&insn, 7, 7, (offset & nth_bit(6)) >> 6); + c_patch((address)&insn, 8, 8, (offset & nth_bit(10)) >> 10); + c_patch((address)&insn, 10, 9, (offset & right_n_bits(10)) >> 8); + c_patch((address)&insn, 11, 11, (offset & nth_bit(4)) >> 4); + c_patch((address)&insn, 12, 12, (offset & nth_bit(11)) >> 11); + c_patch((address)&insn, 15, 13, 0b101); + emit_int16(insn); } - INSN(c_j, 0b101, 0b01); + void c_j(address dest) { + assert_cond(dest != nullptr); + int64_t distance = dest - pc(); + assert(is_simm12(distance) && ((distance % 2) == 0), "invalid encoding"); + c_j(distance); + } -#undef INSN + void c_j(Label &L) { + wrap_label(L, &Assembler::c_j); + } + + public: #define INSN(NAME, funct3, op) \ void NAME(Register Rs1, int32_t imm) { \ @@ -2812,24 +2811,35 @@ enum Nf { // -------------------------- // Unconditional branch instructions // -------------------------- -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - /* jalr -> c.jr/c.jalr */ \ - if (do_compress() && (offset == 0 && Rs != x0)) { \ - if (Rd == x1) { \ - c_jalr(Rs); \ - return; \ - } else if (Rd == x0) { \ - c_jr(Rs); \ - return; \ - } \ - } \ - _jalr(Rd, Rs, offset); \ + protected: + // All calls and jumps must go via MASM. + void jalr(Register Rd, Register Rs, const int32_t offset) { + /* jalr -> c.jr/c.jalr */ + if (do_compress() && (offset == 0 && Rs != x0)) { + if (Rd == x1) { + c_jalr(Rs); + return; + } else if (Rd == x0) { + c_jr(Rs); + return; + } + } + _jalr(Rd, Rs, offset); } - INSN(jalr); + void jal(Register Rd, const int32_t offset) { + /* jal -> c.j, note c.jal is RV32C only */ + if (do_compress() && + Rd == x0 && + is_simm12(offset) && ((offset % 2) == 0)) { + c_j(offset); + return; + } -#undef INSN + _jal(Rd, offset); + } + + public: // -------------------------- // Miscellaneous Instructions @@ -3009,18 +3019,6 @@ enum Nf { #undef INSN -// --------------------------------------------------------------------------------------- - -#define INSN(NAME, REGISTER) \ - void NAME(Register Rs) { \ - jalr(REGISTER, Rs, 0); \ - } - - INSN(jr, x0); - INSN(jalr, x1); - -#undef INSN - // -------------- ZCB Instruction Definitions -------------- // Zcb additional C instructions private: diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 5d0fa3fad3cec..a15405f532302 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -1841,17 +1841,7 @@ void LIR_Assembler::leal(LIR_Opr addr, LIR_Opr dest, LIR_PatchCode patch_code, C void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) { assert(!tmp->is_valid(), "don't need temporary"); - CodeBlob *cb = CodeCache::find_blob(dest); - if (cb != nullptr) { - __ far_call(RuntimeAddress(dest)); - } else { - RuntimeAddress target(dest); - __ relocate(target.rspec(), [&] { - int32_t offset; - __ movptr(t0, target.target(), offset); - __ jalr(x1, t0, offset); - }); - } + __ rt_call(dest); if (info != nullptr) { add_call_info_here(info); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 2468bf70fe53e..dd9a9974f1b94 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2762,6 +2762,10 @@ void C2_MacroAssembler::compare_integral_v(VectorRegister vd, VectorRegister src case BoolTest::ge: vmsge_vv(vd, src1, src2, vm); break; case BoolTest::lt: vmslt_vv(vd, src1, src2, vm); break; case BoolTest::gt: vmsgt_vv(vd, src1, src2, vm); break; + case BoolTest::ule: vmsleu_vv(vd, src1, src2, vm); break; + case BoolTest::uge: vmsgeu_vv(vd, src1, src2, vm); break; + case BoolTest::ult: vmsltu_vv(vd, src1, src2, vm); break; + case BoolTest::ugt: vmsgtu_vv(vd, src1, src2, vm); break; default: assert(false, "unsupported compare condition"); ShouldNotReachHere(); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index cbf8de7341d0d..0f3850809775c 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -211,21 +211,6 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, } } -void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, - Register var_size_in_bytes, - int con_size_in_bytes, - Register tmp1) { - assert(tmp1->is_valid(), "need temp reg"); - - __ ld(tmp1, Address(xthread, in_bytes(JavaThread::allocated_bytes_offset()))); - if (var_size_in_bytes->is_valid()) { - __ add(tmp1, tmp1, var_size_in_bytes); - } else { - __ add(tmp1, tmp1, con_size_in_bytes); - } - __ sd(tmp1, Address(xthread, in_bytes(JavaThread::allocated_bytes_offset()))); -} - static volatile uint32_t _patching_epoch = 0; address BarrierSetAssembler::patching_epoch_addr() { diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp index eb0801d237f70..c1f51d768df5d 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp @@ -45,11 +45,6 @@ enum class NMethodPatchingType { }; class BarrierSetAssembler: public CHeapObj { -private: - void incr_allocated_bytes(MacroAssembler* masm, - Register var_size_in_bytes, int con_size_in_bytes, - Register t1 = noreg); - public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, Register src, Register dst, Register count, RegSet saved_regs) {} diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp index 26d60441c2d2c..9be8259e7e85d 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp @@ -112,18 +112,14 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, assert_different_registers(obj, pre_val, tmp1, tmp2); assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - Address in_progress(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset())); Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset())); // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ lwu(tmp1, in_progress); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbu(tmp1, in_progress); - } - __ beqz(tmp1, done); + Address gc_state(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); + __ lbu(t1, gc_state); + __ test_bit(t1, t1, ShenandoahHeap::MARKING_BITPOS); + __ beqz(t1, done); // Do we need to load the previous value? if (obj != noreg) { @@ -300,7 +296,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, assert(!is_narrow, "phantom access cannot be narrow"); target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak); } - __ call(target); + __ rt_call(target); __ mv(t0, x10); __ pop_call_clobbered_registers(); __ mv(x10, t0); @@ -703,7 +699,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_s assert(is_native, "phantom must only be called off-heap"); target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom); } - __ call(target); + __ rt_call(target); __ mv(t0, x10); __ pop_call_clobbered_registers(); __ mv(x10, t0); diff --git a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp index fd1701c8188b8..8423ecad8a3da 100644 --- a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp +++ b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp @@ -177,7 +177,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { __ relocate(target.rspec(), [&] { int32_t offset; __ la(t0, target.target(), offset); - __ jalr(x1, t0, offset); + __ jalr(t0, offset); }); __ leave(); __ ret(); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b450d93680f3b..bfa68a88f5735 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -339,7 +339,7 @@ void MacroAssembler::call_VM_base(Register oop_result, relocate(target.rspec(), [&] { int32_t offset; la(t0, target.target(), offset); - jalr(x0, t0, offset); + jr(t0, offset); }); bind(ok); } @@ -641,14 +641,16 @@ void MacroAssembler::emit_static_call_stub() { // Jump to the entry point of the c2i stub. int32_t offset = 0; movptr(t0, 0, offset); - jalr(x0, t0, offset); + jr(t0, offset); } void MacroAssembler::call_VM_leaf_base(address entry_point, int number_of_arguments, Label *retaddr) { + int32_t offset = 0; push_reg(RegSet::of(t0, xmethod), sp); // push << t0 & xmethod >> to sp - call(entry_point); + mv(t0, entry_point, offset); + jalr(t0, offset); if (retaddr != nullptr) { bind(*retaddr); } @@ -716,33 +718,19 @@ void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Reg } void MacroAssembler::la(Register Rd, const address addr) { - int64_t offset = addr - pc(); - if (is_valid_32bit_offset(offset)) { - auipc(Rd, (int32_t)offset + 0x800); //0x800, Note:the 11th sign bit - addi(Rd, Rd, ((int64_t)offset << 52) >> 52); - } else { - movptr(Rd, addr); - } + int32_t offset; + la(Rd, addr, offset); + addi(Rd, Rd, offset); } void MacroAssembler::la(Register Rd, const address addr, int32_t &offset) { - assert((uintptr_t)addr < (1ull << 48), "bad address"); - - unsigned long target_address = (uintptr_t)addr; - unsigned long low_address = (uintptr_t)CodeCache::low_bound(); - unsigned long high_address = (uintptr_t)CodeCache::high_bound(); - long offset_low = target_address - low_address; - long offset_high = target_address - high_address; - - // RISC-V doesn't compute a page-aligned address, in order to partially - // compensate for the use of *signed* offsets in its base+disp12 - // addressing mode (RISC-V's PC-relative reach remains asymmetric - // [-(2G + 2K), 2G - 2K). - if (offset_high >= -((1L << 31) + (1L << 11)) && offset_low < (1L << 31) - (1L << 11)) { + if (is_32bit_offset_from_codecache((int64_t)addr)) { int64_t distance = addr - pc(); + assert(is_valid_32bit_offset(distance), "Must be"); auipc(Rd, (int32_t)distance + 0x800); offset = ((int32_t)distance << 20) >> 20; } else { + assert(!CodeCache::contains(addr), "Must be"); movptr(Rd, addr, offset); } } @@ -859,88 +847,113 @@ void MacroAssembler::li(Register Rd, int64_t imm) { } } -#define INSN(NAME, REGISTER) \ - void MacroAssembler::NAME(const address dest, Register temp) { \ - assert_cond(dest != nullptr); \ - int64_t distance = dest - pc(); \ - if (is_simm21(distance) && ((distance % 2) == 0)) { \ - Assembler::jal(REGISTER, distance); \ - } else { \ - assert(temp != noreg, "expecting a register"); \ - int32_t offset = 0; \ - movptr(temp, dest, offset); \ - Assembler::jalr(REGISTER, temp, offset); \ - } \ - } \ - - INSN(j, x0); - INSN(jal, x1); - -#undef INSN +void MacroAssembler::jump_link(const address dest, Register temp) { + assert_cond(dest != nullptr); + int64_t distance = dest - pc(); + if (is_simm21(distance) && ((distance % 2) == 0)) { + Assembler::jal(x1, distance); + } else { + assert(temp != noreg && temp != x0, "expecting a register"); + int32_t offset = 0; + la(temp, dest, offset); + jalr(temp, offset); + } +} -#define INSN(NAME, REGISTER) \ - void MacroAssembler::NAME(const Address &adr, Register temp) { \ - switch (adr.getMode()) { \ - case Address::literal: { \ - relocate(adr.rspec(), [&] { \ - NAME(adr.target(), temp); \ - }); \ - break; \ - } \ - case Address::base_plus_offset: { \ - int32_t offset = ((int32_t)adr.offset() << 20) >> 20; \ - la(temp, Address(adr.base(), adr.offset() - offset)); \ - Assembler::jalr(REGISTER, temp, offset); \ - break; \ - } \ - default: \ - ShouldNotReachHere(); \ - } \ - } - - INSN(j, x0); - INSN(jal, x1); +void MacroAssembler::jump_link(const Address &adr, Register temp) { + switch (adr.getMode()) { + case Address::literal: { + relocate(adr.rspec(), [&] { + jump_link(adr.target(), temp); + }); + break; + } + case Address::base_plus_offset: { + int32_t offset = ((int32_t)adr.offset() << 20) >> 20; + la(temp, Address(adr.base(), adr.offset() - offset)); + jalr(temp, offset); + break; + } + default: + ShouldNotReachHere(); + } +} -#undef INSN +void MacroAssembler::j(const address dest, Register temp) { + assert(CodeCache::contains(dest), "Must be"); + assert_cond(dest != nullptr); + int64_t distance = dest - pc(); -#define INSN(NAME) \ - void MacroAssembler::NAME(Register Rd, const address dest, Register temp) { \ - assert_cond(dest != nullptr); \ - int64_t distance = dest - pc(); \ - if (is_simm21(distance) && ((distance % 2) == 0)) { \ - Assembler::NAME(Rd, distance); \ - } else { \ - assert_different_registers(Rd, temp); \ - int32_t offset = 0; \ - movptr(temp, dest, offset); \ - jalr(Rd, temp, offset); \ - } \ - } \ - void MacroAssembler::NAME(Register Rd, Label &L, Register temp) { \ - assert_different_registers(Rd, temp); \ - wrap_label(Rd, L, temp, &MacroAssembler::NAME); \ + // We can't patch C, i.e. if Label wasn't bound we need to patch this jump. + IncompressibleRegion ir(this); + if (is_simm21(distance) && ((distance % 2) == 0)) { + Assembler::jal(x0, distance); + } else { + assert(temp != noreg && temp != x0, "expecting a register"); + int32_t offset = 0; + la(temp, dest, offset); + jr(temp, offset); } +} - INSN(jal); +void MacroAssembler::j(const Address &adr, Register temp) { + switch (adr.getMode()) { + case Address::literal: { + relocate(adr.rspec(), [&] { + j(adr.target(), temp); + }); + break; + } + case Address::base_plus_offset: { + int32_t offset = ((int32_t)adr.offset() << 20) >> 20; + la(temp, Address(adr.base(), adr.offset() - offset)); + jr(temp, offset); + break; + } + default: + ShouldNotReachHere(); + } +} -#undef INSN +void MacroAssembler::j(Label &lab, Register temp) { + assert_different_registers(x0, temp); + if (lab.is_bound()) { + MacroAssembler::j(target(lab), temp); + } else { + lab.add_patch_at(code(), locator()); + MacroAssembler::j(pc(), temp); + } +} -#define INSN(NAME, REGISTER) \ - void MacroAssembler::NAME(Label &l, Register temp) { \ - jal(REGISTER, l, temp); \ - } \ +void MacroAssembler::jr(Register Rd, int32_t offset) { + assert(Rd != noreg, "expecting a register"); + Assembler::jalr(x0, Rd, offset); +} - INSN(j, x0); - INSN(jal, x1); +void MacroAssembler::call(const address dest, Register temp) { + assert_cond(dest != nullptr); + assert(temp != noreg, "expecting a register"); + int32_t offset = 0; + la(temp, dest, offset); + jalr(temp, offset); +} -#undef INSN +void MacroAssembler::jalr(Register Rs, int32_t offset) { + assert(Rs != noreg, "expecting a register"); + Assembler::jalr(x1, Rs, offset); +} -void MacroAssembler::wrap_label(Register Rt, Label &L, Register tmp, load_insn_by_temp insn) { - if (L.is_bound()) { - (this->*insn)(Rt, target(L), tmp); +void MacroAssembler::rt_call(address dest, Register tmp) { + CodeBlob *cb = CodeCache::find_blob(dest); + RuntimeAddress target(dest); + if (cb) { + far_call(target, tmp); } else { - L.add_patch_at(code(), locator()); - (this->*insn)(Rt, pc(), tmp); + relocate(target.rspec(), [&] { + int32_t offset; + la(tmp, target.target(), offset); + jalr(tmp, offset); + }); } } @@ -3169,7 +3182,6 @@ void MacroAssembler::atomic_cas( } void MacroAssembler::far_jump(const Address &entry, Register tmp) { - assert(ReservedCodeCacheSize < 4*G, "branch out of range"); assert(CodeCache::find_blob(entry.target()) != nullptr, "destination of far call not found in code cache"); assert(entry.rspec().type() == relocInfo::external_word_type @@ -3179,12 +3191,11 @@ void MacroAssembler::far_jump(const Address &entry, Register tmp) { relocate(entry.rspec(), [&] { int32_t offset; la(tmp, entry.target(), offset); - jalr(x0, tmp, offset); + jr(tmp, offset); }); } void MacroAssembler::far_call(const Address &entry, Register tmp) { - assert(ReservedCodeCacheSize < 4*G, "branch out of range"); assert(CodeCache::find_blob(entry.target()) != nullptr, "destination of far call not found in code cache"); assert(entry.rspec().type() == relocInfo::external_word_type @@ -3194,9 +3205,8 @@ void MacroAssembler::far_call(const Address &entry, Register tmp) { // We can use auipc + jalr here because we know that the total size of // the code cache cannot exceed 2Gb. relocate(entry.rspec(), [&] { - int32_t offset; - la(tmp, entry.target(), offset); - jalr(x1, tmp, offset); // link + assert(is_valid_32bit_offset(entry.target() - pc()), "Far call using wrong instructions."); + call(entry.target(), tmp); }); } @@ -3452,7 +3462,7 @@ void MacroAssembler::reserved_stack_check() { relocate(target.rspec(), [&] { int32_t offset; movptr(t0, target.target(), offset); - jalr(x0, t0, offset); + jr(t0, offset); }); should_not_reach_here(); @@ -3534,7 +3544,7 @@ address MacroAssembler::trampoline_call(Address entry) { } #endif relocate(entry.rspec(), [&] { - jal(target); + jump_link(target, t0); }); postcond(pc() != badAddress); @@ -4373,7 +4383,7 @@ address MacroAssembler::zero_words(Register ptr, Register cnt) { return nullptr; } } else { - jal(zero_blocks); + jump_link(zero_blocks, t0); } } bind(around); @@ -5018,20 +5028,6 @@ void MacroAssembler::double_move(VMRegPair src, VMRegPair dst, Register tmp) { } } -void MacroAssembler::rt_call(address dest, Register tmp) { - CodeBlob *cb = CodeCache::find_blob(dest); - RuntimeAddress target(dest); - if (cb) { - far_call(target, tmp); - } else { - relocate(target.rspec(), [&] { - int32_t offset; - movptr(tmp, target.target(), offset); - jalr(x1, tmp, offset); - }); - } -} - void MacroAssembler::test_bit(Register Rd, Register Rs, uint32_t bit_pos) { assert(bit_pos < 64, "invalid bit range"); if (UseZbs) { diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 7c77edd8711ce..35a242e47fd06 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -592,14 +592,40 @@ class MacroAssembler: public Assembler { void bltz(Register Rs, const address dest); void bgtz(Register Rs, const address dest); - void j(Label &l, Register temp = t0); + private: + void jump_link(const address dest, Register temp); + void jump_link(const Address &adr, Register temp); + public: + // We try to follow risc-v asm menomics. + // But as we don't layout a reachable GOT, + // we often need to resort to movptr, li <48imm>. + // https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md + + // jump: jal x0, offset + // For long reach uses temp register for: + // la + jr void j(const address dest, Register temp = t0); void j(const Address &adr, Register temp = t0); - void jal(Label &l, Register temp = t0); - void jal(const address dest, Register temp = t0); - void jal(const Address &adr, Register temp = t0); - void jal(Register Rd, Label &L, Register temp = t0); - void jal(Register Rd, const address dest, Register temp = t0); + void j(Label &l, Register temp = t0); + + // jump register: jalr x0, offset(rs) + void jr(Register Rd, int32_t offset = 0); + + // call: la + jalr x1 + void call(const address dest, Register temp = t0); + + // jalr: jalr x1, offset(rs) + void jalr(Register Rs, int32_t offset = 0); + + // Emit a runtime call. Only invalidates the tmp register which + // is used to keep the entry address for jalr/movptr. + // Uses call() for intra code cache, else movptr + jalr. + void rt_call(address dest, Register tmp = t0); + + // ret: jalr x0, 0(x1) + inline void ret() { + Assembler::jalr(x0, x1, 0); + } //label void beqz(Register Rs, Label &l, bool is_far = false); @@ -689,6 +715,14 @@ class MacroAssembler: public Assembler { return x < (twoG - twoK) && x >= (-twoG - twoK); } + // Ensure that the auipc can reach the destination at x from anywhere within + // the code cache so that if it is relocated we know it will still reach. + bool is_32bit_offset_from_codecache(int64_t x) { + int64_t low = (int64_t)CodeCache::low_bound(); + int64_t high = (int64_t)CodeCache::high_bound(); + return is_valid_32bit_offset(x - low) && is_valid_32bit_offset(x - high); + } + public: void push_reg(Register Rs); void pop_reg(Register Rd); @@ -733,14 +767,13 @@ class MacroAssembler: public Assembler { typedef void (MacroAssembler::* compare_and_branch_insn)(Register Rs1, Register Rs2, const address dest); typedef void (MacroAssembler::* compare_and_branch_label_insn)(Register Rs1, Register Rs2, Label &L, bool is_far); typedef void (MacroAssembler::* jal_jalr_insn)(Register Rt, address dest); - typedef void (MacroAssembler::* load_insn_by_temp)(Register Rt, address dest, Register temp); - void wrap_label(Register r, Label &L, Register t, load_insn_by_temp insn); void wrap_label(Register r, Label &L, jal_jalr_insn insn); void wrap_label(Register r1, Register r2, Label &L, compare_and_branch_insn insn, compare_and_branch_label_insn neg_insn, bool is_far = false); + // la will use movptr instead of GOT when not in reach for auipc. void la(Register Rd, Label &label); void la(Register Rd, const address addr); void la(Register Rd, const address addr, int32_t &offset); @@ -1469,21 +1502,6 @@ class MacroAssembler: public Assembler { VMRegPair dst, bool is_receiver, int* receiver_offset); - // Emit a runtime call. Only invalidates the tmp register which - // is used to keep the entry address for jalr/movptr. - void rt_call(address dest, Register tmp = t0); - - void call(const address dest, Register temp = t0) { - assert_cond(dest != nullptr); - assert(temp != noreg, "expecting a register"); - int32_t offset = 0; - mv(temp, dest, offset); - jalr(x1, temp, offset); - } - - inline void ret() { - jalr(x0, x1, 0); - } #ifdef ASSERT // Template short-hand support to clean-up after a failed call to trampoline diff --git a/src/hotspot/cpu/riscv/matcher_riscv.hpp b/src/hotspot/cpu/riscv/matcher_riscv.hpp index 32665f5922cf5..d1e10c3493942 100644 --- a/src/hotspot/cpu/riscv/matcher_riscv.hpp +++ b/src/hotspot/cpu/riscv/matcher_riscv.hpp @@ -128,8 +128,8 @@ static const bool int_in_long = true; // Does the CPU supports vector variable shift instructions? - static constexpr bool supports_vector_variable_shifts(void) { - return false; + static bool supports_vector_variable_shifts(void) { + return UseRVV; } // Does target support predicated operation emulation. @@ -148,8 +148,8 @@ } // Does the CPU supports vector unsigned comparison instructions? - static constexpr bool supports_vector_comparison_unsigned(int vlen, BasicType bt) { - return false; + static bool supports_vector_comparison_unsigned(int vlen, BasicType bt) { + return UseRVV; } // Some microarchitectures have mask registers used on vectors diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index c4048f66e0d3e..399de3a2805d2 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -400,7 +400,7 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { int32_t offset = 0; a.movptr(t0, entry, offset); // lui, addi, slli, addi, slli - a.jalr(x0, t0, offset); // jalr + a.jr(t0, offset); // jalr ICache::invalidate_range(code_pos, instruction_size); } @@ -410,7 +410,6 @@ void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) ShouldNotCallThis(); } - address NativeCallTrampolineStub::destination(nmethod *nm) const { return ptr_at(data_offset); } diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 6ee3365ff733f..5c57ffabe5649 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -2218,6 +2218,32 @@ instruct replicateD(vReg dst, fRegD src) %{ %} // vector shift +// +// Following shift instruct's are shared by vectorization (in SLP, superword.cpp) and Vector API. +// +// Shift behaviour in vectorization is defined by java language spec, which includes: +// 1. "If the promoted type of the left-hand operand is int, then only the five lowest-order bits of +// the right-hand operand are used as the shift distance. It is as if the right-hand operand were +// subjected to a bitwise logical AND operator & (ยง15.22.1) with the mask value 0x1f (0b11111). +// The shift distance actually used is therefore always in the range 0 to 31, inclusive." +// 2. similarly, for long "with the mask value 0x3f (0b111111)" +// check https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.19 for details. +// +// Shift behaviour in Vector API is defined as: +// e.g. for ASHR, "a>>(n&(ESIZE*8-1))" +// this behaviour is the same as shift instrunction's in riscv vector extension. +// check https://docs.oracle.com/en/java/javase/21/docs/api/jdk.incubator.vector/jdk/incubator/vector/VectorOperators.html#ASHR +// and https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#116-vector-single-width-shift-instructions for details. +// +// Despite the difference between these 2 behaviours, the same shift instruct's of byte and short are +// still shared between vectorization and Vector API. The way it works is hidden inside the implementation +// of vectorization and Vector API: +// 1. when doing optimization vectorization masks the shift value with "(BitsPerInt - 1)" or "(BitsPerLong - 1)" +// 2. in Vector API, shift value is masked with SHIFT_MASK (e.g. for ByteVector it's "Byte.SIZE - 1") +// +// If not because of this pre-processing of shift value respectively in vectorization and Vector API, then +// e.g. for a byte shift value 16, the intrinsic behaviour will be different, and they can not share the same +// instruct here, as vectorization requires x >> 16, but Vector API requires x >> (16 & 7). instruct vasrB(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ match(Set dst (RShiftVB src shift)); diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 582538a18b496..52fc126a459b7 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -652,7 +652,7 @@ class StubGenerator: public StubCodeGenerator { assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); #endif BLOCK_COMMENT("call MacroAssembler::debug"); - __ call(CAST_FROM_FN_PTR(address, MacroAssembler::debug64)); + __ rt_call(CAST_FROM_FN_PTR(address, MacroAssembler::debug64)); __ ebreak(); return start; @@ -5450,7 +5450,7 @@ static const int64_t right_3_bits = right_n_bits(3); } __ mv(c_rarg0, xthread); BLOCK_COMMENT("call runtime_entry"); - __ call(runtime_entry); + __ rt_call(runtime_entry); // Generate oop map OopMap* map = new OopMap(framesize, 0); diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 07aad47173c29..769e4dc5ccc78 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -1206,7 +1206,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // hand. // __ mv(c_rarg0, xthread); - __ call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + __ rt_call(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); __ get_method(xmethod); __ reinit_heapbase(); __ bind(Continue); @@ -1255,7 +1255,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ push_call_clobbered_registers(); __ mv(c_rarg0, xthread); - __ call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)); + __ rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)); __ pop_call_clobbered_registers(); __ bind(no_reguard); } @@ -1815,7 +1815,7 @@ void TemplateInterpreterGenerator::trace_bytecode(Template* t) { // the tosca in-state for the given template. assert(Interpreter::trace_code(t->tos_in()) != nullptr, "entry must have been generated"); - __ jal(Interpreter::trace_code(t->tos_in())); + __ call(Interpreter::trace_code(t->tos_in())); __ reinit_heapbase(); } diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 503440a5fcc01..a5e62169a9350 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -2274,7 +2274,9 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false); __ call_VM_leaf(entry); - __ bind(*stub->continuation()); + if (stub != nullptr) { + __ bind(*stub->continuation()); + } } void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr dest, LIR_Opr tmp) { @@ -2385,7 +2387,8 @@ void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { arrayOopDesc::base_offset_in_bytes(op->type()), type2aelembytes(op->type()), op->klass()->as_register(), - *op->stub()->entry()); + *op->stub()->entry(), + op->zero_array()); } __ bind(*op->stub()->continuation()); } diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp index 8df135974259e..619f0f7174f01 100644 --- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2017 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024 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 @@ -710,7 +710,13 @@ void LIRGenerator::do_ArrayCopy(Intrinsic* x) { frame_map()->c_calling_convention(&sig); // Make all state_for calls early since they can emit code. - CodeEmitInfo* info = state_for (x, x->state()); + CodeEmitInfo* info = nullptr; + if (x->state_before() != nullptr && x->state_before()->force_reexecute()) { + info = state_for(x, x->state_before()); + info->set_force_reexecute(); + } else { + info = state_for(x, x->state()); + } LIRItem src(x->argument_at(0), this); LIRItem src_pos(x->argument_at(1), this); @@ -735,6 +741,9 @@ void LIRGenerator::do_ArrayCopy(Intrinsic* x) { int flags; ciArrayKlass* expected_type; arraycopy_helper(x, &flags, &expected_type); + if (x->check_flag(Instruction::OmitChecksFlag)) { + flags = 0; + } __ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(), length.result(), tmp, expected_type, flags, info); // does add_safepoint @@ -769,7 +778,13 @@ void LIRGenerator::do_NewInstance(NewInstance* x) { } void LIRGenerator::do_NewTypeArray(NewTypeArray* x) { - CodeEmitInfo* info = state_for (x, x->state()); + CodeEmitInfo* info = nullptr; + if (x->state_before() != nullptr && x->state_before()->force_reexecute()) { + info = state_for(x, x->state_before()); + info->set_force_reexecute(); + } else { + info = state_for(x, x->state()); + } LIRItem length(x->length(), this); length.load_item(); @@ -786,7 +801,8 @@ void LIRGenerator::do_NewTypeArray(NewTypeArray* x) { __ metadata2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg); CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info); - __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path); + __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, + klass_reg, slow_path, x->zero_array()); LIR_Opr result = rlock_result(x); __ move(reg, result); diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index 58bdcee5d5f8f..c35b092329781 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024 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 @@ -164,7 +164,7 @@ void C1_MacroAssembler::try_allocate( Register obj, // result: Pointer to object after successful allocation. Register var_size_in_bytes, // Object size in bytes if unknown at compile time; invalid otherwise. int con_size_in_bytes, // Object size in bytes if known at compile time. - Register t1, // Temp register: Must be global register for incr_allocated_bytes. + Register t1, // Temp register. Label& slow_case // Continuation point if fast allocation fails. ) { if (UseTLAB) { @@ -191,7 +191,6 @@ void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register } void C1_MacroAssembler::initialize_body(Register objectFields, Register len_in_bytes, Register Rzero) { - Label done; assert_different_registers(objectFields, len_in_bytes, Rzero); // Initialize object fields. @@ -203,7 +202,6 @@ void C1_MacroAssembler::initialize_body(Register objectFields, Register len_in_b // Use Rzero as src length, then mvcle will copy nothing // and fill the object with the padding value 0. move_long_ext(objectFields, as_Register(Rzero->encoding()-1), 0); - bind(done); } void C1_MacroAssembler::allocate_object( @@ -274,7 +272,8 @@ void C1_MacroAssembler::allocate_array( int base_offset_in_bytes, // elements offset in bytes int elt_size, // element size in bytes Register klass, // object klass - Label& slow_case // Continuation point if fast allocation fails. + Label& slow_case, // Continuation point if fast allocation fails. + bool zero_array // zero the allocated array or not ) { assert_different_registers(obj, len, t1, t2, klass); @@ -305,15 +304,17 @@ void C1_MacroAssembler::allocate_array( initialize_header(obj, klass, len, noreg, t1); // Clear rest of allocated space. - Label done; - Register object_fields = t1; - Register Rzero = Z_R1_scratch; - z_aghi(arr_size, -base_offset_in_bytes); - z_bre(done); // Jump if size of fields is zero. - z_la(object_fields, base_offset_in_bytes, obj); - z_xgr(Rzero, Rzero); - initialize_body(object_fields, arr_size, Rzero); - bind(done); + if (zero_array) { + Label done; + Register object_fields = t1; + Register Rzero = Z_R1_scratch; + z_aghi(arr_size, -base_offset_in_bytes); + z_bre(done); // Jump if size of fields is zero. + z_la(object_fields, base_offset_in_bytes, obj); + z_xgr(Rzero, Rzero); + initialize_body(object_fields, arr_size, Rzero); + bind(done); + } // Dtrace support is unimplemented. // if (CURRENT_ENV->dtrace_alloc_probes()) { diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp index c77258509e1a5..e93eff43bd4af 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024 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 @@ -89,7 +89,8 @@ int base_offset_in_bytes, // elements offset in bytes int elt_size, // element size in bytes Register klass, // object klass - Label& slow_case // Continuation point if fast allocation fails. + Label& slow_case, // Continuation point if fast allocation fails. + bool zero_array // zero the allocated array or not ); // Invalidates registers in this window. diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index bcf4d5ea13b60..ee9e206494113 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -76,7 +76,8 @@ static const unsigned char tuple_table[Assembler::EVEX_ETUP + 1][Assembler::AVX_ 2, 4, 8, // EVEX_OVM(0) 16, 16, 16, // EVEX_M128(0) 8, 32, 64, // EVEX_DUP(0) - 0, 0, 0 // EVEX_NTUP + 1, 1, 1, // EVEX_NOSCALE(0) + 0, 0, 0 // EVEX_ETUP }; AddressLiteral::AddressLiteral(address target, relocInfo::relocType rtype) { @@ -294,11 +295,7 @@ void Assembler::emit_data(jint data, RelocationHolder const& rspec, int format) } static int encode(Register r) { - int enc = r->encoding(); - if (enc >= 8) { - enc -= 8; - } - return enc; + return r->encoding() & 7; } void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) { @@ -438,6 +435,9 @@ bool Assembler::query_compressed_disp_byte(int disp, bool is_evex_inst, int vect case EVEX_DUP: break; + case EVEX_NOSCALE: + break; + default: assert(0, "no valid evex tuple_table entry"); break; @@ -525,6 +525,9 @@ bool Assembler::emit_compressed_disp_byte(int &disp) { case EVEX_DUP: break; + case EVEX_NOSCALE: + break; + default: assert(0, "no valid evex tuple_table entry"); break; @@ -546,6 +549,24 @@ bool Assembler::emit_compressed_disp_byte(int &disp) { return is8bit(disp); } +bool Assembler::needs_rex2(Register reg1, Register reg2, Register reg3) { + bool rex2 = (reg1->is_valid() && reg1->encoding() >= 16) || + (reg2->is_valid() && reg2->encoding() >= 16) || + (reg3->is_valid() && reg3->encoding() >= 16); + assert(!rex2 || UseAPX, "extended gpr use requires UseAPX"); + return rex2; +} + +bool Assembler::needs_eevex(Register reg1, Register reg2, Register reg3) { + return needs_rex2(reg1, reg2, reg3); +} + +bool Assembler::needs_eevex(int enc1, int enc2, int enc3) { + bool eevex = enc1 >= 16 || enc2 >= 16 || enc3 >=16; + assert(!eevex || UseAPX, "extended gpr use requires UseAPX"); + return eevex; +} + static bool is_valid_encoding(int reg_enc) { return reg_enc >= 0; } @@ -616,9 +637,9 @@ void Assembler::emit_operand_helper(int reg_enc, int base_enc, int index_enc, if (is_valid_encoding(index_enc)) { assert(scale != Address::no_scale, "inconsistent address"); // [base + index*scale + disp] - if (disp == 0 && no_relocation && - base_enc != rbp->encoding() LP64_ONLY(&& base_enc != r13->encoding())) { + if (disp == 0 && no_relocation && ((base_enc & 0x7) != 5)) { // [base + index*scale] + // !(rbp | r13 | r21 | r29) // [00 reg 100][ss index base] emit_modrm_sib(0b00, reg_enc, 0b100, scale, index_enc, base_enc); @@ -635,7 +656,8 @@ void Assembler::emit_operand_helper(int reg_enc, int base_enc, int index_enc, scale, index_enc, base_enc); emit_data(disp, rspec, disp32_operand); } - } else if (base_enc == rsp->encoding() LP64_ONLY(|| base_enc == r12->encoding())) { + } else if ((base_enc & 0x7) == 4) { + // rsp | r12 | r20 | r28 // [rsp + disp] if (disp == 0 && no_relocation) { // [rsp] @@ -657,10 +679,11 @@ void Assembler::emit_operand_helper(int reg_enc, int base_enc, int index_enc, } } else { // [base + disp] - assert(base_enc != rsp->encoding() LP64_ONLY(&& base_enc != r12->encoding()), "illegal addressing mode"); - if (disp == 0 && no_relocation && - base_enc != rbp->encoding() LP64_ONLY(&& base_enc != r13->encoding())) { + // !(rsp | r12 | r20 | r28) were handled above + assert(((base_enc & 0x7) != 4), "illegal addressing mode"); + if (disp == 0 && no_relocation && ((base_enc & 0x7) != 5)) { // [base] + // !(rbp | r13 | r21 | r29) // [00 reg base] emit_modrm(0, reg_enc, base_enc); } else if (emit_compressed_disp_byte(disp) && no_relocation) { @@ -817,6 +840,13 @@ address Assembler::locate_operand(address inst, WhichOperand which) { NOT_LP64(assert(false, "64bit prefixes")); goto again_after_prefix; + case REX2: + NOT_LP64(assert(false, "64bit prefixes")); + if ((0xFF & *ip++) & REXBIT_W) { + is_64bit = true; + } + goto again_after_prefix; + case REX_W: case REX_WB: case REX_WX: @@ -866,6 +896,14 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case REX_WRXB: NOT_LP64(assert(false, "64bit prefix found")); goto again_after_size_prefix2; + + case REX2: + NOT_LP64(assert(false, "64bit prefix found")); + if ((0xFF & *ip++) & REXBIT_W) { + is_64bit = true; + } + goto again_after_size_prefix2; + case 0x8B: // movw r, a case 0x89: // movw a, r debug_only(has_disp32 = true); @@ -1155,6 +1193,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case REX_WRB: case REX_WRX: case REX_WRXB: + case REX2: NOT_LP64(assert(false, "found 64bit prefix")); ip++; default: @@ -1281,6 +1320,33 @@ void Assembler::emit_operand(XMMRegister reg, Address adr, int post_addr_length) } } +void Assembler::emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding, int byte3) { + int opcode_prefix = (ocp_and_encoding & 0xFF00) >> 8; + if (opcode_prefix != 0) { + emit_int32(opcode_prefix, (unsigned char)byte1, byte2 | (ocp_and_encoding & 0xFF), byte3); + } else { + emit_int24((unsigned char)byte1, byte2 | (ocp_and_encoding & 0xFF), byte3); + } +} + +void Assembler::emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding) { + int opcode_prefix = (ocp_and_encoding & 0xFF00) >> 8; + if (opcode_prefix != 0) { + emit_int24(opcode_prefix, (unsigned char)byte1, byte2 | (ocp_and_encoding & 0xFF)); + } else { + emit_int16((unsigned char)byte1, byte2 | (ocp_and_encoding & 0xFF)); + } +} + +void Assembler::emit_opcode_prefix_and_encoding(int byte1, int ocp_and_encoding) { + int opcode_prefix = (ocp_and_encoding & 0xFF00) >> 8; + if (opcode_prefix != 0) { + emit_int16(opcode_prefix, (unsigned char)byte1 | (ocp_and_encoding & 0xFF)); + } else { + emit_int8((unsigned char)byte1 | (ocp_and_encoding & 0xFF)); + } +} + // Now the Assembler instructions (identical for 32/64 bits) void Assembler::adcl(Address dst, int32_t imm32) { @@ -1603,50 +1669,48 @@ void Assembler::andl(Register dst, Register src) { void Assembler::andnl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF2, (0xC0 | encode)); } void Assembler::andnl(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF2); emit_operand(dst, src2, 0); } void Assembler::bsfl(Register dst, Register src) { - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - (unsigned char)0xBC, - 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::bsrl(Register dst, Register src) { - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - (unsigned char)0xBD, - 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode); } void Assembler::bswapl(Register reg) { // bswap - int encode = prefix_and_encode(reg->encoding()); - emit_int16(0x0F, (0xC8 | encode)); + int encode = prefix_and_encode(reg->encoding(), false, true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xC8, encode); } void Assembler::blsil(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsil(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, dst->encoding(), rbx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rbx, src, 0); @@ -1654,8 +1718,8 @@ void Assembler::blsil(Register dst, Address src) { void Assembler::blsmskl(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, 0xC0 | encode); } @@ -1663,7 +1727,8 @@ void Assembler::blsmskl(Register dst, Register src) { void Assembler::blsmskl(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, dst->encoding(), rdx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rdx, src, 0); @@ -1671,15 +1736,16 @@ void Assembler::blsmskl(Register dst, Address src) { void Assembler::blsrl(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsrl(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, dst->encoding(), rcx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rcx, src, 0); @@ -1743,18 +1809,15 @@ void Assembler::cld() { void Assembler::cmovl(Condition cc, Register dst, Register src) { NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction")); - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - 0x40 | cc, - 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding(0x40 | cc, 0xC0, encode); } - void Assembler::cmovl(Condition cc, Register dst, Address src) { InstructionMark im(this); NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction")); - prefix(src, dst); - emit_int16(0x0F, (0x40 | cc)); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((0x40 | cc)); emit_operand(dst, src, 0); } @@ -1840,16 +1903,16 @@ void Assembler::cmpw(Address dst, Register reg) { // The ZF is set if the compared values were equal, and cleared otherwise. void Assembler::cmpxchgl(Register reg, Address adr) { // cmpxchg InstructionMark im(this); - prefix(adr, reg); - emit_int16(0x0F, (unsigned char)0xB1); + prefix(adr, reg, false, true /* is_map1 */); + emit_int8((unsigned char)0xB1); emit_operand(reg, adr, 0); } void Assembler::cmpxchgw(Register reg, Address adr) { // cmpxchg InstructionMark im(this); size_prefix(); - prefix(adr, reg); - emit_int16(0x0F, (unsigned char)0xB1); + prefix(adr, reg, false, true /* is_map1 */); + emit_int8((unsigned char)0xB1); emit_operand(reg, adr, 0); } @@ -1858,8 +1921,8 @@ void Assembler::cmpxchgw(Register reg, Address adr) { // cmpxchg // The ZF is set if the compared values were equal, and cleared otherwise. void Assembler::cmpxchgb(Register reg, Address adr) { // cmpxchg InstructionMark im(this); - prefix(adr, reg, true); - emit_int16(0x0F, (unsigned char)0xB0); + prefix(adr, reg, true, true /* is_map1 */); + emit_int8((unsigned char)0xB0); emit_operand(reg, adr, 0); } @@ -1917,69 +1980,83 @@ void Assembler::cpuid() { // F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E. Accumulate CRC32 on r / m64. v void Assembler::crc32(Register crc, Register v, int8_t sizeInBytes) { assert(VM_Version::supports_sse4_2(), ""); - int8_t w = 0x01; - Prefix p = Prefix_EMPTY; + if (needs_eevex(crc, v)) { + InstructionAttr attributes(AVX_128bit, /* rex_w */ sizeInBytes == 8, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(crc->encoding(), 0, v->encoding(), sizeInBytes == 2 ? VEX_SIMD_66 : VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, true); + emit_int16(sizeInBytes == 1 ? (unsigned char)0xF0 : (unsigned char)0xF1, (0xC0 | encode)); + } else { + int8_t w = 0x01; + Prefix p = Prefix_EMPTY; - emit_int8((unsigned char)0xF2); - switch (sizeInBytes) { - case 1: - w = 0; - break; - case 2: - case 4: - break; - LP64_ONLY(case 8:) - // This instruction is not valid in 32 bits - // Note: - // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf - // - // Page B - 72 Vol. 2C says - // qwreg2 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : 11 qwreg1 qwreg2 - // mem64 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : mod qwreg r / m - // F0!!! - // while 3 - 208 Vol. 2A - // F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E.Accumulate CRC32 on r / m64. - // - // the 0 on a last bit is reserved for a different flavor of this instruction : - // F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E.Accumulate CRC32 on r / m8. - p = REX_W; - break; - default: - assert(0, "Unsupported value for a sizeInBytes argument"); - break; + emit_int8((unsigned char)0xF2); + switch (sizeInBytes) { + case 1: + w = 0; + break; + case 2: + case 4: + break; + LP64_ONLY(case 8:) + // This instruction is not valid in 32 bits + // Note: + // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + // + // Page B - 72 Vol. 2C says + // qwreg2 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : 11 qwreg1 qwreg2 + // mem64 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : mod qwreg r / m + // F0!!! + // while 3 - 208 Vol. 2A + // F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E.Accumulate CRC32 on r / m64. + // + // the 0 on a last bit is reserved for a different flavor of this instruction : + // F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E.Accumulate CRC32 on r / m8. + p = REX_W; + break; + default: + assert(0, "Unsupported value for a sizeInBytes argument"); + break; + } + LP64_ONLY(prefix(crc, v, p);) + emit_int32(0x0F, + 0x38, + 0xF0 | w, + 0xC0 | ((crc->encoding() & 0x7) << 3) | (v->encoding() & 7)); } - LP64_ONLY(prefix(crc, v, p);) - emit_int32(0x0F, - 0x38, - 0xF0 | w, - 0xC0 | ((crc->encoding() & 0x7) << 3) | (v->encoding() & 7)); } void Assembler::crc32(Register crc, Address adr, int8_t sizeInBytes) { assert(VM_Version::supports_sse4_2(), ""); InstructionMark im(this); - int8_t w = 0x01; - Prefix p = Prefix_EMPTY; + if (needs_eevex(crc, adr.base(), adr.index())) { + InstructionAttr attributes(AVX_128bit, /* vex_w */ sizeInBytes == 8, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); + vex_prefix(adr, 0, crc->encoding(), sizeInBytes == 2 ? VEX_SIMD_66 : VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); + emit_int8(sizeInBytes == 1 ? (unsigned char)0xF0 : (unsigned char)0xF1); + emit_operand(crc, adr, 0); + } else { + int8_t w = 0x01; + Prefix p = Prefix_EMPTY; - emit_int8((uint8_t)0xF2); - switch (sizeInBytes) { - case 1: - w = 0; - break; - case 2: - case 4: - break; - LP64_ONLY(case 8:) - // This instruction is not valid in 32 bits - p = REX_W; - break; - default: - assert(0, "Unsupported value for a sizeInBytes argument"); - break; + emit_int8((uint8_t)0xF2); + switch (sizeInBytes) { + case 1: + w = 0; + break; + case 2: + case 4: + break; + LP64_ONLY(case 8:) + // This instruction is not valid in 32 bits + p = REX_W; + break; + default: + assert(0, "Unsupported value for a sizeInBytes argument"); + break; + } + LP64_ONLY(prefix(crc, adr, p);) + emit_int24(0x0F, 0x38, (0xF0 | w)); + emit_operand(crc, adr, 0); } - LP64_ONLY(prefix(crc, adr, p);) - emit_int24(0x0F, 0x38, (0xF0 | w)); - emit_operand(crc, adr, 0); } void Assembler::cvtdq2pd(XMMRegister dst, XMMRegister src) { @@ -2081,7 +2158,7 @@ void Assembler::cvtsd2ss(XMMRegister dst, Address src) { void Assembler::cvtsi2sdl(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes, true); emit_int16(0x2A, (0xC0 | encode)); } @@ -2098,7 +2175,7 @@ void Assembler::cvtsi2sdl(XMMRegister dst, Address src) { void Assembler::cvtsi2ssl(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes, true); emit_int16(0x2A, (0xC0 | encode)); } @@ -2115,7 +2192,7 @@ void Assembler::cvtsi2ssl(XMMRegister dst, Address src) { void Assembler::cvtsi2ssq(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes, true); emit_int16(0x2A, (0xC0 | encode)); } @@ -2418,10 +2495,8 @@ void Assembler::imull(Register src) { } void Assembler::imull(Register dst, Register src) { - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - (unsigned char)0xAF, - (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAF, 0xC0, encode); } void Assembler::imull(Register dst, Address src, int32_t value) { @@ -2450,8 +2525,8 @@ void Assembler::imull(Register dst, Register src, int value) { void Assembler::imull(Register dst, Address src) { InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xAF); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xAF); emit_operand(dst, src, 0); } @@ -2587,7 +2662,10 @@ void Assembler::jmpb_0(Label& L, const char* file, int line) { } void Assembler::ldmxcsr( Address src) { - if (UseAVX > 0 ) { + // This instruction should be SSE encoded with the REX2 prefix when an + // extended GPR is present. To be consistent when UseAPX is enabled, use + // this encoding even when an extended GPR is not used. + if (UseAVX > 0 && !UseAPX ) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); vex_prefix(src, 0, 0, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); @@ -2596,8 +2674,8 @@ void Assembler::ldmxcsr( Address src) { } else { NOT_LP64(assert(VM_Version::supports_sse(), "")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, (unsigned char)0xAE); + prefix(src, true /* is_map1 */); + emit_int8((unsigned char)0xAE); emit_operand(as_Register(2), src, 0); } } @@ -2624,16 +2702,16 @@ void Assembler::size_prefix() { void Assembler::lzcntl(Register dst, Register src) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); emit_int8((unsigned char)0xF3); - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBD, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode); } void Assembler::lzcntl(Register dst, Address src) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xBD); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xBD); emit_operand(dst, src, 0); } @@ -2725,28 +2803,28 @@ void Assembler::kmovbl(KRegister dst, KRegister src) { void Assembler::kmovbl(KRegister dst, Register src) { assert(VM_Version::supports_avx512dq(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16((unsigned char)0x92, (0xC0 | encode)); } void Assembler::kmovbl(Register dst, KRegister src) { assert(VM_Version::supports_avx512dq(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int16((unsigned char)0x93, (0xC0 | encode)); } void Assembler::kmovwl(KRegister dst, Register src) { assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes, true); emit_int16((unsigned char)0x92, (0xC0 | encode)); } void Assembler::kmovwl(Register dst, KRegister src) { assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int16((unsigned char)0x93, (0xC0 | encode)); } @@ -2754,7 +2832,8 @@ void Assembler::kmovwl(Register dst, KRegister src) { void Assembler::kmovwl(KRegister dst, Address src) { assert(VM_Version::supports_evex(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x90); emit_operand(dst, src, 0); @@ -2763,7 +2842,8 @@ void Assembler::kmovwl(KRegister dst, Address src) { void Assembler::kmovwl(Address dst, KRegister src) { assert(VM_Version::supports_evex(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x91); emit_operand(src, dst, 0); @@ -2778,14 +2858,14 @@ void Assembler::kmovwl(KRegister dst, KRegister src) { void Assembler::kmovdl(KRegister dst, Register src) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes, true); emit_int16((unsigned char)0x92, (0xC0 | encode)); } void Assembler::kmovdl(Register dst, KRegister src) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int16((unsigned char)0x93, (0xC0 | encode)); } @@ -2800,7 +2880,8 @@ void Assembler::kmovql(KRegister dst, KRegister src) { void Assembler::kmovql(KRegister dst, Address src) { assert(VM_Version::supports_avx512bw(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x90); emit_operand(dst, src, 0); @@ -2809,7 +2890,8 @@ void Assembler::kmovql(KRegister dst, Address src) { void Assembler::kmovql(Address dst, KRegister src) { assert(VM_Version::supports_avx512bw(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x91); emit_operand(src, dst, 0); @@ -2817,14 +2899,14 @@ void Assembler::kmovql(Address dst, KRegister src) { void Assembler::kmovql(KRegister dst, Register src) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes, true); emit_int16((unsigned char)0x92, (0xC0 | encode)); } void Assembler::kmovql(Register dst, KRegister src) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int16((unsigned char)0x93, (0xC0 | encode)); } @@ -3105,7 +3187,7 @@ void Assembler::movb(Address dst, Register src) { void Assembler::movdl(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x6E, (0xC0 | encode)); } @@ -3113,7 +3195,7 @@ void Assembler::movdl(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // swap src/dst to get correct prefix - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x7E, (0xC0 | encode)); } @@ -3582,28 +3664,28 @@ void Assembler::movq(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // swap src/dst to get correct prefix - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x7E, (0xC0 | encode)); } void Assembler::movq(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x6E, (0xC0 | encode)); } void Assembler::movsbl(Register dst, Address src) { // movsxb InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xBE); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xBE); emit_operand(dst, src, 0); } void Assembler::movsbl(Register dst, Register src) { // movsxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); - emit_int24(0x0F, (unsigned char)0xBE, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true, true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBE, 0xC0, encode); } void Assembler::movsd(XMMRegister dst, XMMRegister src) { @@ -3675,14 +3757,14 @@ void Assembler::movss(Address dst, XMMRegister src) { void Assembler::movswl(Register dst, Address src) { // movsxw InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xBF); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xBF); emit_operand(dst, src, 0); } void Assembler::movswl(Register dst, Register src) { // movsxw - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBF, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBF, 0xC0, encode); } void Assembler::movups(XMMRegister dst, Address src) { @@ -3753,27 +3835,27 @@ void Assembler::movw(Address dst, Register src) { void Assembler::movzbl(Register dst, Address src) { // movzxb InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xB6); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xB6); emit_operand(dst, src, 0); } void Assembler::movzbl(Register dst, Register src) { // movzxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); - emit_int24(0x0F, (unsigned char)0xB6, 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true, true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB6, 0xC0, encode); } void Assembler::movzwl(Register dst, Address src) { // movzxw InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xB7); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xB7); emit_operand(dst, src, 0); } void Assembler::movzwl(Register dst, Register src) { // movzxw - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB7, 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB7, 0xC0, encode); } void Assembler::mull(Address src) { @@ -4416,6 +4498,7 @@ void Assembler::ud2() { void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) { assert(VM_Version::supports_sse4_2(), ""); + assert(!needs_eevex(src.base(), src.index()), "does not support extended gprs"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); @@ -4743,7 +4826,7 @@ void Assembler::vmovmskpd(Register dst, XMMRegister src, int vec_enc) { void Assembler::pextrd(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x16, (0xC0 | encode), imm8); } @@ -4761,7 +4844,7 @@ void Assembler::pextrd(Address dst, XMMRegister src, int imm8) { void Assembler::pextrq(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x16, (0xC0 | encode), imm8); } @@ -4797,7 +4880,7 @@ void Assembler::pextrw(Address dst, XMMRegister src, int imm8) { void Assembler::pextrb(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x14, (0xC0 | encode), imm8); } @@ -4815,7 +4898,7 @@ void Assembler::pextrb(Address dst, XMMRegister src, int imm8) { void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x22, (0xC0 | encode), imm8); } @@ -4833,14 +4916,14 @@ void Assembler::pinsrd(XMMRegister dst, Address src, int imm8) { void Assembler::vpinsrd(XMMRegister dst, XMMRegister nds, Register src, int imm8) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x22, (0xC0 | encode), imm8); } void Assembler::pinsrq(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x22, (0xC0 | encode), imm8); } @@ -4858,14 +4941,14 @@ void Assembler::pinsrq(XMMRegister dst, Address src, int imm8) { void Assembler::vpinsrq(XMMRegister dst, XMMRegister nds, Register src, int imm8) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x22, (0xC0 | encode), imm8); } void Assembler::pinsrw(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int24((unsigned char)0xC4, (0xC0 | encode), imm8); } @@ -4883,7 +4966,7 @@ void Assembler::pinsrw(XMMRegister dst, Address src, int imm8) { void Assembler::vpinsrw(XMMRegister dst, XMMRegister nds, Register src, int imm8) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int24((unsigned char)0xC4, (0xC0 | encode), imm8); } @@ -4901,14 +4984,14 @@ void Assembler::pinsrb(XMMRegister dst, Address src, int imm8) { void Assembler::pinsrb(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x20, (0xC0 | encode), imm8); } void Assembler::vpinsrb(XMMRegister dst, XMMRegister nds, Register src, int imm8) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x20, (0xC0 | encode), imm8); } @@ -5311,16 +5394,16 @@ void Assembler::popcntl(Register dst, Address src) { assert(VM_Version::supports_popcnt(), "must support"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xB8); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xB8); emit_operand(dst, src, 0); } void Assembler::popcntl(Register dst, Register src) { assert(VM_Version::supports_popcnt(), "must support"); emit_int8((unsigned char)0xF3); - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB8, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB8, 0xC0, encode); } void Assembler::evpopcntb(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { @@ -5392,48 +5475,48 @@ void Assembler::popl(Address dst) { void Assembler::prefetchnta(Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "must support")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x18); + prefix(src, true /* is_map1 */); + emit_int8(0x18); emit_operand(rax, src, 0); // 0, src } void Assembler::prefetchr(Address src) { assert(VM_Version::supports_3dnow_prefetch(), "must support"); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x0D); + prefix(src, true /* is_map1 */); + emit_int8(0x0D); emit_operand(rax, src, 0); // 0, src } void Assembler::prefetcht0(Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "must support")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x18); + prefix(src, true /* is_map1 */); + emit_int8(0x18); emit_operand(rcx, src, 0); // 1, src } void Assembler::prefetcht1(Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "must support")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x18); + prefix(src, true /* is_map1 */); + emit_int8(0x18); emit_operand(rdx, src, 0); // 2, src } void Assembler::prefetcht2(Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "must support")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x18); + prefix(src, true /* is_map1 */); + emit_int8(0x18); emit_operand(rbx, src, 0); // 3, src } void Assembler::prefetchw(Address src) { assert(VM_Version::supports_3dnow_prefetch(), "must support"); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x0D); + prefix(src, true /* is_map1 */); + emit_int8(0x0D); emit_operand(rcx, src, 0); // 1, src } @@ -5441,6 +5524,12 @@ void Assembler::prefix(Prefix p) { emit_int8(p); } +void Assembler::prefix16(int prefix) { + assert(UseAPX, "APX features not enabled"); + emit_int8((prefix & 0xff00) >> 8); + emit_int8(prefix & 0xff); +} + void Assembler::pshufb(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_ssse3(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -5648,6 +5737,7 @@ void Assembler::vpslldq(XMMRegister dst, XMMRegister src, int shift, int vector_ void Assembler::ptest(XMMRegister dst, Address src) { assert(VM_Version::supports_sse4_1(), ""); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); + assert(!needs_eevex(src.base(), src.index()), "does not support extended gprs"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); @@ -5665,6 +5755,7 @@ void Assembler::ptest(XMMRegister dst, XMMRegister src) { void Assembler::vptest(XMMRegister dst, Address src) { assert(VM_Version::supports_avx(), ""); + assert(!needs_eevex(src.base(), src.index()), "does not support extended gprs"); InstructionMark im(this); InstructionAttr attributes(AVX_256bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); assert(dst != xnoreg, "sanity"); @@ -6078,8 +6169,8 @@ void Assembler::sbbl(Register dst, Register src) { void Assembler::setb(Condition cc, Register dst) { assert(0 <= cc && cc < 16, "illegal cc"); - int encode = prefix_and_encode(dst->encoding(), true); - emit_int24(0x0F, (unsigned char)0x90 | cc, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), true, true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0x90 | cc, 0xC0, encode); } void Assembler::palignr(XMMRegister dst, XMMRegister src, int imm8) { @@ -6212,34 +6303,34 @@ void Assembler::shrl(Address dst, int imm8) { void Assembler::shldl(Register dst, Register src) { - int encode = prefix_and_encode(src->encoding(), dst->encoding()); - emit_int24(0x0F, (unsigned char)0xA5, (0xC0 | encode)); + int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xA5, 0xC0, encode); } void Assembler::shldl(Register dst, Register src, int8_t imm8) { - int encode = prefix_and_encode(src->encoding(), dst->encoding()); - emit_int32(0x0F, (unsigned char)0xA4, (0xC0 | encode), imm8); + int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xA4, 0xC0, encode, imm8); } void Assembler::shrdl(Register dst, Register src) { - int encode = prefix_and_encode(src->encoding(), dst->encoding()); - emit_int24(0x0F, (unsigned char)0xAD, (0xC0 | encode)); + int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAD, 0xC0, encode); } void Assembler::shrdl(Register dst, Register src, int8_t imm8) { - int encode = prefix_and_encode(src->encoding(), dst->encoding()); - emit_int32(0x0F, (unsigned char)0xAC, (0xC0 | encode), imm8); + int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAC, 0xC0, encode, imm8); } #ifdef _LP64 void Assembler::shldq(Register dst, Register src, int8_t imm8) { - int encode = prefixq_and_encode(src->encoding(), dst->encoding()); - emit_int32(0x0F, (unsigned char)0xA4, (0xC0 | encode), imm8); + int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xA4, 0xC0, encode, imm8); } void Assembler::shrdq(Register dst, Register src, int8_t imm8) { - int encode = prefixq_and_encode(src->encoding(), dst->encoding()); - emit_int32(0x0F, (unsigned char)0xAC, (0xC0 | encode), imm8); + int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAC, 0xC0, encode, imm8); } #endif @@ -6305,8 +6396,11 @@ void Assembler::sqrtss(XMMRegister dst, Address src) { emit_operand(dst, src, 0); } -void Assembler::stmxcsr( Address dst) { - if (UseAVX > 0 ) { +void Assembler::stmxcsr(Address dst) { + // This instruction should be SSE encoded with the REX2 prefix when an + // extended GPR is present. To be consistent when UseAPX is enabled, use + // this encoding even when an extended GPR is not used. + if (UseAVX > 0 && !UseAPX ) { assert(VM_Version::supports_avx(), ""); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); @@ -6316,8 +6410,8 @@ void Assembler::stmxcsr( Address dst) { } else { NOT_LP64(assert(VM_Version::supports_sse(), "")); InstructionMark im(this); - prefix(dst); - emit_int16(0x0F, (unsigned char)0xAE); + prefix(dst, true /* is_map1 */); + emit_int8((unsigned char)0xAE); emit_operand(as_Register(3), dst, 0); } } @@ -6457,34 +6551,32 @@ void Assembler::testl(Register dst, Address src) { void Assembler::tzcntl(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); emit_int8((unsigned char)0xF3); - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - (unsigned char)0xBC, - 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::tzcntl(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xBC); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xBC); emit_operand(dst, src, 0); } void Assembler::tzcntq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); emit_int8((unsigned char)0xF3); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBC, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::tzcntq(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefixq(src, dst); - emit_int16(0x0F, (unsigned char)0xBC); + prefixq(src, dst, true /* is_map1 */); + emit_int8((unsigned char)0xBC); emit_operand(dst, src, 0); } @@ -6530,23 +6622,23 @@ void Assembler::xabort(int8_t imm8) { void Assembler::xaddb(Address dst, Register src) { InstructionMark im(this); - prefix(dst, src, true); - emit_int16(0x0F, (unsigned char)0xC0); + prefix(dst, src, true, true /* is_map1 */); + emit_int8((unsigned char)0xC0); emit_operand(src, dst, 0); } void Assembler::xaddw(Address dst, Register src) { InstructionMark im(this); emit_int8(0x66); - prefix(dst, src); - emit_int16(0x0F, (unsigned char)0xC1); + prefix(dst, src, false, true /* is_map1 */); + emit_int8((unsigned char)0xC1); emit_operand(src, dst, 0); } void Assembler::xaddl(Address dst, Register src) { InstructionMark im(this); - prefix(dst, src); - emit_int16(0x0F, (unsigned char)0xC1); + prefix(dst, src, false, true /* is_map1 */); + emit_int8((unsigned char)0xC1); emit_operand(src, dst, 0); } @@ -9116,7 +9208,7 @@ void Assembler::extractps(Register dst, XMMRegister src, uint8_t imm8) { assert(VM_Version::supports_sse4_1(), ""); assert(imm8 <= 0x03, "imm8: %u", imm8); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); // imm8: // 0x00 - extract from bits 31:0 // 0x01 - extract from bits 63:32 @@ -10886,7 +10978,7 @@ void Assembler::evpbroadcastb(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16(0x7A, (0xC0 | encode)); } @@ -10895,7 +10987,7 @@ void Assembler::evpbroadcastw(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes , true); emit_int16(0x7B, (0xC0 | encode)); } @@ -10904,7 +10996,7 @@ void Assembler::evpbroadcastd(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16(0x7C, (0xC0 | encode)); } @@ -10913,7 +11005,7 @@ void Assembler::evpbroadcastq(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16(0x7C, (0xC0 | encode)); } @@ -11673,7 +11765,8 @@ void Assembler::vex_prefix(bool vex_r, bool vex_b, bool vex_x, int nds_enc, VexS } // This is a 4 byte encoding -void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, bool evex_v, int nds_enc, VexSimdPrefix pre, VexOpcode opc){ +void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, bool eevex_b, bool evex_v, + bool eevex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc) { // EVEX 0x62 prefix // byte1 = EVEX_4bytes; @@ -11682,18 +11775,18 @@ void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, boo // EVEX.b is not currently used for broadcast of single element or data rounding modes _attributes->set_evex_encoding(evex_encoding); - // P0: byte 2, initialized to RXBR`00mm + // P0: byte 2, initialized to RXBR'0mmm // instead of not'd int byte2 = (vex_r ? VEX_R : 0) | (vex_x ? VEX_X : 0) | (vex_b ? VEX_B : 0) | (evex_r ? EVEX_Rb : 0); byte2 = (~byte2) & 0xF0; + byte2 |= eevex_b ? EEVEX_B : 0; // confine opc opcode extensions in mm bits to lower two bits - // of form {0F, 0F_38, 0F_3A} + // of form {0F, 0F_38, 0F_3A, 0F_3C} byte2 |= opc; // P1: byte 3 as Wvvvv1pp int byte3 = ((~nds_enc) & 0xf) << 3; - // p[10] is always 1 - byte3 |= EVEX_F; + byte3 |= (eevex_x ? 0 : EEVEX_X); byte3 |= (vex_w & 1) << 7; // confine pre opcode extensions in pp bits to lower two bits // of form {66, F3, F2} @@ -11720,6 +11813,10 @@ void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, boo } void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) { + if (adr.base_needs_rex2() || adr.index_needs_rex2()) { + assert(UseAPX, "APX features not enabled"); + } + bool is_extended = adr.base_needs_rex2() || adr.index_needs_rex2() || nds_enc >= 16 || xreg_enc >= 16; bool vex_r = (xreg_enc & 8) == 8; bool vex_b = adr.base_needs_rex(); bool vex_x; @@ -11729,13 +11826,12 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix vex_x = adr.index_needs_rex(); } set_attributes(attributes); - // For EVEX instruction (which is not marked as pure EVEX instruction) check and see if this instruction // is allowed in legacy mode and has resources which will fit in it. // Pure EVEX instructions will have is_evex_instruction set in their definition. if (!attributes->is_legacy_mode()) { if (UseAVX > 2 && !attributes->is_evex_instruction() && !is_managed()) { - if ((attributes->get_vector_len() != AVX_512bit) && (nds_enc < 16) && (xreg_enc < 16)) { + if ((attributes->get_vector_len() != AVX_512bit) && !is_extended) { attributes->set_is_legacy_mode(); } } @@ -11746,7 +11842,7 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix (attributes->get_vector_len() == AVX_512bit) || (!_legacy_mode_vl) || (attributes->is_legacy_mode())),"XMM register should be 0-15"); - assert(((nds_enc < 16 && xreg_enc < 16) || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); + assert((!is_extended || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); } clear_managed(); @@ -11760,8 +11856,10 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix } else { evex_v = (nds_enc >= 16); } + bool eevex_x = adr.index_needs_rex2(); + bool eevex_b = adr.base_needs_rex2(); attributes->set_is_evex_instruction(); - evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_v, nds_enc, pre, opc); + evex_prefix(vex_r, vex_b, vex_x, evex_r, eevex_b, evex_v, eevex_x, nds_enc, pre, opc); } else { if (UseAVX > 2 && attributes->is_rex_vex_w_reverted()) { attributes->set_rex_vex_w(false); @@ -11770,7 +11868,11 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix } } -int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) { +int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr) { + if (src_is_gpr && src_enc >= 16) { + assert(UseAPX, "APX features not enabled"); + } + bool is_extended = dst_enc >= 16 || nds_enc >= 16 || src_enc >=16; bool vex_r = (dst_enc & 8) == 8; bool vex_b = (src_enc & 8) == 8; bool vex_x = false; @@ -11782,7 +11884,7 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS if (!attributes->is_legacy_mode()) { if (UseAVX > 2 && !attributes->is_evex_instruction() && !is_managed()) { if ((!attributes->uses_vl() || (attributes->get_vector_len() != AVX_512bit)) && - (dst_enc < 16) && (nds_enc < 16) && (src_enc < 16)) { + !is_extended) { attributes->set_is_legacy_mode(); } } @@ -11799,7 +11901,7 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS (!_legacy_mode_vl) || (attributes->is_legacy_mode())),"XMM register should be 0-15"); // Instruction with legacy_mode true should have dst, nds and src < 15 - assert(((dst_enc < 16 && nds_enc < 16 && src_enc < 16) || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); + assert(((!is_extended) || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); } clear_managed(); @@ -11807,10 +11909,11 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS { bool evex_r = (dst_enc >= 16); bool evex_v = (nds_enc >= 16); + bool evex_b = (src_enc >= 16) && src_is_gpr; // can use vex_x as bank extender on rm encoding - vex_x = (src_enc >= 16); + vex_x = (src_enc >= 16) && !src_is_gpr; attributes->set_is_evex_instruction(); - evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_v, nds_enc, pre, opc); + evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_b, evex_v, false /*eevex_x*/, nds_enc, pre, opc); } else { if (UseAVX > 2 && attributes->is_rex_vex_w_reverted()) { attributes->set_rex_vex_w(false); @@ -11822,7 +11925,6 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS return (((dst_enc & 7) << 3) | (src_enc & 7)); } - void Assembler::simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) { if (UseAVX > 0) { @@ -11836,12 +11938,12 @@ void Assembler::simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexS } int Assembler::simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes) { + VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr) { int dst_enc = dst->encoding(); int src_enc = src->encoding(); if (UseAVX > 0) { int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes); + return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes, src_is_gpr); } else { assert((nds == dst) || (nds == src) || (nds == xnoreg), "wrong sse encoding"); return rex_prefix_and_encode(dst_enc, src_enc, pre, opc, attributes->is_rex_vex_w()); @@ -12336,50 +12438,51 @@ void Assembler::evpblendmq (XMMRegister dst, KRegister mask, XMMRegister nds, XM void Assembler::bzhiq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::bzhil(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pextl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pdepl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pextq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pdepq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pextl(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF5); emit_operand(dst, src2, 0); @@ -12388,7 +12491,8 @@ void Assembler::pextl(Register dst, Register src1, Address src2) { void Assembler::pdepl(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF5); emit_operand(dst, src2, 0); @@ -12397,7 +12501,8 @@ void Assembler::pdepl(Register dst, Register src1, Address src2) { void Assembler::pextq(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF5); emit_operand(dst, src2, 0); @@ -12406,7 +12511,8 @@ void Assembler::pextq(Register dst, Register src1, Address src2) { void Assembler::pdepq(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF5); emit_operand(dst, src2, 0); @@ -12414,15 +12520,16 @@ void Assembler::pdepq(Register dst, Register src1, Address src2) { void Assembler::sarxl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::sarxl(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12430,15 +12537,16 @@ void Assembler::sarxl(Register dst, Address src1, Register src2) { void Assembler::sarxq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::sarxq(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12446,15 +12554,16 @@ void Assembler::sarxq(Register dst, Address src1, Register src2) { void Assembler::shlxl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::shlxl(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12462,15 +12571,16 @@ void Assembler::shlxl(Register dst, Address src1, Register src2) { void Assembler::shlxq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::shlxq(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12478,15 +12588,16 @@ void Assembler::shlxq(Register dst, Address src1, Register src2) { void Assembler::shrxl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::shrxl(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12494,15 +12605,16 @@ void Assembler::shrxl(Register dst, Address src1, Register src2) { void Assembler::shrxq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::shrxq(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12806,13 +12918,48 @@ void Assembler::emit_data64(jlong data, emit_int64(data); } +int Assembler::get_base_prefix_bits(int enc) { + int bits = 0; + if (enc & 16) bits |= REX2BIT_B4; + if (enc & 8) bits |= REXBIT_B; + return bits; +} + +int Assembler::get_index_prefix_bits(int enc) { + int bits = 0; + if (enc & 16) bits |= REX2BIT_X4; + if (enc & 8) bits |= REXBIT_X; + return bits; +} + +int Assembler::get_base_prefix_bits(Register base) { + return base->is_valid() ? get_base_prefix_bits(base->encoding()) : 0; +} + +int Assembler::get_index_prefix_bits(Register index) { + return index->is_valid() ? get_index_prefix_bits(index->encoding()) : 0; +} + +int Assembler::get_reg_prefix_bits(int enc) { + int bits = 0; + if (enc & 16) bits |= REX2BIT_R4; + if (enc & 8) bits |= REXBIT_R; + return bits; +} + void Assembler::prefix(Register reg) { - if (reg->encoding() >= 8) { + if (reg->encoding() >= 16) { + prefix16(WREX2 | get_base_prefix_bits(reg->encoding())); + } else if (reg->encoding() >= 8) { prefix(REX_B); } } void Assembler::prefix(Register dst, Register src, Prefix p) { + if ((p & WREX2) || src->encoding() >= 16 || dst->encoding() >= 16) { + prefix_rex2(dst, src); + return; + } if (src->encoding() >= 8) { p = (Prefix)(p | REX_B); } @@ -12825,7 +12972,17 @@ void Assembler::prefix(Register dst, Register src, Prefix p) { } } +void Assembler::prefix_rex2(Register dst, Register src) { + int bits = 0; + bits |= get_base_prefix_bits(src->encoding()); + bits |= get_reg_prefix_bits(dst->encoding()); + prefix16(WREX2 | bits); +} + void Assembler::prefix(Register dst, Address adr, Prefix p) { + if (adr.base_needs_rex2() || adr.index_needs_rex2() || dst->encoding() >= 16) { + prefix_rex2(dst, adr); + } if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { assert(false, "prefix(Register dst, Address adr, Prefix p) does not support handling of an X"); @@ -12846,7 +13003,19 @@ void Assembler::prefix(Register dst, Address adr, Prefix p) { } } -void Assembler::prefix(Address adr) { +void Assembler::prefix_rex2(Register dst, Address adr) { + assert(!adr.index_needs_rex2(), "prefix(Register dst, Address adr) does not support handling of an X"); + int bits = 0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_reg_prefix_bits(dst->encoding()); + prefix16(WREX2 | bits); +} + +void Assembler::prefix(Address adr, bool is_map1) { + if (adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefix_rex2(adr, is_map1); + return; + } if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { prefix(REX_XB); @@ -12858,9 +13027,21 @@ void Assembler::prefix(Address adr) { prefix(REX_X); } } + if (is_map1) emit_int8(0x0F); +} + +void Assembler::prefix_rex2(Address adr, bool is_map1) { + int bits = is_map1 ? REX2BIT_M0 : 0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + prefix16(WREX2 | bits); } -void Assembler::prefix(Address adr, Register reg, bool byteinst) { +void Assembler::prefix(Address adr, Register reg, bool byteinst, bool is_map1) { + if (reg->encoding() >= 16 || adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefix_rex2(adr, reg, byteinst, is_map1); + return; + } if (reg->encoding() < 8) { if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { @@ -12890,9 +13071,22 @@ void Assembler::prefix(Address adr, Register reg, bool byteinst) { } } } + if (is_map1) emit_int8(0x0F); +} + +void Assembler::prefix_rex2(Address adr, Register reg, bool byteinst, bool is_map1) { + int bits = is_map1 ? REX2BIT_M0 : 0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + bits |= get_reg_prefix_bits(reg->encoding()); + prefix16(WREX2 | bits); } void Assembler::prefix(Address adr, XMMRegister reg) { + if (reg->encoding() >= 16 || adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefixq_rex2(adr, reg); + return; + } if (reg->encoding() < 8) { if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { @@ -12922,17 +13116,37 @@ void Assembler::prefix(Address adr, XMMRegister reg) { } } -int Assembler::prefix_and_encode(int reg_enc, bool byteinst) { +void Assembler::prefix_rex2(Address adr, XMMRegister src) { + int bits = 0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + bits |= get_reg_prefix_bits(src->encoding()); + prefix16(WREX2 | bits); +} + +int Assembler::prefix_and_encode(int reg_enc, bool byteinst, bool is_map1) { + if (reg_enc >= 16) { + return prefix_and_encode_rex2(reg_enc, is_map1); + } if (reg_enc >= 8) { prefix(REX_B); reg_enc -= 8; } else if (byteinst && reg_enc >= 4) { prefix(REX); } - return reg_enc; + int opc_prefix = is_map1 ? 0x0F00 : 0; + return opc_prefix | reg_enc; } -int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { +int Assembler::prefix_and_encode_rex2(int reg_enc, bool is_map1) { + prefix16(WREX2 | (is_map1 ? REX2BIT_M0 : 0) | get_base_prefix_bits(reg_enc)); + return reg_enc & 0x7; +} + +int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte, bool is_map1) { + if (src_enc >= 16 || dst_enc >= 16) { + return prefix_and_encode_rex2(dst_enc, src_enc, is_map1 ? REX2BIT_M0 : 0); + } if (dst_enc < 8) { if (src_enc >= 8) { prefix(REX_B); @@ -12949,16 +13163,46 @@ int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, boo } dst_enc -= 8; } + int opcode_prefix = is_map1 ? 0x0F00 : 0; + return opcode_prefix | (dst_enc << 3 | src_enc); +} + +int Assembler::prefix_and_encode_rex2(int dst_enc, int src_enc, int init_bits) { + int bits = init_bits; + bits |= get_reg_prefix_bits(dst_enc); + bits |= get_base_prefix_bits(src_enc); + dst_enc &= 0x7; + src_enc &= 0x7; + prefix16(WREX2 | bits); return dst_enc << 3 | src_enc; } -int8_t Assembler::get_prefixq(Address adr) { +bool Assembler::prefix_is_rex2(int prefix) { + return (prefix & 0xFF00) == WREX2; +} + +int Assembler::get_prefixq(Address adr, bool is_map1) { + if (adr.base_needs_rex2() || adr.index_needs_rex2()) { + return get_prefixq_rex2(adr, is_map1); + } int8_t prfx = get_prefixq(adr, rax); assert(REX_W <= prfx && prfx <= REX_WXB, "must be"); - return prfx; + return is_map1 ? (((int16_t)prfx) << 8) | 0x0F : (int16_t)prfx; +} + +int Assembler::get_prefixq_rex2(Address adr, bool is_map1) { + assert(UseAPX, "APX features not enabled"); + int bits = REXBIT_W; + if (is_map1) bits |= REX2BIT_M0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + return WREX2 | bits; } -int8_t Assembler::get_prefixq(Address adr, Register src) { +int Assembler::get_prefixq(Address adr, Register src, bool is_map1) { + if (adr.base_needs_rex2() || adr.index_needs_rex2() || src->encoding() >= 16) { + return get_prefixq_rex2(adr, src, is_map1); + } int8_t prfx = (int8_t)(REX_W + ((int)adr.base_needs_rex()) + ((int)adr.index_needs_rex() << 1) + @@ -12994,18 +13238,42 @@ int8_t Assembler::get_prefixq(Address adr, Register src) { } } #endif - return prfx; + return is_map1 ? (((int16_t)prfx) << 8) | 0x0F : (int16_t)prfx; +} + +int Assembler::get_prefixq_rex2(Address adr, Register src, bool is_map1) { + assert(UseAPX, "APX features not enabled"); + int bits = REXBIT_W; + if (is_map1) bits |= REX2BIT_M0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + bits |= get_reg_prefix_bits(src->encoding()); + return WREX2 | bits; } void Assembler::prefixq(Address adr) { - emit_int8(get_prefixq(adr)); + if (adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefix16(get_prefixq_rex2(adr)); + } else { + emit_int8(get_prefixq(adr)); + } } -void Assembler::prefixq(Address adr, Register src) { - emit_int8(get_prefixq(adr, src)); +void Assembler::prefixq(Address adr, Register src, bool is_map1) { + if (adr.base_needs_rex2() || adr.index_needs_rex2() || src->encoding() >= 16) { + prefix16(get_prefixq_rex2(adr, src, is_map1)); + } else { + emit_int8(get_prefixq(adr, src)); + if (is_map1) emit_int8(0x0F); + } } + void Assembler::prefixq(Address adr, XMMRegister src) { + if (src->encoding() >= 16 || adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefixq_rex2(adr, src); + return; + } if (src->encoding() < 8) { if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { @@ -13037,17 +13305,38 @@ void Assembler::prefixq(Address adr, XMMRegister src) { } } -int Assembler::prefixq_and_encode(int reg_enc) { +void Assembler::prefixq_rex2(Address adr, XMMRegister src) { + int bits = REXBIT_W; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + bits |= get_reg_prefix_bits(src->encoding()); + prefix16(WREX2 | bits); +} + +int Assembler::prefixq_and_encode(int reg_enc, bool is_map1) { + if (reg_enc >= 16) { + return prefixq_and_encode_rex2(reg_enc, is_map1); + } if (reg_enc < 8) { prefix(REX_W); } else { prefix(REX_WB); reg_enc -= 8; } - return reg_enc; + int opcode_prefix = is_map1 ? 0x0F00 : 0; + return opcode_prefix | reg_enc; } -int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { + +int Assembler::prefixq_and_encode_rex2(int reg_enc, bool is_map1) { + prefix16(WREX2 | REXBIT_W | (is_map1 ? REX2BIT_M0: 0) | get_base_prefix_bits(reg_enc)); + return reg_enc & 0x7; +} + +int Assembler::prefixq_and_encode(int dst_enc, int src_enc, bool is_map1) { + if (dst_enc >= 16 || src_enc >= 16) { + return prefixq_and_encode_rex2(dst_enc, src_enc, is_map1); + } if (dst_enc < 8) { if (src_enc < 8) { prefix(REX_W); @@ -13064,7 +13353,22 @@ int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { } dst_enc -= 8; } - return dst_enc << 3 | src_enc; + int opcode_prefix = is_map1 ? 0x0F00 : 0; + return opcode_prefix | (dst_enc << 3 | src_enc); +} + +int Assembler::prefixq_and_encode_rex2(int dst_enc, int src_enc, bool is_map1) { + int init_bits = REXBIT_W | (is_map1 ? REX2BIT_M0 : 0); + return prefix_and_encode_rex2(dst_enc, src_enc, init_bits); +} + +void Assembler::emit_prefix_and_int8(int prefix, int b1) { + if ((prefix & 0xFF00) == 0) { + emit_int16(prefix, b1); + } else { + assert((prefix & 0xFF00) != WREX2 || UseAPX, "APX features not enabled"); + emit_int24((prefix & 0xFF00) >> 8, prefix & 0x00FF, b1); + } } void Assembler::adcq(Register dst, int32_t imm32) { @@ -13074,7 +13378,7 @@ void Assembler::adcq(Register dst, int32_t imm32) { void Assembler::adcq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x13); + emit_prefix_and_int8(get_prefixq(src, dst), 0x13); emit_operand(dst, src, 0); } @@ -13091,7 +13395,7 @@ void Assembler::addq(Address dst, int32_t imm32) { void Assembler::addq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x01); + emit_prefix_and_int8(get_prefixq(dst, src), 0x01); emit_operand(src, dst, 0); } @@ -13102,7 +13406,7 @@ void Assembler::addq(Register dst, int32_t imm32) { void Assembler::addq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x03); + emit_prefix_and_int8(get_prefixq(src, dst), 0x03); emit_operand(dst, src, 0); } @@ -13113,24 +13417,35 @@ void Assembler::addq(Register dst, Register src) { void Assembler::adcxq(Register dst, Register src) { //assert(VM_Version::supports_adx(), "adx instructions not supported"); - emit_int8(0x66); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int32(0x0F, - 0x38, - (unsigned char)0xF6, - (0xC0 | encode)); + if (needs_rex2(dst, src)) { + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C, &attributes, true); + emit_int16((unsigned char)0x66, (0xC0 | encode)); + } else { + emit_int8(0x66); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_int32(0x0F, + 0x38, + (unsigned char)0xF6, + (0xC0 | encode)); + } } void Assembler::adoxq(Register dst, Register src) { //assert(VM_Version::supports_adx(), "adx instructions not supported"); - emit_int8((unsigned char)0xF3); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int32(0x0F, - 0x38, - (unsigned char)0xF6, - (0xC0 | encode)); + if (needs_rex2(dst, src)) { + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_3C, &attributes, true); + emit_int16((unsigned char)0x66, (0xC0 | encode)); + } else { + emit_int8((unsigned char)0xF3); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_int32(0x0F, + 0x38, + (unsigned char)0xF6, + (0xC0 | encode)); + } } - void Assembler::andq(Address dst, int32_t imm32) { InstructionMark im(this); prefixq(dst); @@ -13144,7 +13459,7 @@ void Assembler::andq(Register dst, int32_t imm32) { void Assembler::andq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x23); + emit_prefix_and_int8(get_prefixq(src, dst), 0x23); emit_operand(dst, src, 0); } @@ -13155,52 +13470,54 @@ void Assembler::andq(Register dst, Register src) { void Assembler::andq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x21); + emit_prefix_and_int8(get_prefixq(dst, src), 0x21); emit_operand(src, dst, 0); } void Assembler::andnq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF2, (0xC0 | encode)); } void Assembler::andnq(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF2); emit_operand(dst, src2, 0); } void Assembler::bsfq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBC, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::bsrq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBD, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode); } void Assembler::bswapq(Register reg) { - int encode = prefixq_and_encode(reg->encoding()); - emit_int16(0x0F, (0xC8 | encode)); + int encode = prefixq_and_encode(reg->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xC8, encode); } void Assembler::blsiq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsiq(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src, dst->encoding(), rbx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rbx, src, 0); @@ -13208,15 +13525,16 @@ void Assembler::blsiq(Register dst, Address src) { void Assembler::blsmskq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsmskq(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src, dst->encoding(), rdx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rdx, src, 0); @@ -13224,15 +13542,16 @@ void Assembler::blsmskq(Register dst, Address src) { void Assembler::blsrq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsrq(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src, dst->encoding(), rcx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rcx, src, 0); @@ -13248,8 +13567,8 @@ void Assembler::cdqe() { void Assembler::clflush(Address adr) { assert(VM_Version::supports_clflush(), "should do"); - prefix(adr); - emit_int16(0x0F, (unsigned char)0xAE); + prefix(adr, true /* is_map1 */); + emit_int8((unsigned char)0xAE); emit_operand(rdi, adr, 0); } @@ -13261,9 +13580,9 @@ void Assembler::clflushopt(Address adr) { assert(adr.disp() == 0, "displacement should be 0"); // instruction prefix is 0x66 emit_int8(0x66); - prefix(adr); + prefix(adr, true /* is_map1 */); // opcode family is 0x0F 0xAE - emit_int16(0x0F, (unsigned char)0xAE); + emit_int8((unsigned char)0xAE); // extended opcode byte is 7 == rdi emit_operand(rdi, adr, 0); } @@ -13276,21 +13595,22 @@ void Assembler::clwb(Address adr) { assert(adr.disp() == 0, "displacement should be 0"); // instruction prefix is 0x66 emit_int8(0x66); - prefix(adr); + prefix(adr, true /* is_map1 */); // opcode family is 0x0f 0xAE - emit_int16(0x0F, (unsigned char)0xAE); + emit_int8((unsigned char)0xAE); // extended opcode byte is 6 == rsi emit_operand(rsi, adr, 0); } void Assembler::cmovq(Condition cc, Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (0x40 | cc), (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((0x40 | cc), 0xC0, encode); } void Assembler::cmovq(Condition cc, Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), 0x0F, (0x40 | cc)); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (0x40 | cc)); emit_operand(dst, src, 0); } @@ -13307,7 +13627,7 @@ void Assembler::cmpq(Register dst, int32_t imm32) { void Assembler::cmpq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x39); + emit_prefix_and_int8(get_prefixq(dst, src), 0x39); emit_operand(src, dst, 0); } @@ -13318,20 +13638,21 @@ void Assembler::cmpq(Register dst, Register src) { void Assembler::cmpq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x3B); + emit_prefix_and_int8(get_prefixq(src, dst), 0x3B); emit_operand(dst, src, 0); } void Assembler::cmpxchgq(Register reg, Address adr) { InstructionMark im(this); - emit_int24(get_prefixq(adr, reg), 0x0F, (unsigned char)0xB1); + int prefix = get_prefixq(adr, reg, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xB1); emit_operand(reg, adr, 0); } void Assembler::cvtsi2sdq(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes, true); emit_int16(0x2A, (0xC0 | encode)); } @@ -13360,7 +13681,9 @@ void Assembler::cvttsd2siq(Register dst, Address src) { // F2 REX.W 0F 2C /r // CVTTSD2SI r64, xmm1/m64 InstructionMark im(this); - emit_int32((unsigned char)0xF2, REX_W, 0x0F, 0x2C); + emit_int8((unsigned char)0xF2); + prefixq(src, dst, true /* is_map1 */); + emit_int8((unsigned char)0x2C); emit_operand(dst, src, 0); } @@ -13402,28 +13725,32 @@ void Assembler::decq(Register dst) { void Assembler::decq(Address dst) { // Don't use it directly. Use MacroAssembler::decrementq() instead. InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xFF); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xFF); emit_operand(rcx, dst, 0); } +// can't use REX2 void Assembler::fxrstor(Address src) { InstructionMark im(this); emit_int24(get_prefixq(src), 0x0F, (unsigned char)0xAE); emit_operand(as_Register(1), src, 0); } +// can't use REX2 void Assembler::xrstor(Address src) { InstructionMark im(this); emit_int24(get_prefixq(src), 0x0F, (unsigned char)0xAE); emit_operand(as_Register(5), src, 0); } +// can't use REX2 void Assembler::fxsave(Address dst) { InstructionMark im(this); emit_int24(get_prefixq(dst), 0x0F, (unsigned char)0xAE); emit_operand(as_Register(0), dst, 0); } +// cant use REX2 void Assembler::xsave(Address dst) { InstructionMark im(this); emit_int24(get_prefixq(dst), 0x0F, (unsigned char)0xAE); @@ -13441,8 +13768,8 @@ void Assembler::divq(Register src) { } void Assembler::imulq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xAF, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAF, 0xC0, encode); } void Assembler::imulq(Register src) { @@ -13476,7 +13803,8 @@ void Assembler::imulq(Register dst, Register src, int value) { void Assembler::imulq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), 0x0F, (unsigned char)0xAF); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xAF); emit_operand(dst, src, 0); } @@ -13497,7 +13825,7 @@ void Assembler::incq(Register dst) { void Assembler::incq(Address dst) { // Don't use it directly. Use MacroAssembler::incrementq() instead. InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xFF); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xFF); emit_operand(rax, dst, 0); } @@ -13507,7 +13835,7 @@ void Assembler::lea(Register dst, Address src) { void Assembler::leaq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), (unsigned char)0x8D); + emit_prefix_and_int8(get_prefixq(src, dst), (unsigned char)0x8D); emit_operand(dst, src, 0); } @@ -13565,16 +13893,16 @@ void Assembler::cmp_narrow_oop(Address src1, int32_t imm32, RelocationHolder con void Assembler::lzcntq(Register dst, Register src) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); emit_int8((unsigned char)0xF3); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBD, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode); } void Assembler::lzcntq(Register dst, Address src) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefixq(src, dst); - emit_int16(0x0F, (unsigned char)0xBD); + prefixq(src, dst, true /* is_map1 */); + emit_int8((unsigned char)0xBD); emit_operand(dst, src, 0); } @@ -13582,7 +13910,7 @@ void Assembler::movdq(XMMRegister dst, Register src) { // table D-1 says MMX/SSE2 NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x6E, (0xC0 | encode)); } @@ -13591,7 +13919,7 @@ void Assembler::movdq(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // swap src/dst to get correct prefix - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x7E, (0xC0 | encode)); } @@ -13604,19 +13932,19 @@ void Assembler::movq(Register dst, Register src) { void Assembler::movq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), (unsigned char)0x8B); + emit_prefix_and_int8(get_prefixq(src, dst), (unsigned char)0x8B); emit_operand(dst, src, 0); } void Assembler::movq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), (unsigned char)0x89); + emit_prefix_and_int8(get_prefixq(dst, src), (unsigned char)0x89); emit_operand(src, dst, 0); } void Assembler::movq(Address dst, int32_t imm32) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xC7); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC7); emit_operand(as_Register(0), dst, 4); emit_int32(imm32); } @@ -13629,28 +13957,27 @@ void Assembler::movq(Register dst, int32_t imm32) { void Assembler::movsbq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), - 0x0F, - (unsigned char)0xBE); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xBE); emit_operand(dst, src, 0); } void Assembler::movsbq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBE, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBE, 0xC0, encode); } void Assembler::movslq(Address dst, int32_t imm32) { assert(is_simm32(imm32), "lost bits"); InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xC7); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC7); emit_operand(rax, dst, 4); emit_int32(imm32); } void Assembler::movslq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x63); + emit_prefix_and_int8(get_prefixq(src, dst), 0x63); emit_operand(dst, src, 0); } @@ -13661,46 +13988,43 @@ void Assembler::movslq(Register dst, Register src) { void Assembler::movswq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), - 0x0F, - (unsigned char)0xBF); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xBF); emit_operand(dst, src, 0); } void Assembler::movswq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBF, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBF, 0xC0, encode); } void Assembler::movzbq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), - 0x0F, - (unsigned char)0xB6); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xB6); emit_operand(dst, src, 0); } void Assembler::movzbq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB6, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB6, 0xC0, encode); } void Assembler::movzwq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), - 0x0F, - (unsigned char)0xB7); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xB7); emit_operand(dst, src, 0); } void Assembler::movzwq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB7, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB7, 0xC0, encode); } void Assembler::mulq(Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src), (unsigned char)0xF7); + emit_prefix_and_int8(get_prefixq(src), (unsigned char)0xF7); emit_operand(rsp, src, 0); } @@ -13711,8 +14035,8 @@ void Assembler::mulq(Register src) { void Assembler::mulxq(Register dst1, Register dst2, Register src) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst1->encoding(), dst2->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst1->encoding(), dst2->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF6, (0xC0 | encode)); } @@ -13723,7 +14047,7 @@ void Assembler::negq(Register dst) { void Assembler::negq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xF7); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xF7); emit_operand(as_Register(3), dst, 0); } @@ -13733,24 +14057,22 @@ void Assembler::notq(Register dst) { } void Assembler::btq(Register dst, Register src) { - int encode = prefixq_and_encode(src->encoding(), dst->encoding()); - emit_int24(0x0F, (unsigned char)0xA3, (encode | 0xC0)); + int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xA3, 0xC0, encode); } void Assembler::btq(Register src, int imm8) { assert(isByte(imm8), "not a byte"); - int encode = prefixq_and_encode(src->encoding()); - emit_int16(0x0f, 0xba); - emit_int8(0xe0|encode); + int encode = prefixq_and_encode(src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBA, 0xE0, encode); emit_int8(imm8); } void Assembler::btsq(Address dst, int imm8) { assert(isByte(imm8), "not a byte"); InstructionMark im(this); - emit_int24(get_prefixq(dst), - 0x0F, - (unsigned char)0xBA); + int prefix = get_prefixq(dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xBA); emit_operand(rbp /* 5 */, dst, 1); emit_int8(imm8); } @@ -13758,9 +14080,8 @@ void Assembler::btsq(Address dst, int imm8) { void Assembler::btrq(Address dst, int imm8) { assert(isByte(imm8), "not a byte"); InstructionMark im(this); - emit_int24(get_prefixq(dst), - 0x0F, - (unsigned char)0xBA); + int prefix = get_prefixq(dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xBA); emit_operand(rsi /* 6 */, dst, 1); emit_int8(imm8); } @@ -13773,7 +14094,7 @@ void Assembler::orq(Address dst, int32_t imm32) { void Assembler::orq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), (unsigned char)0x09); + emit_prefix_and_int8(get_prefixq(dst, src), (unsigned char)0x09); emit_operand(src, dst, 0); } @@ -13789,7 +14110,7 @@ void Assembler::orq_imm32(Register dst, int32_t imm32) { void Assembler::orq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x0B); + emit_prefix_and_int8(get_prefixq(src, dst), 0x0B); emit_operand(dst, src, 0); } @@ -13801,28 +14122,27 @@ void Assembler::orq(Register dst, Register src) { void Assembler::popcntq(Register dst, Address src) { assert(VM_Version::supports_popcnt(), "must support"); InstructionMark im(this); - emit_int32((unsigned char)0xF3, - get_prefixq(src, dst), - 0x0F, - (unsigned char)0xB8); + emit_int8((unsigned char)0xF3); + emit_prefix_and_int8(get_prefixq(src, dst, true /* is_map1 */), (unsigned char) 0xB8); emit_operand(dst, src, 0); } void Assembler::popcntq(Register dst, Register src) { assert(VM_Version::supports_popcnt(), "must support"); emit_int8((unsigned char)0xF3); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB8, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB8, 0xC0, encode); } void Assembler::popq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0x8F); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0x8F); emit_operand(rax, dst, 0); } void Assembler::popq(Register dst) { - emit_int8((unsigned char)0x58 | dst->encoding()); + int encode = prefix_and_encode(dst->encoding()); + emit_int8((unsigned char)0x58 | encode); } // Precomputable: popa, pusha, vzeroupper @@ -13962,7 +14282,7 @@ void Assembler::vzeroall() { void Assembler::pushq(Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src), (unsigned char)0xFF); + emit_prefix_and_int8(get_prefixq(src), (unsigned char)0xFF); emit_operand(rsi, src, 0); } @@ -13988,15 +14308,16 @@ void Assembler::rcrq(Register dst, int imm8) { void Assembler::rorxl(Register dst, Register src, int imm8) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes, true); emit_int24((unsigned char)0xF0, (0xC0 | encode), imm8); } void Assembler::rorxl(Register dst, Address src, int imm8) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes); emit_int8((unsigned char)0xF0); emit_operand(dst, src, 1); @@ -14005,15 +14326,16 @@ void Assembler::rorxl(Register dst, Address src, int imm8) { void Assembler::rorxq(Register dst, Register src, int imm8) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes, true); emit_int24((unsigned char)0xF0, (0xC0 | encode), imm8); } void Assembler::rorxq(Register dst, Address src, int imm8) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes); emit_int8((unsigned char)0xF0); emit_operand(dst, src, 1); @@ -14025,11 +14347,11 @@ void Assembler::salq(Address dst, int imm8) { InstructionMark im(this); assert(isShiftCount(imm8 >> 1), "illegal shift count"); if (imm8 == 1) { - emit_int16(get_prefixq(dst), (unsigned char)0xD1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD1); emit_operand(as_Register(4), dst, 0); } else { - emit_int16(get_prefixq(dst), (unsigned char)0xC1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC1); emit_operand(as_Register(4), dst, 1); emit_int8(imm8); } @@ -14037,7 +14359,7 @@ void Assembler::salq(Address dst, int imm8) { void Assembler::salq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xD3); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD3); emit_operand(as_Register(4), dst, 0); } @@ -14060,11 +14382,11 @@ void Assembler::sarq(Address dst, int imm8) { InstructionMark im(this); assert(isShiftCount(imm8 >> 1), "illegal shift count"); if (imm8 == 1) { - emit_int16(get_prefixq(dst), (unsigned char)0xD1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD1); emit_operand(as_Register(7), dst, 0); } else { - emit_int16(get_prefixq(dst), (unsigned char)0xC1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC1); emit_operand(as_Register(7), dst, 1); emit_int8(imm8); } @@ -14072,7 +14394,7 @@ void Assembler::sarq(Address dst, int imm8) { void Assembler::sarq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xD3); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD3); emit_operand(as_Register(7), dst, 0); } @@ -14105,7 +14427,7 @@ void Assembler::sbbq(Register dst, int32_t imm32) { void Assembler::sbbq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x1B); + emit_prefix_and_int8(get_prefixq(src, dst), 0x1B); emit_operand(dst, src, 0); } @@ -14147,7 +14469,7 @@ void Assembler::shrq(Register dst) { void Assembler::shrq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xD3); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD3); emit_operand(as_Register(5), dst, 0); } @@ -14155,11 +14477,11 @@ void Assembler::shrq(Address dst, int imm8) { InstructionMark im(this); assert(isShiftCount(imm8 >> 1), "illegal shift count"); if (imm8 == 1) { - emit_int16(get_prefixq(dst), (unsigned char)0xD1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD1); emit_operand(as_Register(5), dst, 0); } else { - emit_int16(get_prefixq(dst), (unsigned char)0xC1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC1); emit_operand(as_Register(5), dst, 1); emit_int8(imm8); } @@ -14173,7 +14495,7 @@ void Assembler::subq(Address dst, int32_t imm32) { void Assembler::subq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x29); + emit_prefix_and_int8(get_prefixq(dst, src), 0x29); emit_operand(src, dst, 0); } @@ -14190,7 +14512,7 @@ void Assembler::subq_imm32(Register dst, int32_t imm32) { void Assembler::subq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x2B); + emit_prefix_and_int8(get_prefixq(src, dst), 0x2B); emit_operand(dst, src, 0); } @@ -14201,7 +14523,7 @@ void Assembler::subq(Register dst, Register src) { void Assembler::testq(Address dst, int32_t imm32) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xF7); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xF7); emit_operand(as_Register(0), dst, 4); emit_int32(imm32); } @@ -14229,19 +14551,20 @@ void Assembler::testq(Register dst, Register src) { void Assembler::testq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), (unsigned char)0x85); + emit_prefix_and_int8(get_prefixq(src, dst), (unsigned char)0x85); emit_operand(dst, src, 0); } void Assembler::xaddq(Address dst, Register src) { InstructionMark im(this); - emit_int24(get_prefixq(dst, src), 0x0F, (unsigned char)0xC1); + int prefix = get_prefixq(dst, src, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xC1); emit_operand(src, dst, 0); } void Assembler::xchgq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), (unsigned char)0x87); + emit_prefix_and_int8(get_prefixq(src, dst), (unsigned char)0x87); emit_operand(dst, src, 0); } @@ -14257,7 +14580,7 @@ void Assembler::xorq(Register dst, Register src) { void Assembler::xorq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x33); + emit_prefix_and_int8(get_prefixq(src, dst), 0x33); emit_operand(dst, src, 0); } @@ -14274,7 +14597,7 @@ void Assembler::xorq(Address dst, int32_t imm32) { void Assembler::xorq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x31); + emit_prefix_and_int8(get_prefixq(dst, src), 0x31); emit_operand(src, dst, 0); } diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 097bc9de62a39..32a81519f82ce 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -308,17 +308,29 @@ class Address { private: bool base_needs_rex() const { - return _base->is_valid() && _base->encoding() >= 8; + return _base->is_valid() && ((_base->encoding() & 8) == 8); + } + + bool base_needs_rex2() const { + return _base->is_valid() && _base->encoding() >= 16; } bool index_needs_rex() const { - return _index->is_valid() &&_index->encoding() >= 8; + return _index->is_valid() && ((_index->encoding() & 8) == 8); + } + + bool index_needs_rex2() const { + return _index->is_valid() &&_index->encoding() >= 16; } bool xmmindex_needs_rex() const { return _xmmindex->is_valid() && ((_xmmindex->encoding() & 8) == 8); } + bool xmmindex_needs_rex2() const { + return _xmmindex->is_valid() && _xmmindex->encoding() >= 16; + } + relocInfo::relocType reloc() const { return _rspec.type(); } friend class Assembler; @@ -508,12 +520,26 @@ class Assembler : public AbstractAssembler { REX_WRX = 0x4E, REX_WRXB = 0x4F, + REX2 = 0xd5, + WREX2 = REX2 << 8, + VEX_3bytes = 0xC4, VEX_2bytes = 0xC5, EVEX_4bytes = 0x62, Prefix_EMPTY = 0x0 }; + enum PrefixBits { + REXBIT_B = 0x01, + REXBIT_X = 0x02, + REXBIT_R = 0x04, + REXBIT_W = 0x08, + REX2BIT_B4 = 0x10, + REX2BIT_X4 = 0x20, + REX2BIT_R4 = 0x40, + REX2BIT_M0 = 0x80 + }; + enum VexPrefix { VEX_B = 0x20, VEX_X = 0x40, @@ -525,10 +551,18 @@ class Assembler : public AbstractAssembler { EVEX_F = 0x04, EVEX_V = 0x08, EVEX_Rb = 0x10, + EVEX_B = 0x20, EVEX_X = 0x40, EVEX_Z = 0x80 }; + enum ExtEvexPrefix { + EEVEX_R = 0x10, + EEVEX_B = 0x08, + EEVEX_X = 0x04, + EEVEX_V = 0x08 + }; + enum EvexRoundPrefix { EVEX_RNE = 0x0, EVEX_RD = 0x1, @@ -540,7 +574,7 @@ class Assembler : public AbstractAssembler { VEX_SIMD_NONE = 0x0, VEX_SIMD_66 = 0x1, VEX_SIMD_F3 = 0x2, - VEX_SIMD_F2 = 0x3 + VEX_SIMD_F2 = 0x3, }; enum VexOpcode { @@ -548,6 +582,7 @@ class Assembler : public AbstractAssembler { VEX_OPCODE_0F = 0x1, VEX_OPCODE_0F_38 = 0x2, VEX_OPCODE_0F_3A = 0x3, + VEX_OPCODE_0F_3C = 0x4, VEX_OPCODE_MASK = 0x1F }; @@ -572,7 +607,8 @@ class Assembler : public AbstractAssembler { EVEX_OVM = 20, EVEX_M128 = 21, EVEX_DUP = 22, - EVEX_ETUP = 23 + EVEX_NOSCALE = 23, + EVEX_ETUP = 24 }; enum EvexInputSizeInBits { @@ -686,33 +722,62 @@ class Assembler : public AbstractAssembler { InstructionAttr *_attributes; void set_attributes(InstructionAttr* attributes); + int get_base_prefix_bits(int enc); + int get_index_prefix_bits(int enc); + int get_base_prefix_bits(Register base); + int get_index_prefix_bits(Register index); + int get_reg_prefix_bits(int enc); + // 64bit prefixes void prefix(Register reg); void prefix(Register dst, Register src, Prefix p); + void prefix_rex2(Register dst, Register src); void prefix(Register dst, Address adr, Prefix p); - - void prefix(Address adr); - void prefix(Address adr, Register reg, bool byteinst = false); + void prefix_rex2(Register dst, Address adr); + + // The is_map1 bool indicates an x86 map1 instruction which, when + // legacy encoded, uses a 0x0F opcode prefix. By specification, the + // opcode prefix is omitted when using rex2 encoding in support + // of APX extended GPRs. + void prefix(Address adr, bool is_map1 = false); + void prefix_rex2(Address adr, bool is_map1 = false); + void prefix(Address adr, Register reg, bool byteinst = false, bool is_map1 = false); + void prefix_rex2(Address adr, Register reg, bool byteinst = false, bool is_map1 = false); void prefix(Address adr, XMMRegister reg); + void prefix_rex2(Address adr, XMMRegister reg); - int prefix_and_encode(int reg_enc, bool byteinst = false); - int prefix_and_encode(int dst_enc, int src_enc) { - return prefix_and_encode(dst_enc, false, src_enc, false); + int prefix_and_encode(int reg_enc, bool byteinst = false, bool is_map1 = false); + int prefix_and_encode_rex2(int reg_enc, bool is_map1 = false); + int prefix_and_encode(int dst_enc, int src_enc, bool is_map1 = false) { + return prefix_and_encode(dst_enc, false, src_enc, false, is_map1); } - int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte); + int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte, bool is_map1 = false); + int prefix_and_encode_rex2(int dst_enc, int src_enc, int init_bits = 0); // Some prefixq variants always emit exactly one prefix byte, so besides a // prefix-emitting method we provide a method to get the prefix byte to emit, // which can then be folded into a byte stream. - int8_t get_prefixq(Address adr); - int8_t get_prefixq(Address adr, Register reg); + int get_prefixq(Address adr, bool is_map1 = false); + int get_prefixq_rex2(Address adr, bool is_map1 = false); + int get_prefixq(Address adr, Register reg, bool is_map1 = false); + int get_prefixq_rex2(Address adr, Register reg, bool ismap1 = false); void prefixq(Address adr); - void prefixq(Address adr, Register reg); + void prefixq(Address adr, Register reg, bool is_map1 = false); void prefixq(Address adr, XMMRegister reg); + void prefixq_rex2(Address adr, XMMRegister src); - int prefixq_and_encode(int reg_enc); - int prefixq_and_encode(int dst_enc, int src_enc); + bool prefix_is_rex2(int prefix); + + int prefixq_and_encode(int reg_enc, bool is_map1 = false); + int prefixq_and_encode_rex2(int reg_enc, bool is_map1 = false); + int prefixq_and_encode(int dst_enc, int src_enc, bool is_map1 = false); + int prefixq_and_encode_rex2(int dst_enc, int src_enc, bool is_map1 = false); + + bool needs_rex2(Register reg1, Register reg2 = noreg, Register reg3 = noreg); + + bool needs_eevex(Register reg1, Register reg2 = noreg, Register reg3 = noreg); + bool needs_eevex(int enc1, int enc2 = -1, int enc3 = -1); void rex_prefix(Address adr, XMMRegister xreg, VexSimdPrefix pre, VexOpcode opc, bool rex_w); @@ -721,22 +786,21 @@ class Assembler : public AbstractAssembler { void vex_prefix(bool vex_r, bool vex_b, bool vex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc); - void evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, bool evex_v, - int nds_enc, VexSimdPrefix pre, VexOpcode opc); + void evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_v, bool evex_r, bool evex_b, + bool eevex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc); - void vex_prefix(Address adr, int nds_enc, int xreg_enc, - VexSimdPrefix pre, VexOpcode opc, + void vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes); int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, - InstructionAttr *attributes); + InstructionAttr *attributes, bool src_is_gpr = false); void simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes); int simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes); + VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr = false); // Helper functions for groups of instructions void emit_arith_b(int op1, int op2, Register dst, int imm8); @@ -821,6 +885,10 @@ class Assembler : public AbstractAssembler { void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0); void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0); + void emit_prefix_and_int8(int prefix, int b1); + void emit_opcode_prefix_and_encoding(int byte1, int ocp_and_encoding); + void emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding); + void emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding, int byte3); bool always_reachable(AddressLiteral adr) NOT_LP64( { return true; } ); bool reachable(AddressLiteral adr) NOT_LP64( { return true; } ); @@ -907,6 +975,8 @@ class Assembler : public AbstractAssembler { // Instruction prefixes void prefix(Prefix p); + void prefix16(int p); + public: // Creation diff --git a/src/hotspot/cpu/x86/assembler_x86.inline.hpp b/src/hotspot/cpu/x86/assembler_x86.inline.hpp index 66aebb32e21f7..d2aa76fcf5650 100644 --- a/src/hotspot/cpu/x86/assembler_x86.inline.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.inline.hpp @@ -30,23 +30,53 @@ #include "code/codeCache.hpp" #ifndef _LP64 -inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst) { return reg_enc; } -inline int Assembler::prefixq_and_encode(int reg_enc) { return reg_enc; } +inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst, bool is_map1) +{ + int opc_prefix = is_map1 ? 0x0F00 : 0; + return opc_prefix | reg_enc; +} -inline int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { return dst_enc << 3 | src_enc; } -inline int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { return dst_enc << 3 | src_enc; } +inline int Assembler::prefixq_and_encode(int reg_enc, bool is_map1) { + int opc_prefix = is_map1 ? 0xF00 : 0; + return opc_prefix | reg_enc; +} + +inline int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte, bool is_map1) { + int opc_prefix = is_map1 ? 0xF00 : 0; + return opc_prefix | (dst_enc << 3 | src_enc); +} + +inline int Assembler::prefixq_and_encode(int dst_enc, int src_enc, bool is_map1) { + int opc_prefix = is_map1 ? 0xF00 : 0; + return opc_prefix | dst_enc << 3 | src_enc; +} inline void Assembler::prefix(Register reg) {} inline void Assembler::prefix(Register dst, Register src, Prefix p) {} inline void Assembler::prefix(Register dst, Address adr, Prefix p) {} -inline void Assembler::prefix(Address adr) {} + +inline void Assembler::prefix(Address adr, bool is_map1) { + if (is_map1) { + emit_int8(0x0F); + } +} + inline void Assembler::prefixq(Address adr) {} -inline void Assembler::prefix(Address adr, Register reg, bool byteinst) {} -inline void Assembler::prefixq(Address adr, Register reg) {} +inline void Assembler::prefix(Address adr, Register reg, bool byteinst, bool is_map1) { + if (is_map1) { + emit_int8(0x0F); + } +} +inline void Assembler::prefixq(Address adr, Register reg, bool is_map1) { + if (is_map1) { + emit_int8(0x0F); + } +} inline void Assembler::prefix(Address adr, XMMRegister reg) {} inline void Assembler::prefixq(Address adr, XMMRegister reg) {} + #endif // _LP64 #endif // CPU_X86_ASSEMBLER_X86_INLINE_HPP diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index a6801f594bd09..b71b5a2ab47ef 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -352,36 +352,6 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, __ verify_tlab(); } -void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, Register thread, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1) { - if (!thread->is_valid()) { -#ifdef _LP64 - thread = r15_thread; -#else - assert(t1->is_valid(), "need temp reg"); - thread = t1; - __ get_thread(thread); -#endif - } - -#ifdef _LP64 - if (var_size_in_bytes->is_valid()) { - __ addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes); - } else { - __ addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes); - } -#else - if (var_size_in_bytes->is_valid()) { - __ addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes); - } else { - __ addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes); - } - __ adcl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())+4), 0); -#endif -} - #ifdef _LP64 void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slow_path, Label* continuation) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp index a74d5cc767638..81797907aedde 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp @@ -37,12 +37,6 @@ class Node; class InterpreterMacroAssembler; class BarrierSetAssembler: public CHeapObj { -private: - void incr_allocated_bytes(MacroAssembler* masm, Register thread, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1); - public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) {} diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 573edc26dad4c..25a2b931468cd 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -219,7 +219,6 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, assert(pre_val != rax, "check this code"); } - Address in_progress(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset())); Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset())); diff --git a/src/hotspot/cpu/x86/globals_x86.hpp b/src/hotspot/cpu/x86/globals_x86.hpp index 0f01eb3a0c43e..d73a8d0317107 100644 --- a/src/hotspot/cpu/x86/globals_x86.hpp +++ b/src/hotspot/cpu/x86/globals_x86.hpp @@ -232,8 +232,10 @@ define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong); \ product(bool, IntelJccErratumMitigation, true, DIAGNOSTIC, \ "Turn off JVM mitigations related to Intel micro code " \ - "mitigations for the Intel JCC erratum") - + "mitigations for the Intel JCC erratum") \ + \ + product(bool, UseAPX, false, EXPERIMENTAL, \ + "Use Advanced Performance Extensions on x86") \ // end of ARCH_FLAGS #endif // CPU_X86_GLOBALS_X86_HPP diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index e045572a5cdbb..c69c8c0d447b5 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -1549,6 +1549,8 @@ class MacroAssembler: public Assembler { Assembler::evpsrlvd(dst, mask, nds, src, merge, vector_len); } } + + using Assembler::evpsrlq; void evpsrlq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len, bool is_varshift) { if (!is_varshift) { Assembler::evpsrlq(dst, mask, nds, src, merge, vector_len); @@ -1570,6 +1572,7 @@ class MacroAssembler: public Assembler { Assembler::evpsravd(dst, mask, nds, src, merge, vector_len); } } + using Assembler::evpsraq; void evpsraq(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len, bool is_varshift) { if (!is_varshift) { Assembler::evpsraq(dst, mask, nds, src, merge, vector_len); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 63226a560f4df..3f2865e7465e4 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -4255,6 +4255,11 @@ void StubGenerator::generate_compiler_stubs() { StubRoutines::_poly1305_processBlocks = generate_poly1305_processBlocks(); } + if (UseIntPolyIntrinsics) { + StubRoutines::_intpoly_montgomeryMult_P256 = generate_intpoly_montgomeryMult_P256(); + StubRoutines::_intpoly_assign = generate_intpoly_assign(); + } + if (UseMD5Intrinsics) { StubRoutines::_md5_implCompress = generate_md5_implCompress(false, "md5_implCompress"); StubRoutines::_md5_implCompressMB = generate_md5_implCompress(true, "md5_implCompressMB"); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 725932b9e0310..02435bd172c47 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -483,6 +483,9 @@ class StubGenerator: public StubCodeGenerator { const XMMRegister P2L, const XMMRegister P2H, const XMMRegister YTMP1, const Register rscratch); + address generate_intpoly_montgomeryMult_P256(); + address generate_intpoly_assign(); + // BASE64 stubs address base64_shuffle_addr(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp similarity index 100% rename from src/hotspot/cpu/x86/stubGenerator_x86_64_poly.cpp rename to src/hotspot/cpu/x86/stubGenerator_x86_64_poly1305.cpp diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp new file mode 100644 index 0000000000000..25ee68072492c --- /dev/null +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_poly_mont.cpp @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2024, Intel Corporation. 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 "macroAssembler_x86.hpp" +#include "stubGenerator_x86_64.hpp" + +#define __ _masm-> + +ATTRIBUTE_ALIGNED(64) uint64_t MODULUS_P256[] = { + 0x000fffffffffffffULL, 0x00000fffffffffffULL, + 0x0000000000000000ULL, 0x0000001000000000ULL, + 0x0000ffffffff0000ULL, 0x0000000000000000ULL, + 0x0000000000000000ULL, 0x0000000000000000ULL +}; +static address modulus_p256() { + return (address)MODULUS_P256; +} + +ATTRIBUTE_ALIGNED(64) uint64_t P256_MASK52[] = { + 0x000fffffffffffffULL, 0x000fffffffffffffULL, + 0x000fffffffffffffULL, 0x000fffffffffffffULL, + 0xffffffffffffffffULL, 0xffffffffffffffffULL, + 0xffffffffffffffffULL, 0xffffffffffffffffULL, +}; +static address p256_mask52() { + return (address)P256_MASK52; +} + +ATTRIBUTE_ALIGNED(64) uint64_t SHIFT1R[] = { + 0x0000000000000001ULL, 0x0000000000000002ULL, + 0x0000000000000003ULL, 0x0000000000000004ULL, + 0x0000000000000005ULL, 0x0000000000000006ULL, + 0x0000000000000007ULL, 0x0000000000000000ULL, +}; +static address shift_1R() { + return (address)SHIFT1R; +} + +ATTRIBUTE_ALIGNED(64) uint64_t SHIFT1L[] = { + 0x0000000000000007ULL, 0x0000000000000000ULL, + 0x0000000000000001ULL, 0x0000000000000002ULL, + 0x0000000000000003ULL, 0x0000000000000004ULL, + 0x0000000000000005ULL, 0x0000000000000006ULL, +}; +static address shift_1L() { + return (address)SHIFT1L; +} + +/** + * Unrolled Word-by-Word Montgomery Multiplication + * r = a * b * 2^-260 (mod P) + * + * Reference [1]: Shay Gueron and Vlad Krasnov + * "Fast Prime Field Elliptic Curve Cryptography with 256 Bit Primes" + * See Figure 5. "Algorithm 2: Word-by-Word Montgomery Multiplication for a Montgomery + * Friendly modulus p". Note: Step 6. Skipped; Instead use numAdds to reuse existing overflow + * logic. + * + * Pseudocode: + * + * +--+--+--+--+--+--+--+--+ + * M = load(*modulus_p256) | 0| 0| 0|m5|m4|m3|m2|m1| + * +--+--+--+--+--+--+--+--+ + * A = load(*aLimbs) | 0| 0| 0|a5|a4|a3|a2|a1| + * +--+--+--+--+--+--+--+--+ + * Acc1 = 0 | 0| 0| 0| 0| 0| 0| 0| 0| + * +--+--+--+--+--+--+--+--+ + * ---- for i = 0 to 4 + * +--+--+--+--+--+--+--+--+ + * Acc2 = 0 | 0| 0| 0| 0| 0| 0| 0| 0| + * +--+--+--+--+--+--+--+--+ + * B = replicate(bLimbs[i]) |bi|bi|bi|bi|bi|bi|bi|bi| + * +--+--+--+--+--+--+--+--+ + * +--+--+--+--+--+--+--+--+ + * Acc1+=| 0| 0| 0|c5|c4|c3|c2|c1| + * *| 0| 0| 0|a5|a4|a3|a2|a1| + * Acc1 += A * B |bi|bi|bi|bi|bi|bi|bi|bi| + * +--+--+--+--+--+--+--+--+ + * Acc2+=| 0| 0| 0| 0| 0| 0| 0| 0| + * *h| 0| 0| 0|a5|a4|a3|a2|a1| + * Acc2 += A *h B |bi|bi|bi|bi|bi|bi|bi|bi| + * +--+--+--+--+--+--+--+--+ + * N = replicate(Acc1[0]) |n0|n0|n0|n0|n0|n0|n0|n0| + * +--+--+--+--+--+--+--+--+ + * +--+--+--+--+--+--+--+--+ + * Acc1+=| 0| 0| 0|c5|c4|c3|c2|c1| + * *| 0| 0| 0|m5|m4|m3|m2|m1| + * Acc1 += M * N |n0|n0|n0|n0|n0|n0|n0|n0| Note: 52 low bits of Acc1[0] == 0 due to Montgomery! + * +--+--+--+--+--+--+--+--+ + * Acc2+=| 0| 0| 0|d5|d4|d3|d2|d1| + * *h| 0| 0| 0|m5|m4|m3|m2|m1| + * Acc2 += M *h N |n0|n0|n0|n0|n0|n0|n0|n0| + * +--+--+--+--+--+--+--+--+ + * if (i == 4) break; + * // Combine high/low partial sums Acc1 + Acc2 + * +--+--+--+--+--+--+--+--+ + * carry = Acc1[0] >> 52 | 0| 0| 0| 0| 0| 0| 0|c1| + * +--+--+--+--+--+--+--+--+ + * Acc2[0] += carry + * +--+--+--+--+--+--+--+--+ + * Acc1 = Acc1 shift one q element>> | 0| 0| 0| 0|c5|c4|c3|c2| + * +--+--+--+--+--+--+--+--+ + * Acc1 = Acc1 + Acc2 + * ---- done + * // Last Carry round: Combine high/low partial sums Acc1 + Acc1 + Acc2 + * carry = Acc1 >> 52 + * Acc1 = Acc1 shift one q element >> + * Acc1 = mask52(Acc1) + * Acc2 += carry + * Acc1 = Acc1 + Acc2 + * output to rLimbs + */ +void montgomeryMultiply(const Register aLimbs, const Register bLimbs, const Register rLimbs, const Register tmp, MacroAssembler* _masm) { + Register t0 = tmp; + Register rscratch = tmp; + + // Inputs + XMMRegister A = xmm0; + XMMRegister B = xmm1; + XMMRegister T = xmm2; + + // Intermediates + XMMRegister Acc1 = xmm10; + XMMRegister Acc2 = xmm11; + XMMRegister N = xmm12; + XMMRegister carry = xmm13; + + // // Constants + XMMRegister modulus = xmm20; + XMMRegister shift1L = xmm21; + XMMRegister shift1R = xmm22; + XMMRegister mask52 = xmm23; + KRegister limb0 = k1; + KRegister allLimbs = k2; + + __ mov64(t0, 0x1); + __ kmovql(limb0, t0); + __ mov64(t0, 0x1f); + __ kmovql(allLimbs, t0); + __ evmovdquq(shift1L, allLimbs, ExternalAddress(shift_1L()), false, Assembler::AVX_512bit, rscratch); + __ evmovdquq(shift1R, allLimbs, ExternalAddress(shift_1R()), false, Assembler::AVX_512bit, rscratch); + __ evmovdquq(mask52, allLimbs, ExternalAddress(p256_mask52()), false, Assembler::AVX_512bit, rscratch); + + // M = load(*modulus_p256) + __ evmovdquq(modulus, allLimbs, ExternalAddress(modulus_p256()), false, Assembler::AVX_512bit, rscratch); + + // A = load(*aLimbs); masked evmovdquq() can be slow. Instead load full 256bit, and compbine with 64bit + __ evmovdquq(A, Address(aLimbs, 8), Assembler::AVX_256bit); + __ evpermq(A, allLimbs, shift1L, A, false, Assembler::AVX_512bit); + __ movq(T, Address(aLimbs, 0)); + __ evporq(A, A, T, Assembler::AVX_512bit); + + // Acc1 = 0 + __ vpxorq(Acc1, Acc1, Acc1, Assembler::AVX_512bit); + for (int i = 0; i< 5; i++) { + // Acc2 = 0 + __ vpxorq(Acc2, Acc2, Acc2, Assembler::AVX_512bit); + + // B = replicate(bLimbs[i]) + __ vpbroadcastq(B, Address(bLimbs, i*8), Assembler::AVX_512bit); + + // Acc1 += A * B + __ evpmadd52luq(Acc1, A, B, Assembler::AVX_512bit); + + // Acc2 += A *h B + __ evpmadd52huq(Acc2, A, B, Assembler::AVX_512bit); + + // N = replicate(Acc1[0]) + __ vpbroadcastq(N, Acc1, Assembler::AVX_512bit); + + // Acc1 += M * N + __ evpmadd52luq(Acc1, modulus, N, Assembler::AVX_512bit); + + // Acc2 += M *h N + __ evpmadd52huq(Acc2, modulus, N, Assembler::AVX_512bit); + + if (i == 4) break; + + // Combine high/low partial sums Acc1 + Acc2 + + // carry = Acc1[0] >> 52 + __ evpsrlq(carry, limb0, Acc1, 52, true, Assembler::AVX_512bit); + + // Acc2[0] += carry + __ evpaddq(Acc2, limb0, carry, Acc2, true, Assembler::AVX_512bit); + + // Acc1 = Acc1 shift one q element >> + __ evpermq(Acc1, allLimbs, shift1R, Acc1, false, Assembler::AVX_512bit); + + // Acc1 = Acc1 + Acc2 + __ vpaddq(Acc1, Acc1, Acc2, Assembler::AVX_512bit); + } + + // Last Carry round: Combine high/low partial sums Acc1 + Acc1 + Acc2 + // carry = Acc1 >> 52 + __ evpsrlq(carry, allLimbs, Acc1, 52, true, Assembler::AVX_512bit); + + // Acc1 = Acc1 shift one q element >> + __ evpermq(Acc1, allLimbs, shift1R, Acc1, false, Assembler::AVX_512bit); + + // Acc1 = mask52(Acc1) + __ evpandq(Acc1, Acc1, mask52, Assembler::AVX_512bit); // Clear top 12 bits + + // Acc2 += carry + __ evpaddq(Acc2, allLimbs, carry, Acc2, true, Assembler::AVX_512bit); + + // Acc1 = Acc1 + Acc2 + __ vpaddq(Acc1, Acc1, Acc2, Assembler::AVX_512bit); + + // output to rLimbs (1 + 4 limbs) + __ movq(Address(rLimbs, 0), Acc1); + __ evpermq(Acc1, k0, shift1R, Acc1, true, Assembler::AVX_512bit); + __ evmovdquq(Address(rLimbs, 8), k0, Acc1, true, Assembler::AVX_256bit); +} + +address StubGenerator::generate_intpoly_montgomeryMult_P256() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "intpoly_montgomeryMult_P256"); + address start = __ pc(); + __ enter(); + + // Register Map + const Register aLimbs = c_rarg0; // rdi | rcx + const Register bLimbs = c_rarg1; // rsi | rdx + const Register rLimbs = c_rarg2; // rdx | r8 + const Register tmp = r9; + + montgomeryMultiply(aLimbs, bLimbs, rLimbs, tmp, _masm); + __ mov64(rax, 0x1); // Return 1 (Fig. 5, Step 6 [1] skipped in montgomeryMultiply) + + __ leave(); + __ ret(0); + return start; +} + +// A = B if select +// Must be: +// - constant time (i.e. no branches) +// - no-side channel (i.e. all memory must always be accessed, and in same order) +void assign_avx(XMMRegister A, Address aAddr, XMMRegister B, Address bAddr, KRegister select, int vector_len, MacroAssembler* _masm) { + __ evmovdquq(A, aAddr, vector_len); + __ evmovdquq(B, bAddr, vector_len); + __ evmovdquq(A, select, B, true, vector_len); + __ evmovdquq(aAddr, A, vector_len); +} + +void assign_scalar(Address aAddr, Address bAddr, Register select, Register tmp, MacroAssembler* _masm) { + // Original java: + // long dummyLimbs = maskValue & (a[i] ^ b[i]); + // a[i] = dummyLimbs ^ a[i]; + + __ movq(tmp, aAddr); + __ xorq(tmp, bAddr); + __ andq(tmp, select); + __ xorq(aAddr, tmp); +} + +address StubGenerator::generate_intpoly_assign() { + // KNOWN Lengths: + // MontgomeryIntPolynP256: 5 = 4 + 1 + // IntegerPolynomial1305: 5 = 4 + 1 + // IntegerPolynomial25519: 10 = 8 + 2 + // IntegerPolynomialP256: 10 = 8 + 2 + // Curve25519OrderField: 10 = 8 + 2 + // Curve25519OrderField: 10 = 8 + 2 + // P256OrderField: 10 = 8 + 2 + // IntegerPolynomialP384: 14 = 8 + 4 + 2 + // P384OrderField: 14 = 8 + 4 + 2 + // IntegerPolynomial448: 16 = 8 + 8 + // Curve448OrderField: 16 = 8 + 8 + // Curve448OrderField: 16 = 8 + 8 + // IntegerPolynomialP521: 19 = 8 + 8 + 2 + 1 + // P521OrderField: 19 = 8 + 8 + 2 + 1 + // Special Cases 5, 10, 14, 16, 19 + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "intpoly_assign"); + address start = __ pc(); + __ enter(); + + // Inputs + const Register set = c_rarg0; + const Register aLimbs = c_rarg1; + const Register bLimbs = c_rarg2; + const Register length = c_rarg3; + XMMRegister A = xmm0; + XMMRegister B = xmm1; + + Register tmp = r9; + KRegister select = k1; + Label L_Length5, L_Length10, L_Length14, L_Length16, L_Length19, L_DefaultLoop, L_Done; + + __ negq(set); + __ kmovql(select, set); + + // NOTE! Crypto code cannot branch on user input. However; allowed to branch on number of limbs; + // Number of limbs is a constant in each IntegerPolynomial (i.e. this side-channel branch leaks + // number of limbs which is not a secret) + __ cmpl(length, 5); + __ jcc(Assembler::equal, L_Length5); + __ cmpl(length, 10); + __ jcc(Assembler::equal, L_Length10); + __ cmpl(length, 14); + __ jcc(Assembler::equal, L_Length14); + __ cmpl(length, 16); + __ jcc(Assembler::equal, L_Length16); + __ cmpl(length, 19); + __ jcc(Assembler::equal, L_Length19); + + // Default copy loop (UNLIKELY) + __ cmpl(length, 0); + __ jcc(Assembler::lessEqual, L_Done); + __ bind(L_DefaultLoop); + assign_scalar(Address(aLimbs, 0), Address(bLimbs, 0), set, tmp, _masm); + __ subl(length, 1); + __ lea(aLimbs, Address(aLimbs,8)); + __ lea(bLimbs, Address(bLimbs,8)); + __ cmpl(length, 0); + __ jcc(Assembler::greater, L_DefaultLoop); + __ jmp(L_Done); + + __ bind(L_Length5); // 1 + 4 + assign_scalar(Address(aLimbs, 0), Address(bLimbs, 0), set, tmp, _masm); + assign_avx(A, Address(aLimbs, 8), B, Address(bLimbs, 8), select, Assembler::AVX_256bit, _masm); + __ jmp(L_Done); + + __ bind(L_Length10); // 2 + 8 + assign_avx(A, Address(aLimbs, 0), B, Address(bLimbs, 0), select, Assembler::AVX_128bit, _masm); + assign_avx(A, Address(aLimbs, 16), B, Address(bLimbs, 16), select, Assembler::AVX_512bit, _masm); + __ jmp(L_Done); + + __ bind(L_Length14); // 2 + 4 + 8 + assign_avx(A, Address(aLimbs, 0), B, Address(bLimbs, 0), select, Assembler::AVX_128bit, _masm); + assign_avx(A, Address(aLimbs, 16), B, Address(bLimbs, 16), select, Assembler::AVX_256bit, _masm); + assign_avx(A, Address(aLimbs, 48), B, Address(bLimbs, 48), select, Assembler::AVX_512bit, _masm); + __ jmp(L_Done); + + __ bind(L_Length16); // 8 + 8 + assign_avx(A, Address(aLimbs, 0), B, Address(bLimbs, 0), select, Assembler::AVX_512bit, _masm); + assign_avx(A, Address(aLimbs, 64), B, Address(bLimbs, 64), select, Assembler::AVX_512bit, _masm); + __ jmp(L_Done); + + __ bind(L_Length19); // 1 + 2 + 8 + 8 + assign_scalar(Address(aLimbs, 0), Address(bLimbs, 0), set, tmp, _masm); + assign_avx(A, Address(aLimbs, 8), B, Address(bLimbs, 8), select, Assembler::AVX_128bit, _masm); + assign_avx(A, Address(aLimbs, 24), B, Address(bLimbs, 24), select, Assembler::AVX_512bit, _masm); + assign_avx(A, Address(aLimbs, 88), B, Address(bLimbs, 88), select, Assembler::AVX_512bit, _masm); + + __ bind(L_Done); + __ leave(); + __ ret(0); + return start; +} diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 0bffb1aee13f8..f5389d0ef9016 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1002,6 +1002,14 @@ void VM_Version::get_processor_features() { } } + // APX support not enabled yet + if (UseAPX) { + if (!FLAG_IS_DEFAULT(UseAPX)) { + warning("APX is not supported on this CPU."); + } + FLAG_SET_DEFAULT(UseAPX, false); + } + if (FLAG_IS_DEFAULT(IntelJccErratumMitigation)) { _has_intel_jcc_erratum = compute_has_intel_jcc_erratum(); } else { @@ -1366,6 +1374,18 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UsePoly1305Intrinsics, false); } +#ifdef _LP64 + if (supports_avx512ifma() && supports_avx512vlbw()) { + if (FLAG_IS_DEFAULT(UseIntPolyIntrinsics)) { + FLAG_SET_DEFAULT(UseIntPolyIntrinsics, true); + } + } else +#endif + if (UseIntPolyIntrinsics) { + warning("Intrinsics for Polynomial crypto functions not available on this CPU."); + FLAG_SET_DEFAULT(UseIntPolyIntrinsics, false); + } + #ifdef _LP64 if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; diff --git a/src/hotspot/os/bsd/globals_bsd.hpp b/src/hotspot/os/bsd/globals_bsd.hpp index 66fae6a49d239..850d491a11fa4 100644 --- a/src/hotspot/os/bsd/globals_bsd.hpp +++ b/src/hotspot/os/bsd/globals_bsd.hpp @@ -35,7 +35,7 @@ range, \ constraint) \ \ - AARCH64_ONLY(develop(bool, AssertWXAtThreadSync, false, \ + AARCH64_ONLY(develop(bool, AssertWXAtThreadSync, true, \ "Conservatively check W^X thread state at possible safepoint" \ "or handshake")) diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp index 6e518b0213b4a..3a902bb4230c0 100644 --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -235,7 +235,7 @@ bool Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_counterTime: #endif case vmIntrinsics::_getObjectSize: -#if defined(X86) || defined(AARCH64) +#if defined(X86) || defined(AARCH64) || defined(S390) case vmIntrinsics::_clone: #endif break; diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index 4017a5324b53f..bbf802aca1332 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -353,7 +353,7 @@ LIR_OpArrayCopy::LIR_OpArrayCopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_ , _tmp(tmp) , _expected_type(expected_type) , _flags(flags) { -#if defined(X86) || defined(AARCH64) +#if defined(X86) || defined(AARCH64) || defined(S390) if (expected_type != nullptr && flags == 0) { _stub = nullptr; } else { diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index 8d4f57165e151..e60495d1f47fd 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -492,6 +492,10 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_poly1305_processBlocks: if (!UsePoly1305Intrinsics) return true; break; + case vmIntrinsics::_intpoly_montgomeryMult_P256: + case vmIntrinsics::_intpoly_assign: + if (!UseIntPolyIntrinsics) return true; + break; case vmIntrinsics::_updateBytesCRC32C: case vmIntrinsics::_updateDirectByteBufferCRC32C: if (!UseCRC32CIntrinsics) return true; diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index a0db1a65d3a46..b8d8c40cc47a4 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -526,7 +526,18 @@ class methodHandle; do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, countPositives_signature, F_R) \ do_name( implCompressMB_name, "implCompressMultiBlock0") \ \ - /* support for java.util.Base64.Encoder*/ \ + /* support for sun.security.util.math.intpoly.MontgomeryIntegerPolynomialP256 */ \ + do_class(sun_security_util_math_intpoly_MontgomeryIntegerPolynomialP256, "sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256") \ + do_intrinsic(_intpoly_montgomeryMult_P256, sun_security_util_math_intpoly_MontgomeryIntegerPolynomialP256, intPolyMult_name, intPolyMult_signature, F_R) \ + do_name(intPolyMult_name, "mult") \ + do_signature(intPolyMult_signature, "([J[J[J)I") \ + \ + do_class(sun_security_util_math_intpoly_IntegerPolynomial, "sun/security/util/math/intpoly/IntegerPolynomial") \ + do_intrinsic(_intpoly_assign, sun_security_util_math_intpoly_IntegerPolynomial, intPolyAssign_name, intPolyAssign_signature, F_S) \ + do_name(intPolyAssign_name, "conditionalAssign") \ + do_signature(intPolyAssign_signature, "(I[J[J)V") \ + \ + /* support for java.util.Base64.Encoder*/ \ do_class(java_util_Base64_Encoder, "java/util/Base64$Encoder") \ do_intrinsic(_base64_encodeBlock, java_util_Base64_Encoder, encodeBlock_name, encodeBlock_signature, F_R) \ do_name(encodeBlock_name, "encodeBlock") \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index f79af705f0b0a..39340243bc4b8 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -58,7 +58,6 @@ class SerializeClosure; template(java_lang_System, "java/lang/System") \ template(java_lang_Object, "java/lang/Object") \ template(java_lang_Class, "java/lang/Class") \ - template(java_lang_Package, "java/lang/Package") \ template(java_lang_Module, "java/lang/Module") \ template(java_lang_String, "java/lang/String") \ template(java_lang_StringLatin1, "java/lang/StringLatin1") \ @@ -118,7 +117,6 @@ class SerializeClosure; template(java_lang_reflect_RecordComponent, "java/lang/reflect/RecordComponent") \ template(java_lang_StringBuffer, "java/lang/StringBuffer") \ template(java_lang_StringBuilder, "java/lang/StringBuilder") \ - template(java_lang_CharSequence, "java/lang/CharSequence") \ template(java_lang_SecurityManager, "java/lang/SecurityManager") \ template(java_lang_ScopedValue, "java/lang/ScopedValue") \ template(java_lang_ScopedValue_Carrier, "java/lang/ScopedValue$Carrier") \ @@ -131,28 +129,16 @@ class SerializeClosure; template(java_net_URL, "java/net/URL") \ template(java_net_URLClassLoader, "java/net/URLClassLoader") \ template(java_util_jar_Manifest, "java/util/jar/Manifest") \ - template(java_io_OutputStream, "java/io/OutputStream") \ - template(java_io_Reader, "java/io/Reader") \ - template(java_io_BufferedReader, "java/io/BufferedReader") \ - template(java_io_File, "java/io/File") \ - template(java_io_FileInputStream, "java/io/FileInputStream") \ template(java_io_ByteArrayInputStream, "java/io/ByteArrayInputStream") \ template(java_io_Serializable, "java/io/Serializable") \ template(java_nio_Buffer, "java/nio/Buffer") \ template(java_util_Arrays, "java/util/Arrays") \ - template(java_util_Objects, "java/util/Objects") \ template(java_util_Properties, "java/util/Properties") \ - template(java_util_Vector, "java/util/Vector") \ - template(java_util_AbstractList, "java/util/AbstractList") \ - template(java_util_Hashtable, "java/util/Hashtable") \ template(java_util_DualPivotQuicksort, "java/util/DualPivotQuicksort") \ - template(java_lang_Compiler, "java/lang/Compiler") \ template(jdk_internal_misc_Signal, "jdk/internal/misc/Signal") \ template(jdk_internal_util_Preconditions, "jdk/internal/util/Preconditions") \ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ - template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(jdk_internal_vm_PostVMInitHook, "jdk/internal/vm/PostVMInitHook") \ - template(sun_net_www_ParseUtil, "sun/net/www/ParseUtil") \ template(java_util_Iterator, "java/util/Iterator") \ template(java_lang_Record, "java/lang/Record") \ template(sun_instrument_InstrumentationImpl, "sun/instrument/InstrumentationImpl") \ @@ -227,7 +213,6 @@ class SerializeClosure; template(java_lang_BootstrapMethodError, "java/lang/BootstrapMethodError") \ template(java_lang_LinkageError, "java/lang/LinkageError") \ template(java_lang_NegativeArraySizeException, "java/lang/NegativeArraySizeException") \ - template(java_lang_NoSuchFieldException, "java/lang/NoSuchFieldException") \ template(java_lang_NoSuchMethodException, "java/lang/NoSuchMethodException") \ template(java_lang_NullPointerException, "java/lang/NullPointerException") \ template(java_lang_StringIndexOutOfBoundsException, "java/lang/StringIndexOutOfBoundsException")\ @@ -237,7 +222,6 @@ class SerializeClosure; template(java_lang_Exception, "java/lang/Exception") \ template(java_lang_RuntimeException, "java/lang/RuntimeException") \ template(java_io_IOException, "java/io/IOException") \ - template(java_security_PrivilegedActionException, "java/security/PrivilegedActionException") \ \ /* error klasses: at least all errors thrown by the VM have entries here */ \ template(java_lang_AbstractMethodError, "java/lang/AbstractMethodError") \ @@ -283,7 +267,6 @@ class SerializeClosure; template(reflect_CallerSensitive_signature, "Ljdk/internal/reflect/CallerSensitive;") \ template(reflect_DirectConstructorHandleAccessor_NativeAccessor, "jdk/internal/reflect/DirectConstructorHandleAccessor$NativeAccessor") \ template(reflect_SerializationConstructorAccessorImpl, "jdk/internal/reflect/SerializationConstructorAccessorImpl") \ - template(checkedExceptions_name, "checkedExceptions") \ template(clazz_name, "clazz") \ template(exceptionTypes_name, "exceptionTypes") \ template(modifiers_name, "modifiers") \ @@ -363,10 +346,6 @@ class SerializeClosure; template(linkDynamicConstant_signature, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \ template(linkCallSite_name, "linkCallSite") \ template(linkCallSite_signature, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/invoke/MemberName;") \ - template(setTargetNormal_name, "setTargetNormal") \ - template(setTargetVolatile_name, "setTargetVolatile") \ - template(setTarget_signature, "(Ljava/lang/invoke/MethodHandle;)V") \ - template(DEFAULT_CONTEXT_name, "DEFAULT_CONTEXT") \ NOT_LP64( do_alias(intptr_signature, int_signature) ) \ LP64_ONLY( do_alias(intptr_signature, long_signature) ) \ /* Foreign API Support */ \ @@ -411,7 +390,6 @@ class SerializeClosure; template(maxPriority_name, "maxPriority") \ template(shutdown_name, "shutdown") \ template(finalize_method_name, "finalize") \ - template(reference_lock_name, "lock") \ template(reference_discovered_name, "discovered") \ template(run_finalization_name, "runFinalization") \ template(dispatchUncaughtException_name, "dispatchUncaughtException") \ @@ -426,8 +404,6 @@ class SerializeClosure; template(enter_name, "enter") \ template(enterSpecial_name, "enterSpecial") \ template(onContinue_name, "onContinue0") \ - template(getStacks_name, "getStacks") \ - template(onPinned_name, "onPinned0") \ template(scope_name, "scope") \ template(yieldInfo_name, "yieldInfo") \ template(tail_name, "tail") \ @@ -435,26 +411,21 @@ class SerializeClosure; template(bottom_name, "bottom") \ template(mode_name, "mode") \ template(numFrames_name, "numFrames") \ - template(numOops_name, "numOops") \ template(stack_name, "stack") \ template(maxSize_name, "maxSize") \ template(reset_name, "reset") \ template(done_name, "done") \ template(mounted_name, "mounted") \ - template(numInterpretedFrames_name, "numInterpretedFrames") \ template(jfrTraceId_name, "jfrTraceId") \ template(fp_name, "fp") \ template(sp_name, "sp") \ template(pc_name, "pc") \ template(cs_name, "cs") \ - template(refStack_name, "refStack") \ - template(refSP_name, "refSP") \ template(get_name, "get") \ template(refersTo0_name, "refersTo0") \ template(put_name, "put") \ template(type_name, "type") \ template(findNative_name, "findNative") \ - template(deadChild_name, "deadChild") \ template(getFromClass_name, "getFromClass") \ template(dispatch_name, "dispatch") \ template(bootLoader_name, "bootLoader") \ @@ -470,7 +441,6 @@ class SerializeClosure; template(getClassContext_name, "getClassContext") \ template(wait_name, "wait0") \ template(checkPackageAccess_name, "checkPackageAccess") \ - template(newInstance0_name, "newInstance0") \ template(forName_name, "forName") \ template(forName0_name, "forName0") \ template(isJavaIdentifierStart_name, "isJavaIdentifierStart") \ @@ -492,7 +462,6 @@ class SerializeClosure; template(vmholder_name, "vmholder") \ template(method_name, "method") \ template(vmindex_name, "vmindex") \ - template(vmcount_name, "vmcount") \ template(flags_name, "flags") \ template(basicType_name, "basicType") \ template(append_name, "append") \ @@ -560,7 +529,6 @@ class SerializeClosure; template(void_float_signature, "()F") \ template(void_double_signature, "()D") \ template(bool_void_signature, "(Z)V") \ - template(bool_bool_void_signature, "(ZZ)V") \ template(int_void_signature, "(I)V") \ template(int_int_signature, "(I)I") \ template(char_char_signature, "(C)C") \ @@ -589,21 +557,16 @@ class SerializeClosure; template(bool_array_signature, "[Z") \ template(byte_array_signature, "[B") \ template(char_array_signature, "[C") \ - template(int_array_signature, "[I") \ - template(long_array_signature, "[J") \ template(runnable_signature, "Ljava/lang/Runnable;") \ template(continuation_signature, "Ljdk/internal/vm/Continuation;") \ template(continuationscope_signature, "Ljdk/internal/vm/ContinuationScope;") \ template(stackchunk_signature, "Ljdk/internal/vm/StackChunk;") \ - template(vthread_signature, "Ljava/lang/VirtualThread;") \ template(object_void_signature, "(Ljava/lang/Object;)V") \ template(object_int_signature, "(Ljava/lang/Object;)I") \ template(long_object_long_signature, "(JLjava/lang/Object;)J") \ template(object_boolean_signature, "(Ljava/lang/Object;)Z") \ template(object_object_signature, "(Ljava/lang/Object;)Ljava/lang/Object;") \ template(string_void_signature, "(Ljava/lang/String;)V") \ - template(string_int_signature, "(Ljava/lang/String;)I") \ - template(string_byte_array_signature, "(Ljava/lang/String;)[B") \ template(string_bool_byte_array_signature, "(Ljava/lang/String;Z)[B") \ template(throwable_signature, "Ljava/lang/Throwable;") \ template(throwable_void_signature, "(Ljava/lang/Throwable;)V") \ @@ -613,10 +576,6 @@ class SerializeClosure; template(class_long_signature, "(Ljava/lang/Class;)J") \ template(class_boolean_signature, "(Ljava/lang/Class;)Z") \ template(throwable_throwable_signature, "(Ljava/lang/Throwable;)Ljava/lang/Throwable;") \ - template(throwable_string_void_signature, "(Ljava/lang/Throwable;Ljava/lang/String;)V") \ - template(string_array_void_signature, "([Ljava/lang/String;)V") \ - template(string_array_string_array_void_signature, "([Ljava/lang/String;[Ljava/lang/String;)V") \ - template(thread_throwable_void_signature, "(Ljava/lang/Thread;Ljava/lang/Throwable;)V") \ template(thread_void_signature, "(Ljava/lang/Thread;)V") \ template(runnable_void_signature, "(Ljava/lang/Runnable;)V") \ template(threadgroup_runnable_void_signature, "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;)V") \ @@ -625,12 +584,9 @@ class SerializeClosure; template(string_class_signature, "(Ljava/lang/String;)Ljava/lang/Class;") \ template(string_boolean_class_signature, "(Ljava/lang/String;Z)Ljava/lang/Class;") \ template(object_object_object_signature, "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \ - template(string_string_string_signature, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;") \ template(string_string_signature, "(Ljava/lang/String;)Ljava/lang/String;") \ template(classloader_string_long_signature, "(Ljava/lang/ClassLoader;Ljava/lang/String;)J") \ template(byte_array_void_signature, "([B)V") \ - template(char_array_void_signature, "([C)V") \ - template(int_int_void_signature, "(II)V") \ template(long_long_void_signature, "(JJ)V") \ template(void_byte_array_signature, "()[B") \ template(void_classloader_signature, "()Ljava/lang/ClassLoader;") \ @@ -639,16 +595,13 @@ class SerializeClosure; template(void_class_signature, "()Ljava/lang/Class;") \ template(void_class_array_signature, "()[Ljava/lang/Class;") \ template(void_string_signature, "()Ljava/lang/String;") \ - template(void_module_signature, "()Ljava/lang/Module;") \ template(object_array_object_signature, "([Ljava/lang/Object;)Ljava/lang/Object;") \ template(object_object_array_object_signature, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\ - template(exception_void_signature, "(Ljava/lang/Exception;)V") \ template(protectiondomain_signature, "[Ljava/security/ProtectionDomain;") \ template(accesscontrolcontext_signature, "Ljava/security/AccessControlContext;") \ template(class_protectiondomain_signature, "(Ljava/lang/Class;Ljava/security/ProtectionDomain;)V") \ template(thread_signature, "Ljava/lang/Thread;") \ template(thread_fieldholder_signature, "Ljava/lang/Thread$FieldHolder;") \ - template(thread_array_signature, "[Ljava/lang/Thread;") \ template(threadgroup_signature, "Ljava/lang/ThreadGroup;") \ template(threadgroup_array_signature, "[Ljava/lang/ThreadGroup;") \ template(class_array_signature, "[Ljava/lang/Class;") \ @@ -660,7 +613,6 @@ class SerializeClosure; template(string_array_signature, "[Ljava/lang/String;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \ template(referencequeue_signature, "Ljava/lang/ref/ReferenceQueue;") \ - template(weakreference_array_signature, "[Ljava/lang/ref/WeakReference;") \ template(executable_signature, "Ljava/lang/reflect/Executable;") \ template(module_signature, "Ljava/lang/Module;") \ template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \ @@ -690,7 +642,6 @@ class SerializeClosure; \ /* JVM monitoring and management support */ \ template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \ - template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \ template(java_lang_management_MemoryUsage, "java/lang/management/MemoryUsage") \ template(java_lang_management_ThreadInfo, "java/lang/management/ThreadInfo") \ template(jdk_internal_agent_Agent, "jdk/internal/agent/Agent") \ @@ -727,17 +678,12 @@ class SerializeClosure; template(java_lang_management_MemoryPoolMXBean, "java/lang/management/MemoryPoolMXBean") \ template(java_lang_management_MemoryManagerMXBean, "java/lang/management/MemoryManagerMXBean") \ template(java_lang_management_GarbageCollectorMXBean,"java/lang/management/GarbageCollectorMXBean") \ - template(gcInfoBuilder_name, "gcInfoBuilder") \ template(createMemoryPool_name, "createMemoryPool") \ template(createMemoryManager_name, "createMemoryManager") \ template(createGarbageCollector_name, "createGarbageCollector") \ template(createMemoryPool_signature, "(Ljava/lang/String;ZJJ)Ljava/lang/management/MemoryPoolMXBean;") \ template(createMemoryManager_signature, "(Ljava/lang/String;)Ljava/lang/management/MemoryManagerMXBean;") \ template(createGarbageCollector_signature, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/management/GarbageCollectorMXBean;") \ - template(addThreadDumpForMonitors_name, "addThreadDumpForMonitors") \ - template(addThreadDumpForSynchronizers_name, "addThreadDumpForSynchronizers") \ - template(addThreadDumpForMonitors_signature, "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;[I)V") \ - template(addThreadDumpForSynchronizers_signature, "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;)V") \ \ /* JVMTI/java.lang.instrument support and VM Attach mechanism */ \ template(jdk_internal_module_Modules, "jdk/internal/module/Modules") \ @@ -791,7 +737,6 @@ class SerializeClosure; template(java_util_ArrayList, "java/util/ArrayList") \ template(toFileURL_name, "toFileURL") \ template(toFileURL_signature, "(Ljava/lang/String;)Ljava/net/URL;") \ - template(url_void_signature, "(Ljava/net/URL;)V") \ template(url_array_classloader_void_signature, "([Ljava/net/URL;Ljava/lang/ClassLoader;)V") \ \ /* Thread.dump_to_file jcmd */ \ diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp index b875f2f5c6d95..7e6b0e56d9346 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp @@ -62,7 +62,8 @@ inline uint8_t* G1BlockOffsetTable::entry_for_addr(const void* const p) const { } inline HeapWord* G1BlockOffsetTable::addr_for_entry(const uint8_t* const p) const { - size_t delta = pointer_delta(p, _offset_base, sizeof(uint8_t)); + // _offset_base can be "negative", so can't use pointer_delta(). + size_t delta = p - _offset_base; HeapWord* result = (HeapWord*) (delta << CardTable::card_shift()); assert(_reserved.contains(result), "out of bounds accessor from block offset table"); diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 101822dbc4428..3202859907cb8 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -533,7 +533,7 @@ G1AddCardResult G1CardSet::add_to_howl(ContainerPtr parent_container, ContainerPtr container; uint bucket = _config->howl_bucket_index(card_in_region); - ContainerPtr volatile* bucket_entry = howl->get_container_addr(bucket); + ContainerPtr volatile* bucket_entry = howl->container_addr(bucket); while (true) { if (Atomic::load(&howl->_num_entries) >= _config->cards_in_howl_threshold()) { diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp index 16ec6b59a6d0d..261b7e5b20a22 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp @@ -238,23 +238,27 @@ class G1CardSetHowl : public G1CardSetContainer { using ContainerPtr = G1CardSet::ContainerPtr; EntryCountType volatile _num_entries; private: - ContainerPtr _buckets[2]; - // Do not add class member variables beyond this point + // VLA implementation. + ContainerPtr _buckets[1]; + // Do not add class member variables beyond this point. // Iterates over the given ContainerPtr with at index in this Howl card set, // applying a CardOrRangeVisitor on it. template void iterate_cardset(ContainerPtr const container, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config); + ContainerPtr at(EntryCountType index) const; + + ContainerPtr const* buckets() const; + public: G1CardSetHowl(EntryCountType card_in_region, G1CardSetConfiguration* config); - ContainerPtr* get_container_addr(EntryCountType index) { - return &_buckets[index]; - } + ContainerPtr const* container_addr(EntryCountType index) const; - bool contains(uint card_idx, G1CardSetConfiguration* config); + ContainerPtr* container_addr(EntryCountType index); + bool contains(uint card_idx, G1CardSetConfiguration* config); // Iterates over all ContainerPtrs in this Howl card set, applying a CardOrRangeVisitor // on it. template diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp index 35abc09230622..330e9d6360048 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp @@ -257,15 +257,33 @@ inline size_t G1CardSetBitMap::header_size_in_bytes() { return offset_of(G1CardSetBitMap, _bits); } +inline G1CardSetHowl::ContainerPtr const* G1CardSetHowl::container_addr(EntryCountType index) const { + assert(index < _num_entries, "precondition"); + return buckets() + index; +} + +inline G1CardSetHowl::ContainerPtr* G1CardSetHowl::container_addr(EntryCountType index) { + return const_cast(const_cast(this)->container_addr(index)); +} + +inline G1CardSetHowl::ContainerPtr G1CardSetHowl::at(EntryCountType index) const { + return *container_addr(index); +} + +inline G1CardSetHowl::ContainerPtr const* G1CardSetHowl::buckets() const { + const void* ptr = reinterpret_cast(this) + header_size_in_bytes(); + return reinterpret_cast(ptr); +} + inline G1CardSetHowl::G1CardSetHowl(EntryCountType card_in_region, G1CardSetConfiguration* config) : G1CardSetContainer(), _num_entries((config->max_cards_in_array() + 1)) /* Card Transfer will not increment _num_entries */ { EntryCountType num_buckets = config->num_buckets_in_howl(); EntryCountType bucket = config->howl_bucket_index(card_in_region); for (uint i = 0; i < num_buckets; ++i) { - _buckets[i] = G1CardSetInlinePtr(); + *container_addr(i) = G1CardSetInlinePtr(); if (i == bucket) { - G1CardSetInlinePtr value(&_buckets[i], _buckets[i]); + G1CardSetInlinePtr value(container_addr(i), at(i)); value.add(card_in_region, config->inline_ptr_bits_per_card(), config->max_cards_in_inline_ptr()); } } @@ -273,7 +291,7 @@ inline G1CardSetHowl::G1CardSetHowl(EntryCountType card_in_region, G1CardSetConf inline bool G1CardSetHowl::contains(uint card_idx, G1CardSetConfiguration* config) { EntryCountType bucket = config->howl_bucket_index(card_idx); - ContainerPtr* array_entry = get_container_addr(bucket); + ContainerPtr* array_entry = container_addr(bucket); ContainerPtr container = Atomic::load_acquire(array_entry); switch (G1CardSet::container_type(container)) { @@ -299,14 +317,14 @@ inline bool G1CardSetHowl::contains(uint card_idx, G1CardSetConfiguration* confi template inline void G1CardSetHowl::iterate(CardOrRangeVisitor& found, G1CardSetConfiguration* config) { for (uint i = 0; i < config->num_buckets_in_howl(); ++i) { - iterate_cardset(_buckets[i], i, found, config); + iterate_cardset(at(i), i, found, config); } } template inline void G1CardSetHowl::iterate(ContainerPtrVisitor& found, uint num_card_sets) { for (uint i = 0; i < num_card_sets; ++i) { - found(&_buckets[i]); + found(container_addr(i)); } } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 804f255217fdb..e3ab84e95557c 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -1247,6 +1247,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { hr->set_containing_set(nullptr); hr->clear_cardtable(); _g1h->concurrent_mark()->clear_statistics(hr); + G1HeapRegionPrinter::mark_reclaim(hr); _g1h->free_humongous_region(hr, _local_cleanup_list); }; @@ -1263,6 +1264,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { hr->set_containing_set(nullptr); hr->clear_cardtable(); _g1h->concurrent_mark()->clear_statistics(hr); + G1HeapRegionPrinter::mark_reclaim(hr); _g1h->free_region(hr, _local_cleanup_list); } @@ -1317,8 +1319,6 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { ~G1UpdateRegionLivenessAndSelectForRebuildTask() { if (!_cleanup_list.is_empty()) { log_debug(gc)("Reclaimed %u empty regions", _cleanup_list.length()); - // Now print the empty regions list. - G1HeapRegionPrinter::mark_reclaim(&_cleanup_list); // And actually make them available. _g1h->prepend_to_freelist(&_cleanup_list); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp index 20a6e795da0cd..ed6d171fb6fda 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp @@ -39,10 +39,6 @@ class G1HeapRegionPrinter : public AllStatic { action, hr->get_type_str(), p2i(hr->bottom()), p2i(hr->top()), p2i(hr->end())); } - static void mark_reclaim(HeapRegion* hr) { - print("MARK-RECLAIM", hr); - } - public: // In some places we iterate over a list in order to generate output // for the list's elements. By exposing this we can avoid this @@ -61,7 +57,7 @@ class G1HeapRegionPrinter : public AllStatic { static void evac_failure(HeapRegion* hr) { print("EVAC-FAILURE", hr); } - static void mark_reclaim(FreeRegionList* free_list); + static void mark_reclaim(HeapRegion* hr) { print("MARK-RECLAIM", hr); } static void eager_reclaim(HeapRegion* hr) { print("EAGER-RECLAIM", hr); } diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 288abc87be985..ac1a758a709c5 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -412,8 +412,8 @@ class G1FreeHumongousRegionClosure : public HeapRegionIndexClosure { _freed_bytes += r->used(); r->set_containing_set(nullptr); _humongous_regions_reclaimed++; - _g1h->free_humongous_region(r, nullptr); G1HeapRegionPrinter::eager_reclaim(r); + _g1h->free_humongous_region(r, nullptr); }; _g1h->humongous_obj_regions_iterate(r, free_humongous_region); @@ -759,9 +759,9 @@ class FreeCSetClosure : public HeapRegionClosure { assert(!r->is_empty(), "Region %u is an empty region in the collection set.", r->hrm_index()); stats()->account_evacuated_region(r); + G1HeapRegionPrinter::evac_reclaim(r); // Free the region and its remembered set. _g1h->free_region(r, nullptr); - G1HeapRegionPrinter::evac_reclaim(r); } void handle_failed_region(HeapRegion* r) { diff --git a/src/hotspot/share/gc/parallel/objectStartArray.hpp b/src/hotspot/share/gc/parallel/objectStartArray.hpp index dec703cbb1935..aadf2651f2c39 100644 --- a/src/hotspot/share/gc/parallel/objectStartArray.hpp +++ b/src/hotspot/share/gc/parallel/objectStartArray.hpp @@ -57,7 +57,8 @@ class ObjectStartArray : public CHeapObj { // Mapping from object start array entry to address of first word HeapWord* addr_for_entry(const uint8_t* const p) const { - size_t delta = pointer_delta(p, _offset_base, sizeof(uint8_t)); + // _offset_base can be "negative", so can't use pointer_delta(). + size_t delta = p - _offset_base; HeapWord* result = (HeapWord*) (delta << CardTable::card_shift()); assert(_covered_region.contains(result), "out of bounds accessor from card marking array"); diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp index deffcc019c95c..6452f03b5cba5 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp @@ -37,9 +37,6 @@ bool ParMarkBitMap::initialize(MemRegion covered_region) { const idx_t bits = bits_required(covered_region); - // The bits will be divided evenly between two bitmaps; each of them should be - // an integral number of words. - assert(is_aligned(bits, (BitsPerWord * 2)), "region size unaligned"); const size_t words = bits / BitsPerWord; const size_t raw_bytes = words * sizeof(idx_t); @@ -61,8 +58,7 @@ ParMarkBitMap::initialize(MemRegion covered_region) _region_start = covered_region.start(); _region_size = covered_region.word_size(); BitMap::bm_word_t* map = (BitMap::bm_word_t*)_virtual_space->reserved_low_addr(); - _beg_bits = BitMapView(map, bits / 2); - _end_bits = BitMapView(map + words / 2, bits / 2); + _beg_bits = BitMapView(map, bits); return true; } @@ -77,176 +73,6 @@ ParMarkBitMap::initialize(MemRegion covered_region) return false; } -bool -ParMarkBitMap::mark_obj(HeapWord* addr, size_t size) -{ - const idx_t beg_bit = addr_to_bit(addr); - if (_beg_bits.par_set_bit(beg_bit)) { - const idx_t end_bit = addr_to_bit(addr + size - 1); - bool end_bit_ok = _end_bits.par_set_bit(end_bit); - assert(end_bit_ok, "concurrency problem"); - return true; - } - return false; -} - -inline bool -ParMarkBitMap::is_live_words_in_range_in_cache(ParCompactionManager* cm, HeapWord* beg_addr) const { - return cm->last_query_begin() == beg_addr; -} - -inline void -ParMarkBitMap::update_live_words_in_range_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj, size_t result) const { - cm->set_last_query_begin(beg_addr); - cm->set_last_query_object(end_obj); - cm->set_last_query_return(result); -} - -size_t -ParMarkBitMap::live_words_in_range_helper(HeapWord* beg_addr, oop end_obj) const -{ - assert(beg_addr <= cast_from_oop(end_obj), "bad range"); - assert(is_marked(end_obj), "end_obj must be live"); - - idx_t live_bits = 0; - - // The bitmap routines require the right boundary to be word-aligned. - const idx_t end_bit = addr_to_bit(cast_from_oop(end_obj)); - const idx_t range_end = align_range_end(end_bit); - - idx_t beg_bit = find_obj_beg(addr_to_bit(beg_addr), range_end); - while (beg_bit < end_bit) { - idx_t tmp_end = find_obj_end(beg_bit, range_end); - assert(tmp_end < end_bit, "missing end bit"); - live_bits += tmp_end - beg_bit + 1; - beg_bit = find_obj_beg(tmp_end + 1, range_end); - } - return bits_to_words(live_bits); -} - -size_t -ParMarkBitMap::live_words_in_range_use_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_oop) const -{ - HeapWord* last_beg = cm->last_query_begin(); - HeapWord* last_obj = cast_from_oop(cm->last_query_object()); - HeapWord* end_obj = cast_from_oop(end_oop); - - size_t last_ret = cm->last_query_return(); - if (end_obj > last_obj) { - last_ret = last_ret + live_words_in_range_helper(last_obj, end_oop); - last_obj = end_obj; - } else if (end_obj < last_obj) { - // The cached value is for an object that is to the left (lower address) of the current - // end_obj. Calculate back from that cached value. - if (pointer_delta(end_obj, beg_addr) > pointer_delta(last_obj, end_obj)) { - last_ret = last_ret - live_words_in_range_helper(end_obj, cast_to_oop(last_obj)); - } else { - last_ret = live_words_in_range_helper(beg_addr, end_oop); - } - last_obj = end_obj; - } - - update_live_words_in_range_cache(cm, last_beg, cast_to_oop(last_obj), last_ret); - return last_ret; -} - -size_t -ParMarkBitMap::live_words_in_range(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const -{ - // Try to reuse result from ParCompactionManager cache first. - if (is_live_words_in_range_in_cache(cm, beg_addr)) { - return live_words_in_range_use_cache(cm, beg_addr, end_obj); - } - size_t ret = live_words_in_range_helper(beg_addr, end_obj); - update_live_words_in_range_cache(cm, beg_addr, end_obj, ret); - return ret; -} - -ParMarkBitMap::IterationStatus -ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, - idx_t range_beg, idx_t range_end) const -{ - DEBUG_ONLY(verify_bit(range_beg);) - DEBUG_ONLY(verify_bit(range_end);) - assert(range_beg <= range_end, "live range invalid"); - - // The bitmap routines require the right boundary to be word-aligned. - const idx_t search_end = align_range_end(range_end); - - idx_t cur_beg = range_beg; - while (true) { - cur_beg = find_obj_beg(cur_beg, search_end); - if (cur_beg >= range_end) { - break; - } - - const size_t size = obj_size(cur_beg); - IterationStatus status = live_closure->do_addr(bit_to_addr(cur_beg), size); - if (status != incomplete) { - assert(status == would_overflow || status == full, "sanity"); - return status; - } - - cur_beg += words_to_bits(size); - if (cur_beg >= range_end) { - break; - } - } - - return complete; -} - -ParMarkBitMap::IterationStatus -ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, - ParMarkBitMapClosure* dead_closure, - idx_t range_beg, idx_t range_end, - idx_t dead_range_end) const -{ - DEBUG_ONLY(verify_bit(range_beg);) - DEBUG_ONLY(verify_bit(range_end);) - DEBUG_ONLY(verify_bit(dead_range_end);) - assert(range_beg <= range_end, "live range invalid"); - assert(range_end <= dead_range_end, "dead range invalid"); - - // The bitmap routines require the right boundary to be word-aligned. - const idx_t dead_search_end = align_range_end(dead_range_end); - - idx_t cur_beg = range_beg; - if (range_beg < range_end && is_unmarked(range_beg)) { - // The range starts with dead space. Look for the next object, then fill. - // This must be the beginning of old/eden/from/to-space, so it's must be - // large enough for a filler. - cur_beg = find_obj_beg(range_beg + 1, dead_search_end); - const idx_t dead_space_end = cur_beg - 1; - const size_t size = obj_size(range_beg, dead_space_end); - dead_closure->do_addr(bit_to_addr(range_beg), size); - } - - while (cur_beg < range_end) { - const size_t size = obj_size(cur_beg); - IterationStatus status = live_closure->do_addr(bit_to_addr(cur_beg), size); - if (status != incomplete) { - assert(status == would_overflow || status == full, "sanity"); - return status; - } - - const idx_t dead_space_beg = cur_beg + words_to_bits(size); - if (dead_space_beg >= dead_search_end) { - break; - } - // Look for the start of the next object. - cur_beg = find_obj_beg(dead_space_beg, dead_search_end); - if (cur_beg > dead_space_beg) { - // Found dead space; compute the size and invoke the dead closure. - const idx_t dead_space_end = cur_beg - 1; - dead_closure->do_addr(bit_to_addr(dead_space_beg), - obj_size(dead_space_beg, dead_space_end)); - } - } - - return complete; -} - #ifdef ASSERT void ParMarkBitMap::verify_clear() const { diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp index ad0e51fdcdf9b..63c4d4e718578 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp @@ -29,9 +29,7 @@ #include "oops/oop.hpp" #include "utilities/bitMap.hpp" -class ParMarkBitMapClosure; class PSVirtualSpace; -class ParCompactionManager; class ParMarkBitMap: public CHeapObj { @@ -39,18 +37,14 @@ class ParMarkBitMap: public CHeapObj typedef BitMap::idx_t idx_t; // Values returned by the iterate() methods. - enum IterationStatus { incomplete, complete, full, would_overflow }; + enum IterationStatus { incomplete, complete, full }; inline ParMarkBitMap(); bool initialize(MemRegion covered_region); // Atomically mark an object as live. - bool mark_obj(HeapWord* addr, size_t size); - inline bool mark_obj(oop obj, size_t size); - - // Return whether the specified begin or end bit is set. - inline bool is_obj_beg(idx_t bit) const; - inline bool is_obj_end(idx_t bit) const; + inline bool mark_obj(HeapWord* addr); + inline bool mark_obj(oop obj); // Traditional interface for testing whether an object is marked or not (these // test only the begin bits). @@ -58,134 +52,69 @@ class ParMarkBitMap: public CHeapObj inline bool is_marked(HeapWord* addr) const; inline bool is_marked(oop obj) const; - inline bool is_unmarked(idx_t bit) const; inline bool is_unmarked(HeapWord* addr) const; inline bool is_unmarked(oop obj) const; - // Convert sizes from bits to HeapWords and back. An object that is n bits - // long will be bits_to_words(n) words long. An object that is m words long - // will take up words_to_bits(m) bits in the bitmap. - inline static size_t bits_to_words(idx_t bits); - inline static idx_t words_to_bits(size_t words); - - // Return the size in words of an object given a begin bit and an end bit, or - // the equivalent beg_addr and end_addr. - inline size_t obj_size(idx_t beg_bit, idx_t end_bit) const; - inline size_t obj_size(HeapWord* beg_addr, HeapWord* end_addr) const; - - // Return the size in words of the object (a search is done for the end bit). - inline size_t obj_size(idx_t beg_bit) const; - inline size_t obj_size(HeapWord* addr) const; - - // Apply live_closure to each live object that lies completely within the - // range [live_range_beg, live_range_end). This is used to iterate over the - // compacted region of the heap. Return values: - // - // complete The iteration is complete. All objects in the range - // were processed and the closure is not full; - // closure->source() is set one past the end of the range. - // - // full The closure is full; closure->source() is set to one - // past the end of the last object processed. - // - // would_overflow The next object in the range would overflow the closure; - // closure->source() is set to the start of that object. - IterationStatus iterate(ParMarkBitMapClosure* live_closure, - idx_t range_beg, idx_t range_end) const; - inline IterationStatus iterate(ParMarkBitMapClosure* live_closure, - HeapWord* range_beg, - HeapWord* range_end) const; - - // Apply live closure as above and additionally apply dead_closure to all dead - // space in the range [range_beg, dead_range_end). Note that dead_range_end - // must be >= range_end. This is used to iterate over the dense prefix. - // - // This method assumes that if the first bit in the range (range_beg) is not - // marked, then dead space begins at that point and the dead_closure is - // applied. Thus callers must ensure that range_beg is not in the middle of a - // live object. - IterationStatus iterate(ParMarkBitMapClosure* live_closure, - ParMarkBitMapClosure* dead_closure, - idx_t range_beg, idx_t range_end, - idx_t dead_range_end) const; - inline IterationStatus iterate(ParMarkBitMapClosure* live_closure, - ParMarkBitMapClosure* dead_closure, - HeapWord* range_beg, - HeapWord* range_end, - HeapWord* dead_range_end) const; - - // Return the number of live words in the range [beg_addr, end_obj) due to - // objects that start in the range. If a live object extends onto the range, - // the caller must detect and account for any live words due to that object. - // If a live object extends beyond the end of the range, only the words within - // the range are included in the result. The end of the range must be a live object, - // which is the case when updating pointers. This allows a branch to be removed - // from inside the loop. - size_t live_words_in_range(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const; - - inline HeapWord* region_start() const; - inline HeapWord* region_end() const; - inline size_t region_size() const; - inline size_t size() const; - size_t reserved_byte_size() const { return _reserved_byte_size; } // Convert a heap address to/from a bit index. inline idx_t addr_to_bit(HeapWord* addr) const; inline HeapWord* bit_to_addr(idx_t bit) const; - // Return word-aligned up range_end, which must not be greater than size(). - inline idx_t align_range_end(idx_t range_end) const; - - // Return the bit index of the first marked object that begins (or ends, - // respectively) in the range [beg, end). If no object is found, return end. - // end must be word-aligned. - inline idx_t find_obj_beg(idx_t beg, idx_t end) const; - inline idx_t find_obj_end(idx_t beg, idx_t end) const; - inline HeapWord* find_obj_beg(HeapWord* beg, HeapWord* end) const; - inline HeapWord* find_obj_end(HeapWord* beg, HeapWord* end) const; + // Return the address of the last obj-start in the range [beg, end). If no + // object is found, return end. + inline HeapWord* find_obj_beg_reverse(HeapWord* beg, HeapWord* end) const; // Clear a range of bits or the entire bitmap (both begin and end bits are // cleared). inline void clear_range(idx_t beg, idx_t end); - // Return the number of bits required to represent the specified number of - // HeapWords, or the specified region. - static inline idx_t bits_required(size_t words); - static inline idx_t bits_required(MemRegion covered_region); - void print_on_error(outputStream* st) const { st->print_cr("Marking Bits: (ParMarkBitMap*) " PTR_FORMAT, p2i(this)); _beg_bits.print_on_error(st, " Begin Bits: "); - _end_bits.print_on_error(st, " End Bits: "); } #ifdef ASSERT void verify_clear() const; - inline void verify_bit(idx_t bit) const; - inline void verify_addr(HeapWord* addr) const; #endif // #ifdef ASSERT private: - size_t live_words_in_range_helper(HeapWord* beg_addr, oop end_obj) const; - - bool is_live_words_in_range_in_cache(ParCompactionManager* cm, HeapWord* beg_addr) const; - size_t live_words_in_range_use_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const; - void update_live_words_in_range_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj, size_t result) const; // Each bit in the bitmap represents one unit of 'object granularity.' Objects // are double-word aligned in 32-bit VMs, but not in 64-bit VMs, so the 32-bit // granularity is 2, 64-bit is 1. - static inline size_t obj_granularity() { return size_t(MinObjAlignment); } static inline int obj_granularity_shift() { return LogMinObjAlignment; } HeapWord* _region_start; size_t _region_size; BitMapView _beg_bits; - BitMapView _end_bits; PSVirtualSpace* _virtual_space; size_t _reserved_byte_size; + + // Return the number of bits required to represent the specified number of + // HeapWords, or the specified region. + static inline idx_t bits_required(size_t words); + static inline idx_t bits_required(MemRegion covered_region); + + // Convert sizes from bits to HeapWords and back. An object that is n bits + // long will be bits_to_words(n) words long. An object that is m words long + // will take up words_to_bits(m) bits in the bitmap. + inline static size_t bits_to_words(idx_t bits); + inline static idx_t words_to_bits(size_t words); + + // Return word-aligned up range_end, which must not be greater than size(). + inline idx_t align_range_end(idx_t range_end) const; + + inline HeapWord* region_start() const; + inline HeapWord* region_end() const; + inline size_t region_size() const; + inline size_t size() const; + +#ifdef ASSERT + inline void verify_bit(idx_t bit) const; + inline void verify_addr(HeapWord* addr) const; +#endif // #ifdef ASSERT }; #endif // SHARE_GC_PARALLEL_PARMARKBITMAP_HPP diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp index f1dabaf3580cd..6d4aba8e36fc4 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp @@ -31,18 +31,15 @@ #include "utilities/bitMap.inline.hpp" inline ParMarkBitMap::ParMarkBitMap(): - _region_start(nullptr), _region_size(0), _beg_bits(), _end_bits(), _virtual_space(nullptr), _reserved_byte_size(0) + _region_start(nullptr), _region_size(0), _beg_bits(), _virtual_space(nullptr), _reserved_byte_size(0) { } inline void ParMarkBitMap::clear_range(idx_t beg, idx_t end) { _beg_bits.clear_range(beg, end); - _end_bits.clear_range(beg, end); } inline ParMarkBitMap::idx_t ParMarkBitMap::bits_required(size_t words) { - // Need two bits (one begin bit, one end bit) for each unit of 'object - // granularity' in the heap. - return words_to_bits(words * 2); + return words_to_bits(words); } inline ParMarkBitMap::idx_t ParMarkBitMap::bits_required(MemRegion covered_region) { @@ -65,16 +62,8 @@ inline size_t ParMarkBitMap::size() const { return _beg_bits.size(); } -inline bool ParMarkBitMap::is_obj_beg(idx_t bit) const { - return _beg_bits.at(bit); -} - -inline bool ParMarkBitMap::is_obj_end(idx_t bit) const { - return _end_bits.at(bit); -} - inline bool ParMarkBitMap::is_marked(idx_t bit) const { - return is_obj_beg(bit); + return _beg_bits.at(bit); } inline bool ParMarkBitMap::is_marked(HeapWord* addr) const { @@ -85,10 +74,6 @@ inline bool ParMarkBitMap::is_marked(oop obj) const { return is_marked(cast_from_oop(obj)); } -inline bool ParMarkBitMap::is_unmarked(idx_t bit) const { - return !is_marked(bit); -} - inline bool ParMarkBitMap::is_unmarked(HeapWord* addr) const { return !is_marked(addr); } @@ -105,47 +90,12 @@ inline ParMarkBitMap::idx_t ParMarkBitMap::words_to_bits(size_t words) { return words >> obj_granularity_shift(); } -inline size_t ParMarkBitMap::obj_size(idx_t beg_bit, idx_t end_bit) const { - DEBUG_ONLY(verify_bit(beg_bit);) - DEBUG_ONLY(verify_bit(end_bit);) - return bits_to_words(end_bit - beg_bit + 1); -} - -inline size_t ParMarkBitMap::obj_size(HeapWord* beg_addr, HeapWord* end_addr) const { - DEBUG_ONLY(verify_addr(beg_addr);) - DEBUG_ONLY(verify_addr(end_addr);) - return pointer_delta(end_addr, beg_addr) + obj_granularity(); -} - -inline size_t ParMarkBitMap::obj_size(idx_t beg_bit) const { - const idx_t end_bit = _end_bits.find_first_set_bit(beg_bit, size()); - assert(is_marked(beg_bit), "obj not marked"); - assert(end_bit < size(), "end bit missing"); - return obj_size(beg_bit, end_bit); +inline bool ParMarkBitMap::mark_obj(HeapWord* addr) { + return _beg_bits.par_set_bit(addr_to_bit(addr)); } -inline size_t ParMarkBitMap::obj_size(HeapWord* addr) const { - return obj_size(addr_to_bit(addr)); -} - -inline ParMarkBitMap::IterationStatus ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, - HeapWord* range_beg, - HeapWord* range_end) const { - return iterate(live_closure, addr_to_bit(range_beg), addr_to_bit(range_end)); -} - -inline ParMarkBitMap::IterationStatus ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, - ParMarkBitMapClosure* dead_closure, - HeapWord* range_beg, - HeapWord* range_end, - HeapWord* dead_range_end) const { - return iterate(live_closure, dead_closure, - addr_to_bit(range_beg), addr_to_bit(range_end), - addr_to_bit(dead_range_end)); -} - -inline bool ParMarkBitMap::mark_obj(oop obj, size_t size) { - return mark_obj(cast_from_oop(obj), size); +inline bool ParMarkBitMap::mark_obj(oop obj) { + return mark_obj(cast_from_oop(obj)); } inline ParMarkBitMap::idx_t ParMarkBitMap::addr_to_bit(HeapWord* addr) const { @@ -164,27 +114,19 @@ inline ParMarkBitMap::idx_t ParMarkBitMap::align_range_end(idx_t range_end) cons return align_up(range_end, BitsPerWord); } -inline ParMarkBitMap::idx_t ParMarkBitMap::find_obj_beg(idx_t beg, idx_t end) const { - return _beg_bits.find_first_set_bit_aligned_right(beg, end); -} - -inline ParMarkBitMap::idx_t ParMarkBitMap::find_obj_end(idx_t beg, idx_t end) const { - return _end_bits.find_first_set_bit_aligned_right(beg, end); -} - inline HeapWord* ParMarkBitMap::find_obj_beg(HeapWord* beg, HeapWord* end) const { const idx_t beg_bit = addr_to_bit(beg); const idx_t end_bit = addr_to_bit(end); const idx_t search_end = align_range_end(end_bit); - const idx_t res_bit = MIN2(find_obj_beg(beg_bit, search_end), end_bit); + const idx_t res_bit = MIN2(_beg_bits.find_first_set_bit_aligned_right(beg_bit, search_end), + end_bit); return bit_to_addr(res_bit); } -inline HeapWord* ParMarkBitMap::find_obj_end(HeapWord* beg, HeapWord* end) const { +inline HeapWord* ParMarkBitMap::find_obj_beg_reverse(HeapWord* beg, HeapWord* end) const { const idx_t beg_bit = addr_to_bit(beg); const idx_t end_bit = addr_to_bit(end); - const idx_t search_end = align_range_end(end_bit); - const idx_t res_bit = MIN2(find_obj_end(beg_bit, search_end), end_bit); + const idx_t res_bit = _beg_bits.find_last_set_bit_aligned_left(beg_bit, end_bit); return bit_to_addr(res_bit); } diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index fe9bcbff703b9..b95c7c619af7d 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -29,6 +29,7 @@ #include "gc/parallel/psCompactionManager.inline.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psParallelCompact.inline.hpp" +#include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "logging/log.hpp" #include "memory/iterator.inline.hpp" @@ -51,16 +52,16 @@ ParMarkBitMap* ParCompactionManager::_mark_bitmap = nullptr; GrowableArray* ParCompactionManager::_shadow_region_array = nullptr; Monitor* ParCompactionManager::_shadow_region_monitor = nullptr; -ParCompactionManager::ParCompactionManager() { +PreservedMarksSet* ParCompactionManager::_preserved_marks_set = nullptr; + +ParCompactionManager::ParCompactionManager(PreservedMarks* preserved_marks) { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _old_gen = heap->old_gen(); _start_array = old_gen()->start_array(); - reset_bitmap_query_cache(); - - _deferred_obj_array = new (mtGC) GrowableArray(10, mtGC); + _preserved_marks = preserved_marks; _marking_stats_cache = nullptr; } @@ -79,9 +80,12 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { _objarray_task_queues = new ObjArrayTaskQueueSet(parallel_gc_threads); _region_task_queues = new RegionTaskQueueSet(parallel_gc_threads); + _preserved_marks_set = new PreservedMarksSet(true); + _preserved_marks_set->init(parallel_gc_threads); + // Create and register the ParCompactionManager(s) for the worker threads. for(uint i=0; iget(i)); oop_task_queues()->register_queue(i, _manager_array[i]->oop_stack()); _objarray_task_queues->register_queue(i, &_manager_array[i]->_objarray_stack); region_task_queues()->register_queue(i, _manager_array[i]->region_stack()); @@ -93,13 +97,7 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { _shadow_region_array = new (mtGC) GrowableArray(10, mtGC); _shadow_region_monitor = new Monitor(Mutex::nosafepoint, "CompactionManager_lock"); -} -void ParCompactionManager::reset_all_bitmap_query_caches() { - uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().max_workers(); - for (uint i=0; ireset_bitmap_query_cache(); - } } void ParCompactionManager::flush_all_string_dedup_requests() { @@ -168,15 +166,6 @@ void ParCompactionManager::drain_region_stacks() { } while (!region_stack()->is_empty()); } -void ParCompactionManager::drain_deferred_objects() { - while (!_deferred_obj_array->is_empty()) { - HeapWord* addr = _deferred_obj_array->pop(); - assert(addr != nullptr, "expected a deferred object"); - PSParallelCompact::update_deferred_object(this, addr); - } - _deferred_obj_array->clear_and_deallocate(); -} - size_t ParCompactionManager::pop_shadow_region_mt_safe(PSParallelCompact::RegionData* region_ptr) { MonitorLocker ml(_shadow_region_monitor, Mutex::_no_safepoint_check_flag); while (true) { @@ -207,10 +196,6 @@ void ParCompactionManager::remove_all_shadow_regions() { _shadow_region_array->clear(); } -void ParCompactionManager::push_deferred_object(HeapWord* addr) { - _deferred_obj_array->push(addr); -} - #ifdef ASSERT void ParCompactionManager::verify_all_marking_stack_empty() { uint parallel_gc_threads = ParallelGCThreads; diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.hpp index b33ad06ee3ee1..0dd68d2e2f7c7 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_PARALLEL_PSCOMPACTIONMANAGER_HPP #include "gc/parallel/psParallelCompact.hpp" +#include "gc/shared/preservedMarks.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" #include "gc/shared/taskTerminator.hpp" @@ -45,7 +46,7 @@ class ParCompactionManager : public CHeapObj { friend class ParallelScavengeRefProcProxyTask; friend class ParMarkBitMap; friend class PSParallelCompact; - friend class UpdateDensePrefixAndCompactionTask; + friend class FillDensePrefixAndCompactionTask; private: typedef OverflowTaskQueue OopTaskQueue; @@ -75,7 +76,8 @@ class ParCompactionManager : public CHeapObj { // type of TaskQueue. RegionTaskQueue _region_stack; - GrowableArray* _deferred_obj_array; + static PreservedMarksSet* _preserved_marks_set; + PreservedMarks* _preserved_marks; static ParMarkBitMap* _mark_bitmap; @@ -87,10 +89,6 @@ class ParCompactionManager : public CHeapObj { // See pop/push_shadow_region_mt_safe() below static Monitor* _shadow_region_monitor; - HeapWord* _last_query_beg; - oop _last_query_obj; - size_t _last_query_ret; - StringDedup::Requests _string_dedup_requests; static PSOldGen* old_gen() { return _old_gen; } @@ -106,7 +104,7 @@ class ParCompactionManager : public CHeapObj { // objArray stack, otherwise returns false and the task is invalid. bool publish_or_pop_objarray_tasks(ObjArrayTask& task); - ParCompactionManager(); + ParCompactionManager(PreservedMarks* preserved_marks); // Array of task queues. Needed by the task terminator. static RegionTaskQueueSet* region_task_queues() { return _region_task_queues; } OopTaskQueue* oop_stack() { return &_oop_stack; } @@ -153,29 +151,10 @@ class ParCompactionManager : public CHeapObj { return next_shadow_region(); } - void push_deferred_object(HeapWord* addr); - - void reset_bitmap_query_cache() { - _last_query_beg = nullptr; - _last_query_obj = nullptr; - _last_query_ret = 0; - } - void flush_string_dedup_requests() { _string_dedup_requests.flush(); } - // Bitmap query support, cache last query and result - HeapWord* last_query_begin() { return _last_query_beg; } - oop last_query_object() { return _last_query_obj; } - size_t last_query_return() { return _last_query_ret; } - - void set_last_query_begin(HeapWord *new_beg) { _last_query_beg = new_beg; } - void set_last_query_object(oop new_obj) { _last_query_obj = new_obj; } - void set_last_query_return(size_t new_ret) { _last_query_ret = new_ret; } - - static void reset_all_bitmap_query_caches(); - static void flush_all_string_dedup_requests(); RegionTaskQueue* region_stack() { return &_region_stack; } @@ -184,6 +163,9 @@ class ParCompactionManager : public CHeapObj { // Simply use the first compaction manager here. static ParCompactionManager* get_vmthread_cm() { return _manager_array[0]; } + PreservedMarks* preserved_marks() const { + return _preserved_marks; + } ParMarkBitMap* mark_bitmap() { return _mark_bitmap; } @@ -208,13 +190,10 @@ class ParCompactionManager : public CHeapObj { // Process tasks remaining on any stack void drain_region_stacks(); - void drain_deferred_objects(); void follow_contents(oop obj); void follow_array(objArrayOop array, int index); - void update_contents(oop obj); - class FollowStackClosure: public VoidClosure { private: ParCompactionManager* _compaction_manager; diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp index ae2e449e0b6ab..64b0da58fda69 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp @@ -157,13 +157,6 @@ inline void ParCompactionManager::follow_array(objArrayOop obj, int index) { } } -inline void ParCompactionManager::update_contents(oop obj) { - if (!obj->klass()->is_typeArray_klass()) { - PCAdjustPointerClosure apc(this); - obj->oop_iterate(&apc); - } -} - inline void ParCompactionManager::follow_contents(oop obj) { assert(PSParallelCompact::mark_bitmap()->is_marked(obj), "should be marked"); PCIterateMarkAndPushClosure cl(this, PSParallelCompact::ref_processor()); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 994bdc847cf79..e72fa42e6f613 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -30,6 +30,7 @@ #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "compiler/oopMap.hpp" +#include "gc/parallel/objectStartArray.inline.hpp" #include "gc/parallel/parallelArguments.hpp" #include "gc/parallel/parallelScavengeHeap.inline.hpp" #include "gc/parallel/parMarkBitMap.inline.hpp" @@ -54,6 +55,7 @@ #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageSet.inline.hpp" #include "gc/shared/oopStorageSetParState.inline.hpp" +#include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" @@ -98,24 +100,13 @@ // All sizes are in HeapWords. const size_t ParallelCompactData::Log2RegionSize = 16; // 64K words const size_t ParallelCompactData::RegionSize = (size_t)1 << Log2RegionSize; +static_assert(ParallelCompactData::RegionSize >= BitsPerWord, "region-start bit word-aligned"); const size_t ParallelCompactData::RegionSizeBytes = RegionSize << LogHeapWordSize; const size_t ParallelCompactData::RegionSizeOffsetMask = RegionSize - 1; const size_t ParallelCompactData::RegionAddrOffsetMask = RegionSizeBytes - 1; const size_t ParallelCompactData::RegionAddrMask = ~RegionAddrOffsetMask; -const size_t ParallelCompactData::Log2BlockSize = 7; // 128 words -const size_t ParallelCompactData::BlockSize = (size_t)1 << Log2BlockSize; -const size_t ParallelCompactData::BlockSizeBytes = - BlockSize << LogHeapWordSize; -const size_t ParallelCompactData::BlockSizeOffsetMask = BlockSize - 1; -const size_t ParallelCompactData::BlockAddrOffsetMask = BlockSizeBytes - 1; -const size_t ParallelCompactData::BlockAddrMask = ~BlockAddrOffsetMask; - -const size_t ParallelCompactData::BlocksPerRegion = RegionSize / BlockSize; -const size_t ParallelCompactData::Log2BlocksPerRegion = - Log2RegionSize - Log2BlockSize; - const ParallelCompactData::RegionData::region_sz_t ParallelCompactData::RegionData::dc_shift = 27; @@ -412,10 +403,7 @@ ParallelCompactData::ParallelCompactData() : _region_vspace(nullptr), _reserved_byte_size(0), _region_data(nullptr), - _region_count(0), - _block_vspace(nullptr), - _block_data(nullptr), - _block_count(0) {} + _region_count(0) {} bool ParallelCompactData::initialize(MemRegion reserved_heap) { @@ -426,8 +414,7 @@ bool ParallelCompactData::initialize(MemRegion reserved_heap) assert(region_align_down(_heap_start) == _heap_start, "region start not aligned"); - bool result = initialize_region_data(heap_size) && initialize_block_data(); - return result; + return initialize_region_data(heap_size); } PSVirtualSpace* @@ -473,44 +460,12 @@ bool ParallelCompactData::initialize_region_data(size_t heap_size) return false; } -bool ParallelCompactData::initialize_block_data() -{ - assert(_region_count != 0, "region data must be initialized first"); - const size_t count = _region_count << Log2BlocksPerRegion; - _block_vspace = create_vspace(count, sizeof(BlockData)); - if (_block_vspace != 0) { - _block_data = (BlockData*)_block_vspace->reserved_low_addr(); - _block_count = count; - return true; - } - return false; -} - void ParallelCompactData::clear_range(size_t beg_region, size_t end_region) { assert(beg_region <= _region_count, "beg_region out of range"); assert(end_region <= _region_count, "end_region out of range"); - assert(RegionSize % BlockSize == 0, "RegionSize not a multiple of BlockSize"); const size_t region_cnt = end_region - beg_region; memset(_region_data + beg_region, 0, region_cnt * sizeof(RegionData)); - - const size_t beg_block = beg_region * BlocksPerRegion; - const size_t block_cnt = region_cnt * BlocksPerRegion; - memset(_block_data + beg_block, 0, block_cnt * sizeof(BlockData)); -} - -HeapWord* ParallelCompactData::partial_obj_end(size_t region_idx) const -{ - const RegionData* cur_cp = region(region_idx); - const RegionData* const end_cp = region(region_count() - 1); - - HeapWord* result = region_to_addr(region_idx); - if (cur_cp < end_cp) { - do { - result += cur_cp->partial_obj_size(); - } while (cur_cp->partial_obj_size() == RegionSize && ++cur_cp < end_cp); - } - return result; } void @@ -761,49 +716,6 @@ bool ParallelCompactData::summarize(SplitInfo& split_info, return true; } -HeapWord* ParallelCompactData::calc_new_pointer(HeapWord* addr, ParCompactionManager* cm) const { - assert(addr != nullptr, "Should detect null oop earlier"); - assert(ParallelScavengeHeap::heap()->is_in(addr), "not in heap"); - assert(PSParallelCompact::mark_bitmap()->is_marked(addr), "not marked"); - - // Region covering the object. - RegionData* const region_ptr = addr_to_region_ptr(addr); - HeapWord* result = region_ptr->destination(); - - // If the entire Region is live, the new location is region->destination + the - // offset of the object within in the Region. - - // Run some performance tests to determine if this special case pays off. It - // is worth it for pointers into the dense prefix. If the optimization to - // avoid pointer updates in regions that only point to the dense prefix is - // ever implemented, this should be revisited. - if (region_ptr->data_size() == RegionSize) { - result += region_offset(addr); - return result; - } - - // Otherwise, the new location is region->destination + block offset + the - // number of live words in the Block that are (a) to the left of addr and (b) - // due to objects that start in the Block. - - // Fill in the block table if necessary. This is unsynchronized, so multiple - // threads may fill the block table for a region (harmless, since it is - // idempotent). - if (!region_ptr->blocks_filled()) { - PSParallelCompact::fill_blocks(addr_to_region_idx(addr)); - region_ptr->set_blocks_filled(); - } - - HeapWord* const search_start = block_align_down(addr); - const size_t block_offset = addr_to_block_ptr(addr)->offset(); - - const ParMarkBitMap* bitmap = PSParallelCompact::mark_bitmap(); - const size_t live = bitmap->live_words_in_range(cm, search_start, cast_to_oop(addr)); - result += block_offset + live; - DEBUG_ONLY(PSParallelCompact::check_new_location(addr, result)); - return result; -} - #ifdef ASSERT void ParallelCompactData::verify_clear(const PSVirtualSpace* vspace) { @@ -817,7 +729,6 @@ void ParallelCompactData::verify_clear(const PSVirtualSpace* vspace) void ParallelCompactData::verify_clear() { verify_clear(_region_vspace); - verify_clear(_block_vspace); } #endif // #ifdef ASSERT @@ -831,6 +742,19 @@ ParallelCompactData PSParallelCompact::_summary_data; PSParallelCompact::IsAliveClosure PSParallelCompact::_is_alive_closure; +class PCAdjustPointerClosure: public BasicOopIterateClosure { + template + void do_oop_work(T* p) { PSParallelCompact::adjust_pointer(p); } + +public: + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + + virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } +}; + +static PCAdjustPointerClosure pc_adjust_pointer_closure; + bool PSParallelCompact::IsAliveClosure::do_object_b(oop p) { return mark_bitmap()->is_marked(p); } void PSParallelCompact::post_initialize() { @@ -947,8 +871,6 @@ void PSParallelCompact::pre_compact() DEBUG_ONLY(mark_bitmap()->verify_clear();) DEBUG_ONLY(summary_data().verify_clear();) - - ParCompactionManager::reset_all_bitmap_query_caches(); } void PSParallelCompact::post_compact() @@ -1082,18 +1004,20 @@ void PSParallelCompact::fill_dense_prefix_end(SpaceId id) { idx_t const dense_prefix_bit = _mark_bitmap.addr_to_bit(dense_prefix_end); if (region_after_dense_prefix->partial_obj_size() != 0 || - _mark_bitmap.is_obj_beg(dense_prefix_bit)) { + _mark_bitmap.is_marked(dense_prefix_bit)) { // The region after the dense prefix starts with live bytes. return; } - if (_mark_bitmap.is_obj_end(dense_prefix_bit - 2)) { + HeapWord* block_start = start_array(id)->block_start_reaching_into_card(dense_prefix_end); + if (block_start == dense_prefix_end - 1) { + assert(!_mark_bitmap.is_marked(block_start), "inv"); // There is exactly one heap word gap right before the dense prefix end, so we need a filler object. - // The filler object will extend into the region after the last dense prefix region. + // The filler object will extend into region_after_dense_prefix. const size_t obj_len = 2; // min-fill-size HeapWord* const obj_beg = dense_prefix_end - 1; CollectedHeap::fill_with_object(obj_beg, obj_len); - _mark_bitmap.mark_obj(obj_beg, obj_len); + _mark_bitmap.mark_obj(obj_beg); _summary_data.addr_to_region_ptr(obj_beg)->add_live_obj(1); region_after_dense_prefix->set_partial_obj_size(1); region_after_dense_prefix->set_partial_obj_addr(obj_beg); @@ -1359,12 +1283,14 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { DerivedPointerTable::set_active(false); #endif - // adjust_roots() updates Universe::_intArrayKlass which is - // needed by the compaction for filling holes in the dense prefix. - adjust_roots(); + forward_to_new_addr(); + + adjust_pointers(); compact(); + ParCompactionManager::_preserved_marks_set->restore(&ParallelScavengeHeap::heap()->workers()); + ParCompactionManager::verify_all_region_stack_empty(); // Reset the mark bitmap, summary data, and do other bookkeeping. Must be @@ -1685,11 +1611,90 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) { #endif } +template +void PSParallelCompact::adjust_in_space_helper(SpaceId id, volatile uint* claim_counter, Func&& on_stripe) { + MutableSpace* sp = PSParallelCompact::space(id); + HeapWord* const bottom = sp->bottom(); + HeapWord* const top = sp->top(); + if (bottom == top) { + return; + } + + const uint num_regions_per_stripe = 2; + const size_t region_size = ParallelCompactData::RegionSize; + const size_t stripe_size = num_regions_per_stripe * region_size; + + while (true) { + uint counter = Atomic::fetch_then_add(claim_counter, num_regions_per_stripe); + HeapWord* cur_stripe = bottom + counter * region_size; + if (cur_stripe >= top) { + break; + } + HeapWord* stripe_end = MIN2(cur_stripe + stripe_size, top); + on_stripe(cur_stripe, stripe_end); + } +} + +void PSParallelCompact::adjust_in_old_space(volatile uint* claim_counter) { + // Regions in old-space shouldn't be split. + assert(!_space_info[old_space_id].split_info().is_valid(), "inv"); + + auto scan_obj_with_limit = [&] (HeapWord* obj_start, HeapWord* left, HeapWord* right) { + assert(mark_bitmap()->is_marked(obj_start), "inv"); + oop obj = cast_to_oop(obj_start); + return obj->oop_iterate_size(&pc_adjust_pointer_closure, MemRegion(left, right)); + }; + + adjust_in_space_helper(old_space_id, claim_counter, [&] (HeapWord* stripe_start, HeapWord* stripe_end) { + assert(_summary_data.is_region_aligned(stripe_start), "inv"); + RegionData* cur_region = _summary_data.addr_to_region_ptr(stripe_start); + HeapWord* obj_start; + if (cur_region->partial_obj_size() != 0) { + obj_start = cur_region->partial_obj_addr(); + obj_start += scan_obj_with_limit(obj_start, stripe_start, stripe_end); + } else { + obj_start = stripe_start; + } + + while (obj_start < stripe_end) { + obj_start = mark_bitmap()->find_obj_beg(obj_start, stripe_end); + if (obj_start >= stripe_end) { + break; + } + obj_start += scan_obj_with_limit(obj_start, stripe_start, stripe_end); + } + }); +} + +void PSParallelCompact::adjust_in_young_space(SpaceId id, volatile uint* claim_counter) { + adjust_in_space_helper(id, claim_counter, [](HeapWord* stripe_start, HeapWord* stripe_end) { + HeapWord* obj_start = stripe_start; + while (obj_start < stripe_end) { + obj_start = mark_bitmap()->find_obj_beg(obj_start, stripe_end); + if (obj_start >= stripe_end) { + break; + } + oop obj = cast_to_oop(obj_start); + obj_start += obj->oop_iterate_size(&pc_adjust_pointer_closure); + } + }); +} + +void PSParallelCompact::adjust_pointers_in_spaces(uint worker_id, volatile uint* claim_counters) { + auto start_time = Ticks::now(); + adjust_in_old_space(&claim_counters[0]); + for (uint id = eden_space_id; id < last_space_id; ++id) { + adjust_in_young_space(SpaceId(id), &claim_counters[id]); + } + log_trace(gc, phases)("adjust_pointers_in_spaces worker %u: %.3f ms", worker_id, (Ticks::now() - start_time).seconds() * 1000); +} + class PSAdjustTask final : public WorkerTask { SubTasksDone _sub_tasks; WeakProcessor::Task _weak_proc_task; OopStorageSetStrongParState _oop_storage_iter; uint _nworkers; + volatile uint _claim_counters[PSParallelCompact::last_space_id] = {}; enum PSAdjustSubTask { PSAdjustSubTask_code_cache, @@ -1716,36 +1721,165 @@ class PSAdjustTask final : public WorkerTask { void work(uint worker_id) { ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); - PCAdjustPointerClosure adjust(cm); + cm->preserved_marks()->adjust_during_full_gc(); + { + // adjust pointers in all spaces + PSParallelCompact::adjust_pointers_in_spaces(worker_id, _claim_counters); + } { ResourceMark rm; - Threads::possibly_parallel_oops_do(_nworkers > 1, &adjust, nullptr); + Threads::possibly_parallel_oops_do(_nworkers > 1, &pc_adjust_pointer_closure, nullptr); } - _oop_storage_iter.oops_do(&adjust); + _oop_storage_iter.oops_do(&pc_adjust_pointer_closure); { - CLDToOopClosure cld_closure(&adjust, ClassLoaderData::_claim_stw_fullgc_adjust); + CLDToOopClosure cld_closure(&pc_adjust_pointer_closure, ClassLoaderData::_claim_stw_fullgc_adjust); ClassLoaderDataGraph::cld_do(&cld_closure); } { AlwaysTrueClosure always_alive; - _weak_proc_task.work(worker_id, &always_alive, &adjust); + _weak_proc_task.work(worker_id, &always_alive, &pc_adjust_pointer_closure); } if (_sub_tasks.try_claim_task(PSAdjustSubTask_code_cache)) { - NMethodToOopClosure adjust_code(&adjust, NMethodToOopClosure::FixRelocations); + NMethodToOopClosure adjust_code(&pc_adjust_pointer_closure, NMethodToOopClosure::FixRelocations); CodeCache::nmethods_do(&adjust_code); } _sub_tasks.all_tasks_claimed(); } }; -void PSParallelCompact::adjust_roots() { +void PSParallelCompact::adjust_pointers() { // Adjust the pointers to reflect the new locations - GCTraceTime(Info, gc, phases) tm("Adjust Roots", &_gc_timer); + GCTraceTime(Info, gc, phases) tm("Adjust Pointers", &_gc_timer); uint nworkers = ParallelScavengeHeap::heap()->workers().active_workers(); PSAdjustTask task(nworkers); ParallelScavengeHeap::heap()->workers().run_task(&task); } +// Split [start, end) evenly for a number of workers and return the +// range for worker_id. +static void split_regions_for_worker(size_t start, size_t end, + uint worker_id, uint num_workers, + size_t* worker_start, size_t* worker_end) { + assert(start < end, "precondition"); + assert(num_workers > 0, "precondition"); + assert(worker_id < num_workers, "precondition"); + + size_t num_regions = end - start; + size_t num_regions_per_worker = num_regions / num_workers; + size_t remainder = num_regions % num_workers; + // The first few workers will get one extra. + *worker_start = start + worker_id * num_regions_per_worker + + MIN2(checked_cast(worker_id), remainder); + *worker_end = *worker_start + num_regions_per_worker + + (worker_id < remainder ? 1 : 0); +} + +void PSParallelCompact::forward_to_new_addr() { + GCTraceTime(Info, gc, phases) tm("Forward", &_gc_timer); + uint nworkers = ParallelScavengeHeap::heap()->workers().active_workers(); + + struct ForwardTask final : public WorkerTask { + uint _num_workers; + + explicit ForwardTask(uint num_workers) : + WorkerTask("PSForward task"), + _num_workers(num_workers) {} + + void work(uint worker_id) override { + ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); + for (uint id = old_space_id; id < last_space_id; ++id) { + MutableSpace* sp = PSParallelCompact::space(SpaceId(id)); + HeapWord* dense_prefix_addr = dense_prefix(SpaceId(id)); + HeapWord* top = sp->top(); + + if (dense_prefix_addr == top) { + continue; + } + + size_t dense_prefix_region = _summary_data.addr_to_region_idx(dense_prefix_addr); + size_t top_region = _summary_data.addr_to_region_idx(_summary_data.region_align_up(top)); + size_t start_region; + size_t end_region; + split_regions_for_worker(dense_prefix_region, top_region, + worker_id, _num_workers, + &start_region, &end_region); + for (size_t cur_region = start_region; cur_region < end_region; ++cur_region) { + RegionData* region_ptr = _summary_data.region(cur_region); + size_t live_words = region_ptr->partial_obj_size(); + + if (live_words == ParallelCompactData::RegionSize) { + // No obj-start + continue; + } + + HeapWord* region_start = _summary_data.region_to_addr(cur_region); + HeapWord* region_end = region_start + ParallelCompactData::RegionSize; + + HeapWord* cur_addr = region_start + live_words; + + HeapWord* destination = region_ptr->destination(); + while (cur_addr < region_end) { + cur_addr = mark_bitmap()->find_obj_beg(cur_addr, region_end); + if (cur_addr >= region_end) { + break; + } + assert(mark_bitmap()->is_marked(cur_addr), "inv"); + HeapWord* new_addr = destination + live_words; + oop obj = cast_to_oop(cur_addr); + if (new_addr != cur_addr) { + cm->preserved_marks()->push_if_necessary(obj, obj->mark()); + obj->forward_to(cast_to_oop(new_addr)); + } + size_t obj_size = obj->size(); + live_words += obj_size; + cur_addr += obj_size; + } + } + } + } + } task(nworkers); + + ParallelScavengeHeap::heap()->workers().run_task(&task); + debug_only(verify_forward();) +} + +#ifdef ASSERT +void PSParallelCompact::verify_forward() { + HeapWord* old_dense_prefix_addr = dense_prefix(SpaceId(old_space_id)); + RegionData* old_region = _summary_data.region(_summary_data.addr_to_region_idx(old_dense_prefix_addr)); + HeapWord* bump_ptr = old_region->partial_obj_size() != 0 + ? old_dense_prefix_addr + old_region->partial_obj_size() + : old_dense_prefix_addr; + SpaceId bump_ptr_space = old_space_id; + + for (uint id = old_space_id; id < last_space_id; ++id) { + MutableSpace* sp = PSParallelCompact::space(SpaceId(id)); + HeapWord* dense_prefix_addr = dense_prefix(SpaceId(id)); + HeapWord* top = sp->top(); + HeapWord* cur_addr = dense_prefix_addr; + + while (cur_addr < top) { + cur_addr = mark_bitmap()->find_obj_beg(cur_addr, top); + if (cur_addr >= top) { + break; + } + assert(mark_bitmap()->is_marked(cur_addr), "inv"); + // Move to the space containing cur_addr + if (bump_ptr == _space_info[bump_ptr_space].new_top()) { + bump_ptr = space(space_id(cur_addr))->bottom(); + bump_ptr_space = space_id(bump_ptr); + } + oop obj = cast_to_oop(cur_addr); + if (cur_addr != bump_ptr) { + assert(obj->forwardee() == cast_to_oop(bump_ptr), "inv"); + } + bump_ptr += obj->size(); + cur_addr += obj->size(); + } + } +} +#endif + // Helper class to print 8 region numbers per line and then print the total at the end. class FillableRegionLogger : public StackObj { private: @@ -1826,160 +1960,6 @@ void PSParallelCompact::prepare_region_draining_tasks(uint parallel_gc_threads) } } -class TaskQueue : StackObj { - volatile uint _counter; - uint _size; - uint _insert_index; - PSParallelCompact::UpdateDensePrefixTask* _backing_array; -public: - explicit TaskQueue(uint size) : _counter(0), _size(size), _insert_index(0), _backing_array(nullptr) { - _backing_array = NEW_C_HEAP_ARRAY(PSParallelCompact::UpdateDensePrefixTask, _size, mtGC); - } - ~TaskQueue() { - assert(_counter >= _insert_index, "not all queue elements were claimed"); - FREE_C_HEAP_ARRAY(T, _backing_array); - } - - void push(const PSParallelCompact::UpdateDensePrefixTask& value) { - assert(_insert_index < _size, "too small backing array"); - _backing_array[_insert_index++] = value; - } - - bool try_claim(PSParallelCompact::UpdateDensePrefixTask& reference) { - uint claimed = Atomic::fetch_then_add(&_counter, 1u); - if (claimed < _insert_index) { - reference = _backing_array[claimed]; - return true; - } else { - return false; - } - } -}; - -#define PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING 4 - -void PSParallelCompact::enqueue_dense_prefix_tasks(TaskQueue& task_queue, - uint parallel_gc_threads) { - GCTraceTime(Trace, gc, phases) tm("Dense Prefix Task Setup", &_gc_timer); - - ParallelCompactData& sd = PSParallelCompact::summary_data(); - - // Iterate over all the spaces adding tasks for updating - // regions in the dense prefix. Assume that 1 gc thread - // will work on opening the gaps and the remaining gc threads - // will work on the dense prefix. - unsigned int space_id; - for (space_id = old_space_id; space_id < last_space_id; ++ space_id) { - HeapWord* const dense_prefix_end = _space_info[space_id].dense_prefix(); - const MutableSpace* const space = _space_info[space_id].space(); - - if (dense_prefix_end == space->bottom()) { - // There is no dense prefix for this space. - continue; - } - - // The dense prefix is before this region. - size_t region_index_end_dense_prefix = - sd.addr_to_region_idx(dense_prefix_end); - RegionData* const dense_prefix_cp = - sd.region(region_index_end_dense_prefix); - assert(dense_prefix_end == space->end() || - dense_prefix_cp->available() || - dense_prefix_cp->claimed(), - "The region after the dense prefix should always be ready to fill"); - - size_t region_index_start = sd.addr_to_region_idx(space->bottom()); - - // Is there dense prefix work? - size_t total_dense_prefix_regions = - region_index_end_dense_prefix - region_index_start; - // How many regions of the dense prefix should be given to - // each thread? - if (total_dense_prefix_regions > 0) { - uint tasks_for_dense_prefix = 1; - if (total_dense_prefix_regions <= - (parallel_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING)) { - // Don't over partition. This assumes that - // PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING is a small integer value - // so there are not many regions to process. - tasks_for_dense_prefix = parallel_gc_threads; - } else { - // Over partition - tasks_for_dense_prefix = parallel_gc_threads * - PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING; - } - size_t regions_per_thread = total_dense_prefix_regions / - tasks_for_dense_prefix; - // Give each thread at least 1 region. - if (regions_per_thread == 0) { - regions_per_thread = 1; - } - - for (uint k = 0; k < tasks_for_dense_prefix; k++) { - if (region_index_start >= region_index_end_dense_prefix) { - break; - } - // region_index_end is not processed - size_t region_index_end = MIN2(region_index_start + regions_per_thread, - region_index_end_dense_prefix); - task_queue.push(UpdateDensePrefixTask(SpaceId(space_id), - region_index_start, - region_index_end)); - region_index_start = region_index_end; - } - } - // This gets any part of the dense prefix that did not - // fit evenly. - if (region_index_start < region_index_end_dense_prefix) { - task_queue.push(UpdateDensePrefixTask(SpaceId(space_id), - region_index_start, - region_index_end_dense_prefix)); - } - } -} - -#ifdef ASSERT -// Write a histogram of the number of times the block table was filled for a -// region. -void PSParallelCompact::write_block_fill_histogram() -{ - if (!log_develop_is_enabled(Trace, gc, compaction)) { - return; - } - - Log(gc, compaction) log; - ResourceMark rm; - LogStream ls(log.trace()); - outputStream* out = &ls; - - typedef ParallelCompactData::RegionData rd_t; - ParallelCompactData& sd = summary_data(); - - for (unsigned int id = old_space_id; id < last_space_id; ++id) { - MutableSpace* const spc = _space_info[id].space(); - if (spc->bottom() != spc->top()) { - const rd_t* const beg = sd.addr_to_region_ptr(spc->bottom()); - HeapWord* const top_aligned_up = sd.region_align_up(spc->top()); - const rd_t* const end = sd.addr_to_region_ptr(top_aligned_up); - - size_t histo[5] = { 0, 0, 0, 0, 0 }; - const size_t histo_len = sizeof(histo) / sizeof(size_t); - const size_t region_cnt = pointer_delta(end, beg, sizeof(rd_t)); - - for (const rd_t* cur = beg; cur < end; ++cur) { - ++histo[MIN2(cur->blocks_filled_count(), histo_len - 1)]; - } - out->print("Block fill histogram: %u %-4s" SIZE_FORMAT_W(5), id, space_names[id], region_cnt); - for (size_t i = 0; i < histo_len; ++i) { - out->print(" " SIZE_FORMAT_W(5) " %5.1f%%", - histo[i], 100.0 * histo[i] / region_cnt); - } - out->cr(); - } - } -} -#endif // #ifdef ASSERT - static void compaction_with_stealing_work(TaskTerminator* terminator, uint worker_id) { assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); @@ -2012,72 +1992,146 @@ static void compaction_with_stealing_work(TaskTerminator* terminator, uint worke } } -class UpdateDensePrefixAndCompactionTask: public WorkerTask { - TaskQueue& _tq; +class FillDensePrefixAndCompactionTask: public WorkerTask { + uint _num_workers; TaskTerminator _terminator; public: - UpdateDensePrefixAndCompactionTask(TaskQueue& tq, uint active_workers) : - WorkerTask("UpdateDensePrefixAndCompactionTask"), - _tq(tq), + FillDensePrefixAndCompactionTask(uint active_workers) : + WorkerTask("FillDensePrefixAndCompactionTask"), + _num_workers(active_workers), _terminator(active_workers, ParCompactionManager::region_task_queues()) { } + virtual void work(uint worker_id) { - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); + { + auto start = Ticks::now(); + PSParallelCompact::fill_dead_objs_in_dense_prefix(worker_id, _num_workers); + log_trace(gc, phases)("Fill dense prefix by worker %u: %.3f ms", worker_id, (Ticks::now() - start).seconds() * 1000); + } + compaction_with_stealing_work(&_terminator, worker_id); + } +}; - for (PSParallelCompact::UpdateDensePrefixTask task; _tq.try_claim(task); /* empty */) { - PSParallelCompact::update_and_deadwood_in_dense_prefix(cm, - task._space_id, - task._region_index_start, - task._region_index_end); +void PSParallelCompact::fill_range_in_dense_prefix(HeapWord* start, HeapWord* end) { +#ifdef ASSERT + { + assert(start < end, "precondition"); + assert(mark_bitmap()->find_obj_beg(start, end) == end, "precondition"); + HeapWord* bottom = _space_info[old_space_id].space()->bottom(); + if (start != bottom) { + HeapWord* obj_start = mark_bitmap()->find_obj_beg_reverse(bottom, start); + HeapWord* after_obj = obj_start + cast_to_oop(obj_start)->size(); + assert(after_obj == start, "precondition"); } + } +#endif - // Once a thread has drained it's stack, it should try to steal regions from - // other threads. - compaction_with_stealing_work(&_terminator, worker_id); + CollectedHeap::fill_with_objects(start, pointer_delta(end, start)); + HeapWord* addr = start; + do { + size_t size = cast_to_oop(addr)->size(); + start_array(old_space_id)->update_for_block(addr, addr + size); + addr += size; + } while (addr < end); +} + +void PSParallelCompact::fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers) { + ParMarkBitMap* bitmap = mark_bitmap(); + + HeapWord* const bottom = _space_info[old_space_id].space()->bottom(); + HeapWord* const prefix_end = dense_prefix(old_space_id); - // At this point all regions have been compacted, so it's now safe - // to update the deferred objects that cross region boundaries. - cm->drain_deferred_objects(); + if (bottom == prefix_end) { + return; } -}; + + size_t bottom_region = _summary_data.addr_to_region_idx(bottom); + size_t prefix_end_region = _summary_data.addr_to_region_idx(prefix_end); + + size_t start_region; + size_t end_region; + split_regions_for_worker(bottom_region, prefix_end_region, + worker_id, num_workers, + &start_region, &end_region); + + if (start_region == end_region) { + return; + } + + HeapWord* const start_addr = _summary_data.region_to_addr(start_region); + HeapWord* const end_addr = _summary_data.region_to_addr(end_region); + + // Skip live partial obj (if any) from previous region. + HeapWord* cur_addr; + RegionData* start_region_ptr = _summary_data.region(start_region); + if (start_region_ptr->partial_obj_size() != 0) { + HeapWord* partial_obj_start = start_region_ptr->partial_obj_addr(); + assert(bitmap->is_marked(partial_obj_start), "inv"); + cur_addr = partial_obj_start + cast_to_oop(partial_obj_start)->size(); + } else { + cur_addr = start_addr; + } + + // end_addr is inclusive to handle regions starting with dead space. + while (cur_addr <= end_addr) { + // Use prefix_end to handle trailing obj in each worker region-chunk. + HeapWord* live_start = bitmap->find_obj_beg(cur_addr, prefix_end); + if (cur_addr != live_start) { + // Only worker 0 handles proceeding dead space. + if (cur_addr != start_addr || worker_id == 0) { + fill_range_in_dense_prefix(cur_addr, live_start); + } + } + if (live_start >= end_addr) { + break; + } + assert(bitmap->is_marked(live_start), "inv"); + cur_addr = live_start + cast_to_oop(live_start)->size(); + } +} void PSParallelCompact::compact() { GCTraceTime(Info, gc, phases) tm("Compaction Phase", &_gc_timer); - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - PSOldGen* old_gen = heap->old_gen(); uint active_gc_threads = ParallelScavengeHeap::heap()->workers().active_workers(); - // for [0..last_space_id) - // for [0..active_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING) - // push - // push - // - // max push count is thus: last_space_id * (active_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING + 1) - TaskQueue task_queue(last_space_id * (active_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING + 1)); initialize_shadow_regions(active_gc_threads); prepare_region_draining_tasks(active_gc_threads); - enqueue_dense_prefix_tasks(task_queue, active_gc_threads); { GCTraceTime(Trace, gc, phases) tm("Par Compact", &_gc_timer); - UpdateDensePrefixAndCompactionTask task(task_queue, active_gc_threads); + FillDensePrefixAndCompactionTask task(active_gc_threads); ParallelScavengeHeap::heap()->workers().run_task(&task); #ifdef ASSERT + verify_filler_in_dense_prefix(); + // Verify that all regions have been processed. for (unsigned int id = old_space_id; id < last_space_id; ++id) { verify_complete(SpaceId(id)); } #endif } - - DEBUG_ONLY(write_block_fill_histogram()); } #ifdef ASSERT +void PSParallelCompact::verify_filler_in_dense_prefix() { + HeapWord* bottom = _space_info[old_space_id].space()->bottom(); + HeapWord* dense_prefix_end = dense_prefix(old_space_id); + HeapWord* cur_addr = bottom; + while (cur_addr < dense_prefix_end) { + oop obj = cast_to_oop(cur_addr); + oopDesc::verify(obj); + if (!mark_bitmap()->is_marked(cur_addr)) { + Klass* k = cast_to_oop(cur_addr)->klass_without_asserts(); + assert(k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(), "inv"); + } + cur_addr += obj->size(); + } +} + void PSParallelCompact::verify_complete(SpaceId space_id) { // All Regions between space bottom() to new_top() should be marked as filled // and all Regions between new_top() and top() should be available (i.e., @@ -2117,72 +2171,6 @@ void PSParallelCompact::verify_complete(SpaceId space_id) { } #endif // #ifdef ASSERT -inline void UpdateOnlyClosure::do_addr(HeapWord* addr) { - compaction_manager()->update_contents(cast_to_oop(addr)); -} - -// Update interior oops in the ranges of regions [beg_region, end_region). -void -PSParallelCompact::update_and_deadwood_in_dense_prefix(ParCompactionManager* cm, - SpaceId space_id, - size_t beg_region, - size_t end_region) { - ParallelCompactData& sd = summary_data(); - ParMarkBitMap* const mbm = mark_bitmap(); - - HeapWord* beg_addr = sd.region_to_addr(beg_region); - HeapWord* const end_addr = sd.region_to_addr(end_region); - assert(beg_region <= end_region, "bad region range"); - assert(end_addr <= dense_prefix(space_id), "not in the dense prefix"); - -#ifdef ASSERT - // Claim the regions to avoid triggering an assert when they are marked as - // filled. - for (size_t claim_region = beg_region; claim_region < end_region; ++claim_region) { - assert(sd.region(claim_region)->claim_unsafe(), "claim() failed"); - } -#endif // #ifdef ASSERT - HeapWord* const space_bottom = space(space_id)->bottom(); - - // Check if it's the first region in this space. - if (beg_addr != space_bottom) { - // Find the first live object or block of dead space that *starts* in this - // range of regions. If a partial object crosses onto the region, skip it; - // it will be marked for 'deferred update' when the object head is - // processed. If dead space crosses onto the region, it is also skipped; it - // will be filled when the prior region is processed. If neither of those - // apply, the first word in the region is the start of a live object or dead - // space. - assert(beg_addr > space(space_id)->bottom(), "sanity"); - const RegionData* const cp = sd.region(beg_region); - if (cp->partial_obj_size() != 0) { - beg_addr = sd.partial_obj_end(beg_region); - } else { - idx_t beg_bit = mbm->addr_to_bit(beg_addr); - if (!mbm->is_obj_beg(beg_bit) && !mbm->is_obj_end(beg_bit - 1)) { - beg_addr = mbm->find_obj_beg(beg_addr, end_addr); - } - } - } - - if (beg_addr < end_addr) { - // A live object or block of dead space starts in this range of Regions. - HeapWord* const dense_prefix_end = dense_prefix(space_id); - - // Create closures and iterate. - UpdateOnlyClosure update_closure(mbm, cm, space_id); - FillClosure fill_closure(cm, space_id); - mbm->iterate(&update_closure, &fill_closure, beg_addr, end_addr, dense_prefix_end); - } - - // Mark the regions as filled. - RegionData* const beg_cp = sd.region(beg_region); - RegionData* const end_cp = sd.region(end_region); - for (RegionData* cp = beg_cp; cp < end_cp; ++cp) { - cp->set_completed(); - } -} - // Return the SpaceId for the space containing addr. If addr is not in the // heap, last_space_id is returned. In debug mode it expects the address to be // in the heap and asserts such. @@ -2199,24 +2187,6 @@ PSParallelCompact::SpaceId PSParallelCompact::space_id(HeapWord* addr) { return last_space_id; } -void PSParallelCompact::update_deferred_object(ParCompactionManager* cm, HeapWord *addr) { -#ifdef ASSERT - ParallelCompactData& sd = summary_data(); - size_t region_idx = sd.addr_to_region_idx(addr); - assert(sd.region(region_idx)->completed(), "first region must be completed before deferred updates"); - assert(sd.region(region_idx + 1)->completed(), "second region must be completed before deferred updates"); -#endif - - const SpaceInfo* const space_info = _space_info + space_id(addr); - ObjectStartArray* const start_array = space_info->start_array(); - if (start_array != nullptr) { - start_array->update_for_block(addr, addr + cast_to_oop(addr)->size()); - } - - cm->update_contents(cast_to_oop(addr)); - assert(oopDesc::is_oop(cast_to_oop(addr)), "Expected an oop at " PTR_FORMAT, p2i(cast_to_oop(addr))); -} - // Skip over count live words starting from beg, and return the address of the // next live word. Unless marked, the word corresponding to beg is assumed to // be dead. Callers must either ensure beg does not correspond to the middle of @@ -2228,26 +2198,18 @@ PSParallelCompact::skip_live_words(HeapWord* beg, HeapWord* end, size_t count) assert(count > 0, "sanity"); ParMarkBitMap* m = mark_bitmap(); - idx_t bits_to_skip = m->words_to_bits(count); - idx_t cur_beg = m->addr_to_bit(beg); - const idx_t search_end = m->align_range_end(m->addr_to_bit(end)); - - do { - cur_beg = m->find_obj_beg(cur_beg, search_end); - idx_t cur_end = m->find_obj_end(cur_beg, search_end); - const size_t obj_bits = cur_end - cur_beg + 1; - if (obj_bits > bits_to_skip) { - return m->bit_to_addr(cur_beg + bits_to_skip); + HeapWord* cur_addr = beg; + while (true) { + cur_addr = m->find_obj_beg(cur_addr, end); + assert(cur_addr < end, "inv"); + size_t obj_size = cast_to_oop(cur_addr)->size(); + // Strictly greater-than + if (obj_size > count) { + return cur_addr + count; } - bits_to_skip -= obj_bits; - cur_beg = cur_end + 1; - } while (bits_to_skip > 0); - - // Skipping the desired number of words landed just past the end of an object. - // Find the start of the next object. - cur_beg = m->find_obj_beg(cur_beg, search_end); - assert(cur_beg < m->addr_to_bit(end), "not enough live words to skip"); - return m->bit_to_addr(cur_beg); + count -= obj_size; + cur_addr += obj_size; + } } HeapWord* PSParallelCompact::first_src_addr(HeapWord* const dest_addr, @@ -2431,9 +2393,31 @@ size_t PSParallelCompact::next_src_region(MoveAndUpdateClosure& closure, return 0; } +HeapWord* PSParallelCompact::partial_obj_end(HeapWord* region_start_addr) { + ParallelCompactData& sd = summary_data(); + assert(sd.is_region_aligned(region_start_addr), "precondition"); + + // Use per-region partial_obj_size to locate the end of the obj, that extends to region_start_addr. + SplitInfo& split_info = _space_info[space_id(region_start_addr)].split_info(); + size_t start_region_idx = sd.addr_to_region_idx(region_start_addr); + size_t end_region_idx = sd.region_count(); + size_t accumulated_size = 0; + for (size_t region_idx = start_region_idx; region_idx < end_region_idx; ++region_idx) { + if (split_info.is_split(region_idx)) { + accumulated_size += split_info.partial_obj_size(); + break; + } + size_t cur_partial_obj_size = sd.region(region_idx)->partial_obj_size(); + accumulated_size += cur_partial_obj_size; + if (cur_partial_obj_size != ParallelCompactData::RegionSize) { + break; + } + } + return region_start_addr + accumulated_size; +} + void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosure& closure, size_t region_idx) { - typedef ParMarkBitMap::IterationStatus IterationStatus; ParMarkBitMap* const bitmap = mark_bitmap(); ParallelCompactData& sd = summary_data(); RegionData* const region_ptr = sd.region(region_idx); @@ -2457,7 +2441,30 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu // of the object or as much as will fit. The fact that pointer updates were // deferred will be noted when the object header is processed. HeapWord* const old_src_addr = closure.source(); - closure.copy_partial_obj(); + { + HeapWord* region_start = sd.region_align_down(closure.source()); + HeapWord* obj_start = bitmap->find_obj_beg_reverse(region_start, closure.source()); + HeapWord* obj_end; + if (bitmap->is_marked(obj_start)) { + HeapWord* next_region_start = region_start + ParallelCompactData::RegionSize; + HeapWord* partial_obj_start = (next_region_start >= src_space_top) + ? nullptr + : sd.addr_to_region_ptr(next_region_start)->partial_obj_addr(); + if (partial_obj_start == obj_start) { + // This obj extends to next region. + obj_end = partial_obj_end(next_region_start); + } else { + // Completely contained in this region; safe to use size(). + obj_end = obj_start + cast_to_oop(obj_start)->size(); + } + } else { + // This obj extends to current region. + obj_end = partial_obj_end(region_start); + } + size_t partial_obj_size = pointer_delta(obj_end, closure.source()); + closure.copy_partial_obj(partial_obj_size); + } + if (closure.is_full()) { decrement_destination_counts(cm, src_space_id, src_region_idx, closure.source()); @@ -2478,24 +2485,30 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu } do { - HeapWord* const cur_addr = closure.source(); + HeapWord* cur_addr = closure.source(); HeapWord* const end_addr = MIN2(sd.region_align_up(cur_addr + 1), src_space_top); - IterationStatus status = bitmap->iterate(&closure, cur_addr, end_addr); - - if (status == ParMarkBitMap::would_overflow) { - // The last object did not fit. Note that interior oop updates were - // deferred, then copy enough of the object to fill the region. - cm->push_deferred_object(closure.destination()); - status = closure.copy_until_full(); // copies from closure.source() - - decrement_destination_counts(cm, src_space_id, src_region_idx, - closure.source()); - closure.complete_region(cm, dest_addr, region_ptr); - return; - } + HeapWord* partial_obj_start = (end_addr == src_space_top) + ? nullptr + : sd.addr_to_region_ptr(end_addr)->partial_obj_addr(); + // apply closure on objs inside [cur_addr, end_addr) + do { + cur_addr = bitmap->find_obj_beg(cur_addr, end_addr); + if (cur_addr == end_addr) { + break; + } + size_t obj_size; + if (partial_obj_start == cur_addr) { + obj_size = pointer_delta(partial_obj_end(end_addr), cur_addr); + } else { + // This obj doesn't extend into next region; size() is safe to use. + obj_size = cast_to_oop(cur_addr)->size(); + } + closure.do_addr(cur_addr, obj_size); + cur_addr += obj_size; + } while (cur_addr < end_addr && !closure.is_full()); - if (status == ParMarkBitMap::full) { + if (closure.is_full()) { decrement_destination_counts(cm, src_space_id, src_region_idx, closure.source()); closure.complete_region(cm, dest_addr, region_ptr); @@ -2595,77 +2608,9 @@ void PSParallelCompact::initialize_shadow_regions(uint parallel_gc_threads) } } -void PSParallelCompact::fill_blocks(size_t region_idx) +void MoveAndUpdateClosure::copy_partial_obj(size_t partial_obj_size) { - // Fill in the block table elements for the specified region. Each block - // table element holds the number of live words in the region that are to the - // left of the first object that starts in the block. Thus only blocks in - // which an object starts need to be filled. - // - // The algorithm scans the section of the bitmap that corresponds to the - // region, keeping a running total of the live words. When an object start is - // found, if it's the first to start in the block that contains it, the - // current total is written to the block table element. - const size_t Log2BlockSize = ParallelCompactData::Log2BlockSize; - const size_t Log2RegionSize = ParallelCompactData::Log2RegionSize; - const size_t RegionSize = ParallelCompactData::RegionSize; - - ParallelCompactData& sd = summary_data(); - const size_t partial_obj_size = sd.region(region_idx)->partial_obj_size(); - if (partial_obj_size >= RegionSize) { - return; // No objects start in this region. - } - - // Ensure the first loop iteration decides that the block has changed. - size_t cur_block = sd.block_count(); - - const ParMarkBitMap* const bitmap = mark_bitmap(); - - const size_t Log2BitsPerBlock = Log2BlockSize - LogMinObjAlignment; - assert((size_t)1 << Log2BitsPerBlock == - bitmap->words_to_bits(ParallelCompactData::BlockSize), "sanity"); - - size_t beg_bit = bitmap->words_to_bits(region_idx << Log2RegionSize); - const size_t range_end = beg_bit + bitmap->words_to_bits(RegionSize); - size_t live_bits = bitmap->words_to_bits(partial_obj_size); - beg_bit = bitmap->find_obj_beg(beg_bit + live_bits, range_end); - while (beg_bit < range_end) { - const size_t new_block = beg_bit >> Log2BitsPerBlock; - if (new_block != cur_block) { - cur_block = new_block; - sd.block(cur_block)->set_offset(bitmap->bits_to_words(live_bits)); - } - - const size_t end_bit = bitmap->find_obj_end(beg_bit, range_end); - if (end_bit < range_end - 1) { - live_bits += end_bit - beg_bit + 1; - beg_bit = bitmap->find_obj_beg(end_bit + 1, range_end); - } else { - return; - } - } -} - -ParMarkBitMap::IterationStatus MoveAndUpdateClosure::copy_until_full() -{ - if (source() != copy_destination()) { - DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) - Copy::aligned_conjoint_words(source(), copy_destination(), words_remaining()); - } - update_state(words_remaining()); - assert(is_full(), "sanity"); - return ParMarkBitMap::full; -} - -void MoveAndUpdateClosure::copy_partial_obj() -{ - size_t words = words_remaining(); - - HeapWord* const range_end = MIN2(source() + words, bitmap()->region_end()); - HeapWord* const end_addr = bitmap()->find_obj_end(source(), range_end); - if (end_addr < range_end) { - words = bitmap()->obj_size(source(), end_addr); - } + size_t words = MIN2(partial_obj_size, words_remaining()); // This test is necessary; if omitted, the pointer updates to a partial object // that crosses the dense prefix boundary could be overwritten. @@ -2685,32 +2630,27 @@ void MoveAndUpdateClosure::complete_region(ParCompactionManager *cm, HeapWord *d ParMarkBitMapClosure::IterationStatus MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { assert(destination() != nullptr, "sanity"); - assert(bitmap()->obj_size(addr) == words, "bad size"); - _source = addr; - assert(PSParallelCompact::summary_data().calc_new_pointer(source(), compaction_manager()) == - destination(), "wrong destination"); - - if (words > words_remaining()) { - return ParMarkBitMap::would_overflow; - } // The start_array must be updated even if the object is not moving. if (_start_array != nullptr) { _start_array->update_for_block(destination(), destination() + words); } + // Avoid overflow + words = MIN2(words, words_remaining()); + assert(words > 0, "inv"); + if (copy_destination() != source()) { DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) + assert(source() != destination(), "inv"); + assert(cast_to_oop(source())->is_forwarded(), "inv"); + assert(cast_to_oop(source())->forwardee() == cast_to_oop(destination()), "inv"); Copy::aligned_conjoint_words(source(), copy_destination(), words); + cast_to_oop(copy_destination())->init_mark(); } - oop moved_oop = cast_to_oop(copy_destination()); - compaction_manager()->update_contents(moved_oop); - assert(oopDesc::is_oop_or_null(moved_oop), "Expected an oop or null at " PTR_FORMAT, p2i(moved_oop)); - update_state(words); - assert(copy_destination() == cast_from_oop(moved_oop) + moved_oop->size(), "sanity"); return is_full() ? ParMarkBitMap::full : ParMarkBitMap::incomplete; } @@ -2733,37 +2673,3 @@ void MoveAndUpdateShadowClosure::complete_region(ParCompactionManager *cm, HeapW } } -UpdateOnlyClosure::UpdateOnlyClosure(ParMarkBitMap* mbm, - ParCompactionManager* cm, - PSParallelCompact::SpaceId space_id) : - ParMarkBitMapClosure(mbm, cm), - _start_array(PSParallelCompact::start_array(space_id)) -{ -} - -// Updates the references in the object to their new values. -ParMarkBitMapClosure::IterationStatus -UpdateOnlyClosure::do_addr(HeapWord* addr, size_t words) { - do_addr(addr); - return ParMarkBitMap::incomplete; -} - -FillClosure::FillClosure(ParCompactionManager* cm, PSParallelCompact::SpaceId space_id) : - ParMarkBitMapClosure(PSParallelCompact::mark_bitmap(), cm), - _start_array(PSParallelCompact::start_array(space_id)) -{ - assert(space_id == PSParallelCompact::old_space_id, - "cannot use FillClosure in the young gen"); -} - -ParMarkBitMapClosure::IterationStatus -FillClosure::do_addr(HeapWord* addr, size_t size) { - CollectedHeap::fill_with_objects(addr, size); - HeapWord* const end = addr + size; - do { - size_t size = cast_to_oop(addr)->size(); - _start_array->update_for_block(addr, addr + size); - addr += size; - } while (addr < end); - return ParMarkBitMap::incomplete; -} diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index a36acc72a9ba4..67346d7eee501 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -215,17 +215,6 @@ class ParallelCompactData // Mask for the bits in a pointer to get the address of the start of a region. static const size_t RegionAddrMask; - static const size_t Log2BlockSize; - static const size_t BlockSize; - static const size_t BlockSizeBytes; - - static const size_t BlockSizeOffsetMask; - static const size_t BlockAddrOffsetMask; - static const size_t BlockAddrMask; - - static const size_t BlocksPerRegion; - static const size_t Log2BlocksPerRegion; - class RegionData { public: @@ -274,12 +263,6 @@ class ParallelCompactData inline uint destination_count() const; inline uint destination_count_raw() const; - // Whether the block table for this region has been filled. - inline bool blocks_filled() const; - - // Number of times the block table was filled. - DEBUG_ONLY(inline size_t blocks_filled_count() const;) - // Whether this region is available to be claimed, has been claimed, or has // been completed. // @@ -298,7 +281,6 @@ class ParallelCompactData void set_partial_obj_size(size_t words) { _partial_obj_size = (region_sz_t) words; } - inline void set_blocks_filled(); inline void set_destination_count(uint count); inline void set_live_obj_size(size_t words); @@ -356,13 +338,8 @@ class ParallelCompactData HeapWord* _partial_obj_addr; region_sz_t _partial_obj_size; region_sz_t volatile _dc_and_los; - bool volatile _blocks_filled; int volatile _shadow_state; -#ifdef ASSERT - size_t _blocks_filled_count; // Number of block table fills. -#endif // #ifdef ASSERT - #ifdef ASSERT public: uint _pushed; // 0 until region is pushed onto a stack @@ -370,21 +347,6 @@ class ParallelCompactData #endif }; - // "Blocks" allow shorter sections of the bitmap to be searched. Each Block - // holds an offset, which is the amount of live data in the Region to the left - // of the first live object that starts in the Block. - class BlockData - { - public: - typedef unsigned short int blk_ofs_t; - - blk_ofs_t offset() const { return _offset; } - void set_offset(size_t val) { _offset = (blk_ofs_t)val; } - - private: - blk_ofs_t _offset; - }; - public: ParallelCompactData(); bool initialize(MemRegion reserved_heap); @@ -396,9 +358,6 @@ class ParallelCompactData inline RegionData* region(size_t region_idx) const; inline size_t region(const RegionData* const region_ptr) const; - size_t block_count() const { return _block_count; } - inline BlockData* block(size_t block_idx) const; - // Fill in the regions covering [beg, end) so that no data moves; i.e., the // destination of region n is simply the start of region n. Both arguments // beg and end must be region-aligned. @@ -436,28 +395,12 @@ class ParallelCompactData inline HeapWord* region_align_up(HeapWord* addr) const; inline bool is_region_aligned(HeapWord* addr) const; - size_t addr_to_block_idx(const HeapWord* addr) const; - inline BlockData* addr_to_block_ptr(const HeapWord* addr) const; - - inline HeapWord* block_align_down(HeapWord* addr) const; - - // Return the address one past the end of the partial object. - HeapWord* partial_obj_end(size_t region_idx) const; - - // Return the location of the object after compaction. - HeapWord* calc_new_pointer(HeapWord* addr, ParCompactionManager* cm) const; - - HeapWord* calc_new_pointer(oop p, ParCompactionManager* cm) const { - return calc_new_pointer(cast_from_oop(p), cm); - } - #ifdef ASSERT void verify_clear(const PSVirtualSpace* vspace); void verify_clear(); #endif // #ifdef ASSERT private: - bool initialize_block_data(); bool initialize_region_data(size_t heap_size); PSVirtualSpace* create_vspace(size_t count, size_t element_size); @@ -470,10 +413,6 @@ class ParallelCompactData size_t _reserved_byte_size; RegionData* _region_data; size_t _region_count; - - PSVirtualSpace* _block_vspace; - BlockData* _block_data; - size_t _block_count; }; inline uint @@ -488,31 +427,6 @@ ParallelCompactData::RegionData::destination_count() const return destination_count_raw() >> dc_shift; } -inline bool -ParallelCompactData::RegionData::blocks_filled() const -{ - bool result = _blocks_filled; - OrderAccess::acquire(); - return result; -} - -#ifdef ASSERT -inline size_t -ParallelCompactData::RegionData::blocks_filled_count() const -{ - return _blocks_filled_count; -} -#endif // #ifdef ASSERT - -inline void -ParallelCompactData::RegionData::set_blocks_filled() -{ - OrderAccess::release(); - _blocks_filled = true; - // Debug builds count the number of times the table was filled. - DEBUG_ONLY(Atomic::inc(&_blocks_filled_count)); -} - inline void ParallelCompactData::RegionData::set_destination_count(uint count) { @@ -602,12 +516,6 @@ ParallelCompactData::region(const RegionData* const region_ptr) const return pointer_delta(region_ptr, _region_data, sizeof(RegionData)); } -inline ParallelCompactData::BlockData* -ParallelCompactData::block(size_t n) const { - assert(n < block_count(), "bad arg"); - return _block_data + n; -} - inline size_t ParallelCompactData::region_offset(const HeapWord* addr) const { @@ -667,28 +575,6 @@ ParallelCompactData::is_region_aligned(HeapWord* addr) const return (size_t(addr) & RegionAddrOffsetMask) == 0; } -inline size_t -ParallelCompactData::addr_to_block_idx(const HeapWord* addr) const -{ - assert(addr >= _heap_start, "bad addr"); - assert(addr <= _heap_end, "bad addr"); - return pointer_delta(addr, _heap_start) >> Log2BlockSize; -} - -inline ParallelCompactData::BlockData* -ParallelCompactData::addr_to_block_ptr(const HeapWord* addr) const -{ - return block(addr_to_block_idx(addr)); -} - -inline HeapWord* -ParallelCompactData::block_align_down(HeapWord* addr) const -{ - assert(addr >= _heap_start, "bad addr"); - assert(addr < _heap_end + RegionSize, "bad addr"); - return (HeapWord*)(size_t(addr) & BlockAddrMask); -} - // Abstract closure for use with ParMarkBitMap::iterate(), which will invoke the // do_addr() method. // @@ -774,25 +660,24 @@ inline void ParMarkBitMapClosure::decrement_words_remaining(size_t words) { // does parts of the collection using parallel threads. The collection includes // the tenured generation and the young generation. // -// There are four phases of the collection. +// A collection consists of the following phases. // // - marking phase -// - summary phase +// - summary phase (single-threaded) +// - forward (to new address) phase +// - adjust pointers phase // - compacting phase // - clean up phase // // Roughly speaking these phases correspond, respectively, to +// // - mark all the live objects +// - calculating destination-region for each region for better parallellism in following phases // - calculate the destination of each object at the end of the collection +// - adjust pointers to reflect new destination of objects // - move the objects to their destination // - update some references and reinitialize some variables // -// These three phases are invoked in PSParallelCompact::invoke_no_policy(). The -// marking phase is implemented in PSParallelCompact::marking_phase() and does a -// complete marking of the heap. The summary phase is implemented in -// PSParallelCompact::summary_phase(). The move and update phase is implemented -// in PSParallelCompact::compact(). -// // A space that is being collected is divided into regions and with each region // is associated an object of type ParallelCompactData. Each region is of a // fixed size and typically will contain more than 1 object and may have parts @@ -828,17 +713,12 @@ inline void ParMarkBitMapClosure::decrement_words_remaining(size_t words) { // dense prefix do need to have their object references updated. See method // summarize_dense_prefix(). // -// The summary phase is done using 1 GC thread. +// The forward (to new address) phase calculates the new address of each +// objects and records old-addr-to-new-addr asssociation. // -// The compaction phase moves objects to their new location and updates all -// references in the object. +// The adjust pointers phase remap all pointers to reflect the new address of each object. // -// A current exception is that objects that cross a region boundary are moved -// but do not have their references updated. References are not updated because -// it cannot easily be determined if the klass pointer KKK for the object AAA -// has been updated. KKK likely resides in a region to the left of the region -// containing AAA. These AAA's have their references updated at the end in a -// clean up phase. See the method PSParallelCompact::update_deferred_object(). +// The compaction phase moves objects to their new location. // // Compaction is done on a region basis. A region that is ready to be filled is // put on a ready list and GC threads take region off the list and fill them. A @@ -869,39 +749,18 @@ inline void ParMarkBitMapClosure::decrement_words_remaining(size_t words) { // Environments (VEE 2019). ACM, New York, NY, USA, 108-121. DOI: // https://doi.org/10.1145/3313808.3313820 -class TaskQueue; - class PSParallelCompact : AllStatic { public: // Convenient access to type names. typedef ParMarkBitMap::idx_t idx_t; typedef ParallelCompactData::RegionData RegionData; - typedef ParallelCompactData::BlockData BlockData; typedef enum { old_space_id, eden_space_id, from_space_id, to_space_id, last_space_id } SpaceId; - struct UpdateDensePrefixTask : public CHeapObj { - SpaceId _space_id; - size_t _region_index_start; - size_t _region_index_end; - - UpdateDensePrefixTask() : - _space_id(SpaceId(0)), - _region_index_start(0), - _region_index_end(0) {} - - UpdateDensePrefixTask(SpaceId space_id, - size_t region_index_start, - size_t region_index_end) : - _space_id(space_id), - _region_index_start(region_index_start), - _region_index_end(region_index_end) {} - }; - - public: +public: // Inline closure decls // class IsAliveClosure: public BoolObjectClosure { @@ -909,7 +768,6 @@ class PSParallelCompact : AllStatic { virtual bool do_object_b(oop p); }; - friend class RefProcTaskProxy; friend class PSParallelCompactTest; private: @@ -958,10 +816,11 @@ class PSParallelCompact : AllStatic { static void summary_phase(bool maximum_compaction); - // Adjust addresses in roots. Does not adjust addresses in heap. - static void adjust_roots(); + static void adjust_pointers(); + static void forward_to_new_addr(); - DEBUG_ONLY(static void write_block_fill_histogram();) + static void verify_forward() NOT_DEBUG_RETURN; + static void verify_filler_in_dense_prefix() NOT_DEBUG_RETURN; // Move objects to new locations. static void compact(); @@ -969,10 +828,6 @@ class PSParallelCompact : AllStatic { // Add available regions to the stack and draining tasks to the task queue. static void prepare_region_draining_tasks(uint parallel_gc_threads); - // Add dense prefix update tasks to the task queue. - static void enqueue_dense_prefix_tasks(TaskQueue& task_queue, - uint parallel_gc_threads); - #ifndef PRODUCT // Print generic summary data static void print_generic_summary_data(ParallelCompactData& summary_data, @@ -980,10 +835,23 @@ class PSParallelCompact : AllStatic { HeapWord* const end_addr); #endif // #ifndef PRODUCT + static void fill_range_in_dense_prefix(HeapWord* start, HeapWord* end); + public: + static void fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers); + static bool invoke(bool maximum_heap_compaction); static bool invoke_no_policy(bool maximum_heap_compaction); + template + static void adjust_in_space_helper(SpaceId id, volatile uint* claim_counter, Func&& on_stripe); + + static void adjust_in_old_space(volatile uint* claim_counter); + + static void adjust_in_young_space(SpaceId id, volatile uint* claim_counter); + + static void adjust_pointers_in_spaces(uint worker_id, volatile uint* claim_counter); + static void post_initialize(); // Perform initialization for PSParallelCompact that requires // allocations. This should be called during the VM initialization @@ -1003,7 +871,7 @@ class PSParallelCompact : AllStatic { static inline bool mark_obj(oop obj); static inline bool is_marked(oop obj); - template static inline void adjust_pointer(T* p, ParCompactionManager* cm); + template static inline void adjust_pointer(T* p); // Compaction support. // Return true if p is in the range [beg_addr, end_addr). @@ -1016,19 +884,6 @@ class PSParallelCompact : AllStatic { static inline HeapWord* dense_prefix(SpaceId space_id); static inline ObjectStartArray* start_array(SpaceId space_id); - // Update a region in the dense prefix. For each live object - // in the region, update it's interior references. For each - // dead object, fill it with deadwood. Dead space at the end - // of a region range will be filled to the start of the next - // live object regardless of the region_index_end. None of the - // objects in the dense prefix move and dead space is dead - // (holds only dead objects that don't need any processing), so - // dead space can be filled in any order. - static void update_and_deadwood_in_dense_prefix(ParCompactionManager* cm, - SpaceId space_id, - size_t region_index_start, - size_t region_index_end); - // Return the address of the count + 1st live word in the range [beg, end). static HeapWord* skip_live_words(HeapWord* beg, HeapWord* end, size_t count); @@ -1056,6 +911,8 @@ class PSParallelCompact : AllStatic { size_t beg_region, HeapWord* end_addr); + static HeapWord* partial_obj_end(HeapWord* region_start_addr); + static void fill_region(ParCompactionManager* cm, MoveAndUpdateClosure& closure, size_t region); static void fill_and_update_region(ParCompactionManager* cm, size_t region); @@ -1067,12 +924,6 @@ class PSParallelCompact : AllStatic { // _next_shadow_region filed for each compact manager static void initialize_shadow_regions(uint parallel_gc_threads); - // Fill in the block table for the specified region. - static void fill_blocks(size_t region_idx); - - // Update a single deferred object. - static void update_deferred_object(ParCompactionManager* cm, HeapWord* addr); - static ParMarkBitMap* mark_bitmap() { return &_mark_bitmap; } static ParallelCompactData& summary_data() { return _summary_data; } @@ -1120,14 +971,10 @@ class MoveAndUpdateClosure: public ParMarkBitMapClosure { // return would_overflow. IterationStatus do_addr(HeapWord* addr, size_t size); - // Copy enough words to fill this closure, starting at source(). Interior - // oops and the start array are not updated. Return full. - IterationStatus copy_until_full(); - // Copy enough words to fill this closure or to the end of an object, - // whichever is smaller, starting at source(). Interior oops and the start - // array are not updated. - void copy_partial_obj(); + // whichever is smaller, starting at source(). The start array is not + // updated. + void copy_partial_obj(size_t partial_obj_size); virtual void complete_region(ParCompactionManager* cm, HeapWord* dest_addr, PSParallelCompact::RegionData* region_ptr); @@ -1198,31 +1045,6 @@ MoveAndUpdateShadowClosure::MoveAndUpdateShadowClosure(ParMarkBitMap *bitmap, _offset = calculate_shadow_offset(region, shadow); } -class UpdateOnlyClosure: public ParMarkBitMapClosure { - private: - ObjectStartArray* const _start_array; - - public: - UpdateOnlyClosure(ParMarkBitMap* mbm, - ParCompactionManager* cm, - PSParallelCompact::SpaceId space_id); - - // Update the object. - virtual IterationStatus do_addr(HeapWord* addr, size_t words); - - inline void do_addr(HeapWord* addr); -}; - -class FillClosure: public ParMarkBitMapClosure { - public: - FillClosure(ParCompactionManager* cm, PSParallelCompact::SpaceId space_id); - - virtual IterationStatus do_addr(HeapWord* addr, size_t size); - - private: - ObjectStartArray* const _start_array; -}; - void steal_marking_work(TaskTerminator& terminator, uint worker_id); #endif // SHARE_GC_PARALLEL_PSPARALLELCOMPACT_HPP diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp index a4a5060ffd560..75a092e2dd1ec 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp @@ -78,8 +78,7 @@ inline void PSParallelCompact::check_new_location(HeapWord* old_addr, HeapWord* #endif // ASSERT inline bool PSParallelCompact::mark_obj(oop obj) { - const size_t obj_size = obj->size(); - if (mark_bitmap()->mark_obj(obj, obj_size)) { + if (mark_bitmap()->mark_obj(obj)) { ContinuationGCSupport::transform_stack_chunk(obj); return true; } else { @@ -88,34 +87,22 @@ inline bool PSParallelCompact::mark_obj(oop obj) { } template -inline void PSParallelCompact::adjust_pointer(T* p, ParCompactionManager* cm) { +inline void PSParallelCompact::adjust_pointer(T* p) { T heap_oop = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(heap_oop)) { oop obj = CompressedOops::decode_not_null(heap_oop); assert(ParallelScavengeHeap::heap()->is_in(obj), "should be in heap"); - oop new_obj = cast_to_oop(summary_data().calc_new_pointer(obj, cm)); - assert(new_obj != nullptr, "non-null address for live objects"); - // Is it actually relocated at all? - if (new_obj != obj) { - assert(ParallelScavengeHeap::heap()->is_in_reserved(new_obj), - "should be in object space"); - RawAccess::oop_store(p, new_obj); + if (!obj->is_forwarded()) { + return; } + oop new_obj = obj->forwardee(); + assert(new_obj != nullptr, "non-null address for live objects"); + assert(new_obj != obj, "inv"); + assert(ParallelScavengeHeap::heap()->is_in_reserved(new_obj), + "should be in object space"); + RawAccess::oop_store(p, new_obj); } } -class PCAdjustPointerClosure: public BasicOopIterateClosure { -public: - PCAdjustPointerClosure(ParCompactionManager* cm) : _cm(cm) { - } - template void do_oop_work(T* p) { PSParallelCompact::adjust_pointer(p, _cm); } - virtual void do_oop(oop* p) { do_oop_work(p); } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - - virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } -private: - ParCompactionManager* _cm; -}; - #endif // SHARE_GC_PARALLEL_PSPARALLELCOMPACT_INLINE_HPP diff --git a/src/hotspot/share/gc/serial/serialBlockOffsetTable.inline.hpp b/src/hotspot/share/gc/serial/serialBlockOffsetTable.inline.hpp index fe003774eae1e..d8224cb774e6e 100644 --- a/src/hotspot/share/gc/serial/serialBlockOffsetTable.inline.hpp +++ b/src/hotspot/share/gc/serial/serialBlockOffsetTable.inline.hpp @@ -35,7 +35,8 @@ inline uint8_t* SerialBlockOffsetTable::entry_for_addr(const void* const p) cons } inline HeapWord* SerialBlockOffsetTable::addr_for_entry(const uint8_t* const p) const { - size_t delta = pointer_delta(p, _offset_base, sizeof(uint8_t)); + // _offset_base can be "negative", so can't use pointer_delta(). + size_t delta = p - _offset_base; HeapWord* result = (HeapWord*) (delta << CardTable::card_shift()); assert(_reserved.contains(result), "out of bounds accessor from block offset array"); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index eaea7ba42709d..9602553a6f37b 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -343,37 +343,6 @@ void TenuredGeneration::gc_prologue() { _used_at_prologue = used(); } -bool TenuredGeneration::should_collect(bool full, - size_t size, - bool is_tlab) { - // This should be one big conditional or (||), but I want to be able to tell - // why it returns what it returns (without re-evaluating the conditionals - // in case they aren't idempotent), so I'm doing it this way. - // DeMorgan says it's okay. - if (full) { - log_trace(gc)("TenuredGeneration::should_collect: because full"); - return true; - } - if (should_allocate(size, is_tlab)) { - log_trace(gc)("TenuredGeneration::should_collect: because should_allocate(" SIZE_FORMAT ")", size); - return true; - } - // If we don't have very much free space. - // XXX: 10000 should be a percentage of the capacity!!! - if (free() < 10000) { - log_trace(gc)("TenuredGeneration::should_collect: because free(): " SIZE_FORMAT, free()); - return true; - } - // If we had to expand to accommodate promotions from the young generation - if (_capacity_at_prologue < capacity()) { - log_trace(gc)("TenuredGeneration::should_collect: because_capacity_at_prologue: " SIZE_FORMAT " < capacity(): " SIZE_FORMAT, - _capacity_at_prologue, capacity()); - return true; - } - - return false; -} - void TenuredGeneration::compute_new_size() { assert_locked_or_safepoint(Heap_lock); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index f30cfed2671bc..cfc18b92f2a7c 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -140,10 +140,6 @@ class TenuredGeneration: public Generation { void gc_prologue(); void gc_epilogue(); - bool should_collect(bool full, - size_t word_size, - bool is_tlab); - bool should_allocate(size_t word_size, bool is_tlab) { bool result = false; size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize); diff --git a/src/hotspot/share/gc/shared/gcVMOperations.cpp b/src/hotspot/share/gc/shared/gcVMOperations.cpp index d4a6360557835..4cf1a4ccbafd0 100644 --- a/src/hotspot/share/gc/shared/gcVMOperations.cpp +++ b/src/hotspot/share/gc/shared/gcVMOperations.cpp @@ -130,9 +130,9 @@ bool VM_GC_Operation::doit_prologue() { void VM_GC_Operation::doit_epilogue() { - // Clean up old interpreter OopMap entries that were replaced - // during the GC thread root traversal. - OopMapCache::cleanup_old_entries(); + // GC thread root traversal likely used OopMapCache a lot, which + // might have created lots of old entries. Trigger the cleanup now. + OopMapCache::trigger_cleanup(); if (Universe::has_reference_pending_list()) { Heap_lock->notify_all(); } diff --git a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp index 1131945dc8cce..30bf1f7a39507 100644 --- a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp +++ b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp @@ -58,26 +58,32 @@ ShenandoahBarrierSetC1::ShenandoahBarrierSetC1() : void ShenandoahBarrierSetC1::pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val) { // First we test whether marking is in progress. - BasicType flag_type; + bool patch = (decorators & C1_NEEDS_PATCHING) != 0; bool do_load = pre_val == LIR_OprFact::illegalOpr; - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - flag_type = T_INT; - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, - "Assumption"); - // Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM, - // need to use unsigned instructions to use the large offset to load the satb_mark_queue. - flag_type = T_BOOLEAN; - } + LIR_Opr thrd = gen->getThreadPointer(); - LIR_Address* mark_active_flag_addr = - new LIR_Address(thrd, - in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()), - flag_type); - // Read the marking-in-progress flag. + LIR_Address* gc_state_addr = + new LIR_Address(thrd, + in_bytes(ShenandoahThreadLocalData::gc_state_offset()), + T_BYTE); + // Read the gc_state flag. LIR_Opr flag_val = gen->new_register(T_INT); - __ load(mark_active_flag_addr, flag_val); + __ load(gc_state_addr, flag_val); + + // Create a mask to test if the marking bit is set. + // TODO: can we directly test if bit is set? + LIR_Opr mask = LIR_OprFact::intConst(ShenandoahHeap::MARKING); + LIR_Opr mask_reg = gen->new_register(T_INT); + __ move(mask, mask_reg); + + if (two_operand_lir_form) { + __ logical_and(flag_val, mask_reg, flag_val); + } else { + LIR_Opr masked_flag = gen->new_register(T_INT); + __ logical_and(flag_val, mask_reg, masked_flag); + flag_val = masked_flag; + } __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0)); LIR_PatchCode pre_val_patch_code = lir_patch_none; diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index f34b1cae8fb04..7d1f5cc16a845 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -980,7 +980,7 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p ShenandoahBarrierC2Support::verify(Compile::current()->root()); } else if (phase == BarrierSetC2::BeforeCodeGen) { // Verify Shenandoah pre-barriers - const int marking_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()); + const int gc_state_offset = in_bytes(ShenandoahThreadLocalData::gc_state_offset()); Unique_Node_List visited; Node_List worklist; @@ -988,7 +988,10 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p worklist.push(compile->root()); while (worklist.size() > 0) { Node *x = worklist.pop(); - if (x == nullptr || x == compile->top()) continue; + if (x == nullptr || x == compile->top()) { + continue; + } + if (visited.member(x)) { continue; } else { @@ -1016,7 +1019,7 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p LoadNode *load = cmp->in(1)->as_Load(); if (load->Opcode() == Op_LoadB && load->in(2)->is_AddP() && load->in(2)->in(2)->Opcode() == Op_ThreadLocal && load->in(2)->in(3)->is_Con() - && load->in(2)->in(3)->bottom_type()->is_intptr_t()->get_con() == marking_offset) { + && load->in(2)->in(3)->bottom_type()->is_intptr_t()->get_con() == gc_state_offset) { Node *if_ctrl = iff->in(0); Node *load_ctrl = load->in(0); diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 14fb038a6c6a8..dbb45995698a6 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -463,6 +463,12 @@ void ShenandoahBarrierC2Support::verify(RootNode* root) { "decodeBlock", { { TypeFunc::Parms, ShenandoahLoad }, { TypeFunc::Parms+3, ShenandoahStore }, { -1, ShenandoahNone }, { -1, ShenandoahNone}, { -1, ShenandoahNone}, { -1, ShenandoahNone} }, + "intpoly_montgomeryMult_P256", + { { TypeFunc::Parms, ShenandoahLoad }, { TypeFunc::Parms+1, ShenandoahLoad }, { TypeFunc::Parms+2, ShenandoahStore }, + { -1, ShenandoahNone}, { -1, ShenandoahNone}, { -1, ShenandoahNone} }, + "intpoly_assign", + { { TypeFunc::Parms+1, ShenandoahStore }, { TypeFunc::Parms+2, ShenandoahLoad }, { -1, ShenandoahNone }, + { -1, ShenandoahNone}, { -1, ShenandoahNone}, { -1, ShenandoahNone} }, }; if (call->is_call_to_arraycopystub()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp index 9eec573cc567b..91f1cfe7f562a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp @@ -158,10 +158,6 @@ class ShenandoahThreadLocalData { } // Offsets - static ByteSize satb_mark_queue_active_offset() { - return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active(); - } - static ByteSize satb_mark_queue_index_offset() { return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index eeeb1dcad195a..af221550c69ab 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -42,6 +42,9 @@ bool VM_ShenandoahOperation::doit_prologue() { void VM_ShenandoahOperation::doit_epilogue() { assert(!ShenandoahHeap::heap()->has_gc_state_changed(), "GC State was not synchronized to java threads."); + // GC thread root traversal likely used OopMapCache a lot, which + // might have created lots of old entries. Trigger the cleanup now. + OopMapCache::trigger_cleanup(); } bool VM_ShenandoahReferenceOperation::doit_prologue() { @@ -52,7 +55,6 @@ bool VM_ShenandoahReferenceOperation::doit_prologue() { void VM_ShenandoahReferenceOperation::doit_epilogue() { VM_ShenandoahOperation::doit_epilogue(); - OopMapCache::cleanup_old_entries(); if (Universe::has_reference_pending_list()) { Heap_lock->notify_all(); } diff --git a/src/hotspot/share/gc/x/xDriver.cpp b/src/hotspot/share/gc/x/xDriver.cpp index b78e155d3a726..c477f4a135c32 100644 --- a/src/hotspot/share/gc/x/xDriver.cpp +++ b/src/hotspot/share/gc/x/xDriver.cpp @@ -35,6 +35,7 @@ #include "gc/x/xServiceability.hpp" #include "gc/x/xStat.hpp" #include "gc/x/xVerify.hpp" +#include "interpreter/oopMapCache.hpp" #include "logging/log.hpp" #include "memory/universe.hpp" #include "runtime/threads.hpp" @@ -130,6 +131,10 @@ class VM_XOperation : public VM_Operation { virtual void doit_epilogue() { Heap_lock->unlock(); + + // GC thread root traversal likely used OopMapCache a lot, which + // might have created lots of old entries. Trigger the cleanup now. + OopMapCache::trigger_cleanup(); } bool gc_locked() const { diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 049edc802cc98..5c3afa9db8cc6 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -52,6 +52,7 @@ #include "gc/z/zUncoloredRoot.inline.hpp" #include "gc/z/zVerify.hpp" #include "gc/z/zWorkers.hpp" +#include "interpreter/oopMapCache.hpp" #include "logging/log.hpp" #include "memory/universe.hpp" #include "prims/jvmtiTagMap.hpp" @@ -452,6 +453,10 @@ class VM_ZOperation : public VM_Operation { virtual void doit_epilogue() { Heap_lock->unlock(); + + // GC thread root traversal likely used OopMapCache a lot, which + // might have created lots of old entries. Trigger the cleanup now. + OopMapCache::trigger_cleanup(); } bool success() const { diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 7d12797007b69..dc5f2f5b6371f 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -223,20 +223,6 @@ JRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* current, ConstantPool* pool // Make sure klass is initialized klass->initialize(CHECK); - // At this point the class may not be fully initialized - // because of recursive initialization. If it is fully - // initialized & has_finalized is not set, we rewrite - // it into its fast version (Note: no locking is needed - // here since this is an atomic byte write and can be - // done more than once). - // - // Note: In case of classes with has_finalized we don't - // rewrite since that saves us an extra check in - // the fast version which then would call the - // slow version anyway (and do a call back into - // Java). - // If we have a breakpoint, then we don't rewrite - // because the _breakpoint bytecode would be lost. oop obj = klass->allocate_instance(CHECK); current->set_vm_result(obj); JRT_END diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index 3c2f1dd3e35b1..cae0efae9b26d 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -35,6 +35,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/signature.hpp" +#include "utilities/globalCounter.inline.hpp" class OopMapCacheEntry: private InterpreterOopMap { friend class InterpreterOopMap; @@ -494,15 +495,11 @@ void OopMapCache::flush_obsolete_entries() { } } -// Called by GC for thread root scan during a safepoint only. The other interpreted frame oopmaps -// are generated locally and not cached. +// Lookup or compute/cache the entry. void OopMapCache::lookup(const methodHandle& method, int bci, InterpreterOopMap* entry_for) { - assert(SafepointSynchronize::is_at_safepoint(), "called by GC in a safepoint"); int probe = hash_value_for(method, bci); - int i; - OopMapCacheEntry* entry = nullptr; if (log_is_enabled(Debug, interpreter, oopmap)) { static int count = 0; @@ -512,14 +509,18 @@ void OopMapCache::lookup(const methodHandle& method, method()->name_and_sig_as_C_string(), probe); } - // Search hashtable for match - for(i = 0; i < _probe_depth; i++) { - entry = entry_at(probe + i); - if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) { - entry_for->resource_copy(entry); - assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); - log_debug(interpreter, oopmap)("- found at hash %d", probe + i); - return; + // Search hashtable for match. + // Need a critical section to avoid race against concurrent reclamation. + { + GlobalCounter::CriticalSection cs(Thread::current()); + for (int i = 0; i < _probe_depth; i++) { + OopMapCacheEntry *entry = entry_at(probe + i); + if (entry != nullptr && !entry->is_empty() && entry->match(method, bci)) { + entry_for->resource_copy(entry); + assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); + log_debug(interpreter, oopmap)("- found at hash %d", probe + i); + return; + } } } @@ -541,8 +542,8 @@ void OopMapCache::lookup(const methodHandle& method, } // First search for an empty slot - for(i = 0; i < _probe_depth; i++) { - entry = entry_at(probe + i); + for (int i = 0; i < _probe_depth; i++) { + OopMapCacheEntry* entry = entry_at(probe + i); if (entry == nullptr) { if (put_at(probe + i, tmp, nullptr)) { assert(!entry_for->is_empty(), "A non-empty oop map should be returned"); @@ -557,6 +558,10 @@ void OopMapCache::lookup(const methodHandle& method, // where the first entry in the collision array is replaced with the new one. OopMapCacheEntry* old = entry_at(probe + 0); if (put_at(probe + 0, tmp, old)) { + // Cannot deallocate old entry on the spot: it can still be used by readers + // that got a reference to it before we were able to replace it in the map. + // Instead of synchronizing on GlobalCounter here and incurring heavy thread + // walk, we do this clean up out of band. enqueue_for_cleanup(old); } else { OopMapCacheEntry::deallocate(tmp); @@ -567,13 +572,14 @@ void OopMapCache::lookup(const methodHandle& method, } void OopMapCache::enqueue_for_cleanup(OopMapCacheEntry* entry) { - bool success = false; - OopMapCacheEntry* head; - do { - head = _old_entries; + while (true) { + OopMapCacheEntry* head = Atomic::load(&_old_entries); entry->_next = head; - success = Atomic::cmpxchg(&_old_entries, head, entry) == head; - } while (!success); + if (Atomic::cmpxchg(&_old_entries, head, entry) == head) { + // Enqueued successfully. + break; + } + } if (log_is_enabled(Debug, interpreter, oopmap)) { ResourceMark rm; @@ -582,11 +588,28 @@ void OopMapCache::enqueue_for_cleanup(OopMapCacheEntry* entry) { } } -// This is called after GC threads are done and nothing is accessing the old_entries -// list, so no synchronization needed. -void OopMapCache::cleanup_old_entries() { - OopMapCacheEntry* entry = _old_entries; - _old_entries = nullptr; +bool OopMapCache::has_cleanup_work() { + return Atomic::load(&_old_entries) != nullptr; +} + +void OopMapCache::trigger_cleanup() { + if (has_cleanup_work()) { + MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); + Service_lock->notify_all(); + } +} + +void OopMapCache::cleanup() { + OopMapCacheEntry* entry = Atomic::xchg(&_old_entries, (OopMapCacheEntry*)nullptr); + if (entry == nullptr) { + // No work. + return; + } + + // About to delete the entries than might still be accessed by other threads + // on lookup path. Need to sync up with them before proceeding. + GlobalCounter::write_synchronize(); + while (entry != nullptr) { if (log_is_enabled(Debug, interpreter, oopmap)) { ResourceMark rm; diff --git a/src/hotspot/share/interpreter/oopMapCache.hpp b/src/hotspot/share/interpreter/oopMapCache.hpp index 7378a987cc69b..3c124631377ef 100644 --- a/src/hotspot/share/interpreter/oopMapCache.hpp +++ b/src/hotspot/share/interpreter/oopMapCache.hpp @@ -179,7 +179,15 @@ class OopMapCache : public CHeapObj { // Compute an oop map without updating the cache or grabbing any locks (for debugging) static void compute_one_oop_map(const methodHandle& method, int bci, InterpreterOopMap* entry); - static void cleanup_old_entries(); + + // Check if we need to clean up old entries + static bool has_cleanup_work(); + + // Request cleanup if work is needed + static void trigger_cleanup(); + + // Clean up the old entries + static void cleanup(); }; #endif // SHARE_INTERPRETER_OOPMAPCACHE_HPP diff --git a/src/hotspot/share/jfr/support/jfrIntrinsics.cpp b/src/hotspot/share/jfr/support/jfrIntrinsics.cpp index 4b7c6c8aee9ce..63d0e686021f2 100644 --- a/src/hotspot/share/jfr/support/jfrIntrinsics.cpp +++ b/src/hotspot/share/jfr/support/jfrIntrinsics.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -74,6 +74,7 @@ void* JfrIntrinsicSupport::write_checkpoint(JavaThread* jt) { void* JfrIntrinsicSupport::return_lease(JavaThread* jt) { DEBUG_ONLY(assert_precondition(jt);) + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, jt)); ThreadStateTransition::transition_from_java(jt, _thread_in_native); assert(jt->jfr_thread_local()->has_java_event_writer(), "invariant"); assert(jt->jfr_thread_local()->shelved_buffer() != nullptr, "invariant"); diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 3d942d8322515..624b25b9e2c7b 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -514,6 +514,7 @@ class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation { } void decode(JavaThread* THREAD, DecodeFormat format, jlong buffer) { + JVMCI_event_1("decoding exception from JVM heap (format: %d, buffer[%d]) ", format, buffer == 0L ? -1 : *((u4*) buffer)); JNIAccessMark jni(_to_env, THREAD); jni()->CallStaticVoidMethod(JNIJVMCI::VMSupport::clazz(), JNIJVMCI::VMSupport::decodeAndThrowThrowable_method(), @@ -545,6 +546,7 @@ class SharedLibraryToHotSpotExceptionTranslation : public ExceptionTranslation { } void decode(JavaThread* THREAD, DecodeFormat format, jlong buffer) { + JVMCI_event_1("decoding exception to JVM heap (format: %d, buffer[%d]) ", format, buffer == 0L ? -1 : *((u4*) buffer)); Klass* vmSupport = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_vm_VMSupport(), true, CHECK); JavaCallArguments jargs; jargs.push_int(format); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 035c1dd1ce9ed..c72ca3870b5ab 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -361,6 +361,8 @@ static_field(StubRoutines, _md5_implCompressMB, address) \ static_field(StubRoutines, _chacha20Block, address) \ static_field(StubRoutines, _poly1305_processBlocks, address) \ + static_field(StubRoutines, _intpoly_montgomeryMult_P256, address) \ + static_field(StubRoutines, _intpoly_assign, address) \ static_field(StubRoutines, _sha1_implCompress, address) \ static_field(StubRoutines, _sha1_implCompressMB, address) \ static_field(StubRoutines, _sha256_implCompress, address) \ diff --git a/src/hotspot/share/nmt/mallocTracker.hpp b/src/hotspot/share/nmt/mallocTracker.hpp index 5d755f60ae600..9c14ea04bf0f2 100644 --- a/src/hotspot/share/nmt/mallocTracker.hpp +++ b/src/hotspot/share/nmt/mallocTracker.hpp @@ -179,6 +179,16 @@ class MallocMemorySnapshot { return _all_mallocs.size() + malloc_overhead() + total_arena(); } + // Total peak malloc + size_t total_peak() const { + return _all_mallocs.peak_size(); + } + + // Total peak count + size_t total_peak_count() const { + return _all_mallocs.peak_count(); + } + // Total malloc'd memory used by arenas size_t total_arena() const; diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index b880e56a85328..96ad3c5cb1aa9 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -165,9 +165,11 @@ void MemSummaryReporter::report() { out->print("Total: "); print_total(total_reserved_amount, total_committed_amount); out->cr(); - out->print_cr(" malloc: " SIZE_FORMAT "%s #" SIZE_FORMAT, + out->print_cr(" malloc: " SIZE_FORMAT "%s #" SIZE_FORMAT ", peak=" SIZE_FORMAT "%s #" SIZE_FORMAT, amount_in_current_scale(total_malloced_bytes), current_scale(), - _malloc_snapshot->total_count()); + _malloc_snapshot->total_count(), + amount_in_current_scale(_malloc_snapshot->total_peak()), + current_scale(), _malloc_snapshot->total_peak_count()); out->print(" mmap: "); print_total(total_mmap_reserved_bytes, total_mmap_committed_bytes); out->cr(); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 3b3a4ac10a662..dcc3836039958 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -3547,11 +3547,13 @@ void InstanceKlass::print_on(outputStream* st) const { } } st->print(BULLET"method ordering: "); method_ordering()->print_value_on(st); st->cr(); - st->print(BULLET"default_methods: "); default_methods()->print_value_on(st); st->cr(); - if (Verbose && default_methods() != nullptr) { - Array* method_array = default_methods(); - for (int i = 0; i < method_array->length(); i++) { - st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); + if (default_methods() != nullptr) { + st->print(BULLET"default_methods: "); default_methods()->print_value_on(st); st->cr(); + if (Verbose) { + Array* method_array = default_methods(); + for (int i = 0; i < method_array->length(); i++) { + st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); + } } } if (default_vtable_indices() != nullptr) { diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 929c8b87d39d5..4be0cf78bdcc8 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -310,16 +310,13 @@ int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_kla void Method::mask_for(int bci, InterpreterOopMap* mask) { methodHandle h_this(Thread::current(), this); - // Only GC uses the OopMapCache during thread stack root scanning - // any other uses generate an oopmap but do not save it in the cache. - if (Universe::heap()->is_stw_gc_active()) { - method_holder()->mask_for(h_this, bci, mask); - } else { - OopMapCache::compute_one_oop_map(h_this, bci, mask); - } - return; + mask_for(h_this, bci, mask); } +void Method::mask_for(const methodHandle& this_mh, int bci, InterpreterOopMap* mask) { + assert(this_mh() == this, "Sanity"); + method_holder()->mask_for(this_mh, bci, mask); +} int Method::bci_from(address bcp) const { if (is_native() && bcp == 0) { diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 319a8ff155780..905c53a4ea38b 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -446,8 +446,10 @@ class Method : public Metadata { address signature_handler() const { return *(signature_handler_addr()); } void set_signature_handler(address handler); - // Interpreter oopmap support + // Interpreter oopmap support. + // If handle is already available, call with it for better performance. void mask_for(int bci, InterpreterOopMap* mask); + void mask_for(const methodHandle& this_mh, int bci, InterpreterOopMap* mask); // operations on invocation counter void print_invocation_count(outputStream* st); diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index dc15e82dff8f1..c5e174784773f 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -786,6 +786,8 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_base64_encodeBlock: case vmIntrinsics::_base64_decodeBlock: case vmIntrinsics::_poly1305_processBlocks: + case vmIntrinsics::_intpoly_montgomeryMult_P256: + case vmIntrinsics::_intpoly_assign: case vmIntrinsics::_updateCRC32: case vmIntrinsics::_updateBytesCRC32: case vmIntrinsics::_updateByteBufferCRC32: diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 1771107c85189..a93c9b382f923 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -213,7 +213,13 @@ const Type* CastIINode::Value(PhaseGVN* phase) const { // Similar to ConvI2LNode::Value() for the same reasons // see if we can remove type assertion after loop opts - res = widen_type(phase, res, T_INT); + // But here we have to pay extra attention: + // Do not narrow the type of range check dependent CastIINodes to + // avoid corruption of the graph if a CastII is replaced by TOP but + // the corresponding range check is not removed. + if (!_range_check_dependency) { + res = widen_type(phase, res, T_INT); + } return res; } @@ -233,11 +239,11 @@ Node *CastIINode::Ideal(PhaseGVN *phase, bool can_reshape) { if (progress != nullptr) { return progress; } - if (can_reshape && !phase->C->post_loop_opts_phase()) { + if (can_reshape && !_range_check_dependency && !phase->C->post_loop_opts_phase()) { // makes sure we run ::Value to potentially remove type assertion after loop opts phase->C->record_for_post_loop_opts_igvn(this); } - if (!_type->is_int()->empty()) { + if (!_range_check_dependency) { return optimize_integer_cast(phase, T_INT); } return nullptr; @@ -248,6 +254,13 @@ Node* CastIINode::Identity(PhaseGVN* phase) { if (progress != this) { return progress; } + if (_range_check_dependency) { + if (phase->C->post_loop_opts_phase()) { + return this->in(1); + } else { + phase->C->record_for_post_loop_opts_igvn(this); + } + } return this; } diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 445f22c6b8038..25c7ced8aebfe 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3464,10 +3464,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f } break; } - case Op_CastII: { - remove_range_check_cast(n->as_CastII()); - } - break; #ifdef _LP64 case Op_CmpP: // Do this transformation here to preserve CmpPNode::sub() and @@ -3619,6 +3615,16 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f #endif +#ifdef ASSERT + case Op_CastII: + // Verify that all range check dependent CastII nodes were removed. + if (n->isa_CastII()->has_range_check()) { + n->dump(3); + assert(false, "Range check dependent CastII node was not removed"); + } + break; +#endif + case Op_ModI: if (UseDivMod) { // Check if a%b and a/b both exist @@ -3627,8 +3633,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f // Replace them with a fused divmod if supported if (Matcher::has_match_rule(Op_DivModI)) { DivModINode* divmod = DivModINode::make(n); - divmod->add_prec_from(n); - divmod->add_prec_from(d); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3649,8 +3653,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f // Replace them with a fused divmod if supported if (Matcher::has_match_rule(Op_DivModL)) { DivModLNode* divmod = DivModLNode::make(n); - divmod->add_prec_from(n); - divmod->add_prec_from(d); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3671,8 +3673,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f // Replace them with a fused unsigned divmod if supported if (Matcher::has_match_rule(Op_UDivModI)) { UDivModINode* divmod = UDivModINode::make(n); - divmod->add_prec_from(n); - divmod->add_prec_from(d); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3693,8 +3693,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f // Replace them with a fused unsigned divmod if supported if (Matcher::has_match_rule(Op_UDivModL)) { UDivModLNode* divmod = UDivModLNode::make(n); - divmod->add_prec_from(n); - divmod->add_prec_from(d); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3896,34 +3894,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f } } -void Compile::remove_range_check_cast(CastIINode* cast) { - if (cast->has_range_check()) { - // Range check CastII nodes feed into an address computation subgraph. Remove them to let that subgraph float freely. - // For memory access or integer divisions nodes that depend on the cast, record the dependency on the cast's control - // as a precedence edge, so they can't float above the cast in case that cast's narrowed type helped eliminate a - // range check or a null divisor check. - assert(cast->in(0) != nullptr, "All RangeCheck CastII must have a control dependency"); - ResourceMark rm; - Unique_Node_List wq; - wq.push(cast); - for (uint next = 0; next < wq.size(); ++next) { - Node* m = wq.at(next); - for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { - Node* use = m->fast_out(i); - if (use->is_Mem() || use->is_div_or_mod(T_INT) || use->is_div_or_mod(T_LONG)) { - use->ensure_control_or_add_prec(cast->in(0)); - } else if (!use->is_CFG() && !use->is_Phi()) { - wq.push(use); - } - } - } - cast->subsume_by(cast->in(1), this); - if (cast->outcnt() == 0) { - cast->disconnect_inputs(this); - } - } -} - //------------------------------final_graph_reshaping_walk--------------------- // Replacing Opaque nodes with their input in final_graph_reshaping_impl(), // requires that the walk visits a node's inputs before visiting the node. diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 9a873b8b9cb8b..e1d9b61f7f8d1 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -53,7 +53,6 @@ class Block; class Bundle; class CallGenerator; class CallStaticJavaNode; -class CastIINode; class CloneMap; class CompilationFailureInfo; class ConnectionGraph; @@ -1315,8 +1314,6 @@ class Compile : public Phase { BasicType out_bt, BasicType in_bt); static Node* narrow_value(BasicType bt, Node* value, const Type* type, PhaseGVN* phase, bool transform_res); - - void remove_range_check_cast(CastIINode* cast); }; #endif // SHARE_OPTO_COMPILE_HPP diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 1a9e74dab3df2..b011c9928b6f1 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -2173,6 +2173,8 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "counterMode_AESCrypt") == 0 || strcmp(call->as_CallLeaf()->_name, "galoisCounterMode_AESCrypt") == 0 || strcmp(call->as_CallLeaf()->_name, "poly1305_processBlocks") == 0 || + strcmp(call->as_CallLeaf()->_name, "intpoly_montgomeryMult_P256") == 0 || + strcmp(call->as_CallLeaf()->_name, "intpoly_assign") == 0 || strcmp(call->as_CallLeaf()->_name, "ghash_processBlocks") == 0 || strcmp(call->as_CallLeaf()->_name, "chacha20Block") == 0 || strcmp(call->as_CallLeaf()->_name, "encodeBlock") == 0 || diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index b018fcf509713..96e88c1a96bad 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -638,7 +638,10 @@ bool LibraryCallKit::try_to_inline(int predicate) { return inline_base64_decodeBlock(); case vmIntrinsics::_poly1305_processBlocks: return inline_poly1305_processBlocks(); - + case vmIntrinsics::_intpoly_montgomeryMult_P256: + return inline_intpoly_montgomeryMult_P256(); + case vmIntrinsics::_intpoly_assign: + return inline_intpoly_assign(); case vmIntrinsics::_encodeISOArray: case vmIntrinsics::_encodeByteISOArray: return inline_encodeISOArray(false); @@ -7568,6 +7571,69 @@ bool LibraryCallKit::inline_poly1305_processBlocks() { return true; } +bool LibraryCallKit::inline_intpoly_montgomeryMult_P256() { + address stubAddr; + const char *stubName; + assert(UseIntPolyIntrinsics, "need intpoly intrinsics support"); + assert(callee()->signature()->size() == 3, "intpoly_montgomeryMult_P256 has %d parameters", callee()->signature()->size()); + stubAddr = StubRoutines::intpoly_montgomeryMult_P256(); + stubName = "intpoly_montgomeryMult_P256"; + + if (!stubAddr) return false; + null_check_receiver(); // null-check receiver + if (stopped()) return true; + + Node* a = argument(1); + Node* b = argument(2); + Node* r = argument(3); + + a = must_be_not_null(a, true); + b = must_be_not_null(b, true); + r = must_be_not_null(r, true); + + Node* a_start = array_element_address(a, intcon(0), T_LONG); + assert(a_start, "a array is NULL"); + Node* b_start = array_element_address(b, intcon(0), T_LONG); + assert(b_start, "b array is NULL"); + Node* r_start = array_element_address(r, intcon(0), T_LONG); + assert(r_start, "r array is NULL"); + + Node* call = make_runtime_call(RC_LEAF | RC_NO_FP, + OptoRuntime::intpoly_montgomeryMult_P256_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + a_start, b_start, r_start); + Node* result = _gvn.transform(new ProjNode(call, TypeFunc::Parms)); + set_result(result); + return true; +} + +bool LibraryCallKit::inline_intpoly_assign() { + assert(UseIntPolyIntrinsics, "need intpoly intrinsics support"); + assert(callee()->signature()->size() == 3, "intpoly_assign has %d parameters", callee()->signature()->size()); + const char *stubName = "intpoly_assign"; + address stubAddr = StubRoutines::intpoly_assign(); + if (!stubAddr) return false; + + Node* set = argument(0); + Node* a = argument(1); + Node* b = argument(2); + Node* arr_length = load_array_length(a); + + a = must_be_not_null(a, true); + b = must_be_not_null(b, true); + + Node* a_start = array_element_address(a, intcon(0), T_LONG); + assert(a_start, "a array is NULL"); + Node* b_start = array_element_address(b, intcon(0), T_LONG); + assert(b_start, "b array is NULL"); + + Node* call = make_runtime_call(RC_LEAF | RC_NO_FP, + OptoRuntime::intpoly_assign_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + set, a_start, b_start, arr_length); + return true; +} + //------------------------------inline_digestBase_implCompress----------------------- // // Calculate MD5 for single-block byte[] array. diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index cb4f34a0db6b9..1111c795114c0 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -307,6 +307,8 @@ class LibraryCallKit : public GraphKit { bool inline_base64_encodeBlock(); bool inline_base64_decodeBlock(); bool inline_poly1305_processBlocks(); + bool inline_intpoly_montgomeryMult_P256(); + bool inline_intpoly_assign(); bool inline_digestBase_implCompress(vmIntrinsics::ID id); bool inline_digestBase_implCompressMB(int predicate); bool inline_digestBase_implCompressMB(Node* digestBaseObj, ciInstanceKlass* instklass, diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 38b82e6af93b7..2a26a4ebed383 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1312,8 +1312,7 @@ void PhaseMacroExpand::expand_allocate_common( slow_region = new RegionNode(3); // Now make the initial failure test. Usually a too-big test but - // might be a TRUE for finalizers or a fancy class check for - // newInstance0. + // might be a TRUE for finalizers. IfNode *toobig_iff = new IfNode(ctrl, initial_slow_test, PROB_MIN, COUNT_UNKNOWN); transform_later(toobig_iff); // Plug the failing-too-big test into the slow-path region diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index fa26825e19f50..a436703b0507f 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -3516,7 +3516,10 @@ Node* StoreNode::Identity(PhaseGVN* phase) { val->in(MemNode::Address)->eqv_uncast(adr) && val->in(MemNode::Memory )->eqv_uncast(mem) && val->as_Load()->store_Opcode() == Opcode()) { - result = mem; + // Ensure vector type is the same + if (!is_StoreVector() || as_StoreVector()->vect_type() == mem->as_LoadVector()->vect_type()) { + result = mem; + } } // Two stores in a row of the same value? @@ -3525,7 +3528,24 @@ Node* StoreNode::Identity(PhaseGVN* phase) { mem->in(MemNode::Address)->eqv_uncast(adr) && mem->in(MemNode::ValueIn)->eqv_uncast(val) && mem->Opcode() == Opcode()) { - result = mem; + if (!is_StoreVector()) { + result = mem; + } else { + const StoreVectorNode* store_vector = as_StoreVector(); + const StoreVectorNode* mem_vector = mem->as_StoreVector(); + const Node* store_indices = store_vector->indices(); + const Node* mem_indices = mem_vector->indices(); + const Node* store_mask = store_vector->mask(); + const Node* mem_mask = mem_vector->mask(); + // Ensure types, indices, and masks match + if (store_vector->vect_type() == mem_vector->vect_type() && + ((store_indices == nullptr) == (mem_indices == nullptr) && + (store_indices == nullptr || store_indices->eqv_uncast(mem_indices))) && + ((store_mask == nullptr) == (mem_mask == nullptr) && + (store_mask == nullptr || store_mask->eqv_uncast(mem_mask)))) { + result = mem; + } + } } // Store of zero anywhere into a freshly-allocated object? diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index cadea46e2c9cf..fa85344d0da24 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -2878,15 +2878,6 @@ void Node::ensure_control_or_add_prec(Node* c) { } } -void Node::add_prec_from(Node* n) { - for (uint i = n->req(); i < n->len(); i++) { - Node* prec = n->in(i); - if (prec != nullptr) { - add_prec(prec); - } - } -} - bool Node::is_dead_loop_safe() const { if (is_Phi()) { return true; @@ -2910,9 +2901,6 @@ bool Node::is_dead_loop_safe() const { return false; } -bool Node::is_div_or_mod(BasicType bt) const { return Opcode() == Op_Div(bt) || Opcode() == Op_Mod(bt) || - Opcode() == Op_UDiv(bt) || Opcode() == Op_UMod(bt); } - //============================================================================= //------------------------------yank------------------------------------------- // Find and remove diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 412e193a612b8..314f165ac8b0a 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -180,8 +180,10 @@ class LoadVectorNode; class LoadVectorMaskedNode; class StoreVectorMaskedNode; class LoadVectorGatherNode; +class LoadVectorGatherMaskedNode; class StoreVectorNode; class StoreVectorScatterNode; +class StoreVectorScatterMaskedNode; class VerifyVectorAlignmentNode; class VectorMaskCmpNode; class VectorUnboxNode; @@ -996,8 +998,12 @@ class Node { DEFINE_CLASS_QUERY(CompressM) DEFINE_CLASS_QUERY(LoadVector) DEFINE_CLASS_QUERY(LoadVectorGather) + DEFINE_CLASS_QUERY(LoadVectorMasked) + DEFINE_CLASS_QUERY(LoadVectorGatherMasked) DEFINE_CLASS_QUERY(StoreVector) DEFINE_CLASS_QUERY(StoreVectorScatter) + DEFINE_CLASS_QUERY(StoreVectorMasked) + DEFINE_CLASS_QUERY(StoreVectorScatterMasked) DEFINE_CLASS_QUERY(ShiftV) DEFINE_CLASS_QUERY(Unlock) @@ -1143,7 +1149,6 @@ class Node { // Set control or add control as precedence edge void ensure_control_or_add_prec(Node* c); - void add_prec_from(Node* n); // Visit boundary uses of the node and apply a callback function for each. // Recursively traverse uses, stopping and applying the callback when @@ -1255,8 +1260,6 @@ class Node { // Whether this is a memory phi node bool is_memory_phi() const { return is_Phi() && bottom_type() == Type::MEMORY; } - bool is_div_or_mod(BasicType bt) const; - //----------------- Printing, etc #ifndef PRODUCT public: @@ -2026,10 +2029,6 @@ Op_IL(URShift) Op_IL(LShift) Op_IL(Xor) Op_IL(Cmp) -Op_IL(Div) -Op_IL(Mod) -Op_IL(UDiv) -Op_IL(UMod) inline int Op_ConIL(BasicType bt) { assert(bt == T_INT || bt == T_LONG, "only for int or longs"); diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 2c0215047857c..3b4519623ad74 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1401,6 +1401,45 @@ const TypeFunc* OptoRuntime::poly1305_processBlocks_Type() { return TypeFunc::make(domain, range); } +// MontgomeryIntegerPolynomialP256 multiply function +const TypeFunc* OptoRuntime::intpoly_montgomeryMult_P256_Type() { + int argcnt = 3; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // a array + fields[argp++] = TypePtr::NOTNULL; // b array + fields[argp++] = TypePtr::NOTNULL; // r(esult) array + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; // carry bits in output + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms+1, fields); + return TypeFunc::make(domain, range); +} + +// IntegerPolynomial constant time assignment function +const TypeFunc* OptoRuntime::intpoly_assign_Type() { + int argcnt = 4; + + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypeInt::INT; // set flag + fields[argp++] = TypePtr::NOTNULL; // a array (result) + fields[argp++] = TypePtr::NOTNULL; // b array (if set is set) + fields[argp++] = TypeInt::INT; // array length + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields); + + // result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = NULL; // void + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields); + return TypeFunc::make(domain, range); +} + //------------- Interpreter state access for on stack replacement const TypeFunc* OptoRuntime::osr_end_Type() { // create input type (domain) diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index 30656044cbb20..e4cbdf2f0d0b4 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -298,6 +298,8 @@ class OptoRuntime : public AllStatic { static const TypeFunc* base64_encodeBlock_Type(); static const TypeFunc* base64_decodeBlock_Type(); static const TypeFunc* poly1305_processBlocks_Type(); + static const TypeFunc* intpoly_montgomeryMult_P256_Type(); + static const TypeFunc* intpoly_assign_Type(); static const TypeFunc* updateBytesCRC32_Type(); static const TypeFunc* updateBytesCRC32C_Type(); diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index d35f623555db4..a9ded1bfa2dcd 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -910,6 +910,10 @@ class LoadVectorGatherNode : public LoadVectorNode { ((is_subword_type(vect_type()->element_basic_type())) && idx == MemNode::ValueIn + 1); } + virtual int store_Opcode() const { + // Ensure it is different from any store opcode to avoid folding when indices are used + return -1; + } }; //------------------------------StoreVectorNode-------------------------------- @@ -942,6 +946,8 @@ class StoreVectorNode : public StoreNode { // Needed for proper cloning. virtual uint size_of() const { return sizeof(*this); } + virtual Node* mask() const { return nullptr; } + virtual Node* indices() const { return nullptr; } #ifdef ASSERT // When AlignVector is enabled, SuperWord only creates aligned vector loads and stores. @@ -957,6 +963,7 @@ class StoreVectorNode : public StoreNode { class StoreVectorScatterNode : public StoreVectorNode { public: + enum { Indices = 4 }; StoreVectorScatterNode(Node* c, Node* mem, Node* adr, const TypePtr* at, Node* val, Node* indices) : StoreVectorNode(c, mem, adr, at, val) { init_class_id(Class_StoreVectorScatter); @@ -968,12 +975,14 @@ class StoreVectorNode : public StoreNode { virtual uint match_edge(uint idx) const { return idx == MemNode::Address || idx == MemNode::ValueIn || idx == MemNode::ValueIn + 1; } + virtual Node* indices() const { return in(Indices); } }; //------------------------------StoreVectorMaskedNode-------------------------------- // Store Vector to memory under the influence of a predicate register(mask). class StoreVectorMaskedNode : public StoreVectorNode { public: + enum { Mask = 4 }; StoreVectorMaskedNode(Node* c, Node* mem, Node* dst, Node* src, const TypePtr* at, Node* mask) : StoreVectorNode(c, mem, dst, at, src) { init_class_id(Class_StoreVectorMasked); @@ -987,6 +996,7 @@ class StoreVectorMaskedNode : public StoreVectorNode { return idx > 1; } virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual Node* mask() const { return in(Mask); } }; //------------------------------LoadVectorMaskedNode-------------------------------- @@ -1007,6 +1017,10 @@ class LoadVectorMaskedNode : public LoadVectorNode { return idx > 1; } virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual int store_Opcode() const { + // Ensure it is different from any store opcode to avoid folding when a mask is used + return -1; + } }; //-------------------------------LoadVectorGatherMaskedNode--------------------------------- @@ -1030,12 +1044,19 @@ class LoadVectorGatherMaskedNode : public LoadVectorNode { idx == MemNode::ValueIn + 1 || (is_subword_type(vect_type()->is_vect()->element_basic_type()) && idx == MemNode::ValueIn + 2); } + virtual int store_Opcode() const { + // Ensure it is different from any store opcode to avoid folding when indices and mask are used + return -1; + } }; //------------------------------StoreVectorScatterMaskedNode-------------------------------- // Store Vector into memory via index map under the influence of a predicate register(mask). class StoreVectorScatterMaskedNode : public StoreVectorNode { public: + enum { Indices = 4, + Mask + }; StoreVectorScatterMaskedNode(Node* c, Node* mem, Node* adr, const TypePtr* at, Node* val, Node* indices, Node* mask) : StoreVectorNode(c, mem, adr, at, val) { init_class_id(Class_StoreVectorScatterMasked); @@ -1050,6 +1071,8 @@ class StoreVectorScatterMaskedNode : public StoreVectorNode { idx == MemNode::ValueIn || idx == MemNode::ValueIn + 1 || idx == MemNode::ValueIn + 2; } + virtual Node* mask() const { return in(Mask); } + virtual Node* indices() const { return in(Indices); } }; // Verify that memory address (adr) is aligned. The mask specifies the diff --git a/src/hotspot/share/prims/jvmti.xml b/src/hotspot/share/prims/jvmti.xml index add7d43ad3e78..3bcf15466d760 100644 --- a/src/hotspot/share/prims/jvmti.xml +++ b/src/hotspot/share/prims/jvmti.xml @@ -8249,37 +8249,42 @@ class C2 extends C1 implements I2 { - The thread owning this monitor, or nullptr if unused + The platform thread owning this monitor, or nullptr if owned + by a virtual thread or not owned - The number of times the owning thread has entered the monitor + The number of times the platform thread owning this monitor has entered it, + or 0 if owned by a virtual thread or not owned - The number of threads waiting to own this monitor + The number of platform threads waiting to own this monitor, or 0 + if only virtual threads are waiting or no threads are waiting - The waiter_count waiting threads + The waiter_count waiting platform threads - The number of threads waiting to be notified by this monitor + The number of platform threads waiting to own this monitor, or 0 + if only virtual threads are waiting to be notified or no threads are waiting + to be notified - The notify_waiter_count threads waiting to be notified + The notify_waiter_count platform threads waiting to be notified @@ -8287,6 +8292,12 @@ class C2 extends C1 implements I2 { Get information about the object's monitor. The fields of the structure are filled in with information about usage of the monitor. +

+ This function does not support getting information about an object's monitor + when it is owned by a virtual thread. It also does not support returning a + reference to virtual threads that are waiting to own a monitor or waiting to + be notified. + Decide and then clarify suspend requirements. diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 1615e3c349cc9..94472baf27c49 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -1482,14 +1482,19 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec // first derive the object's owner and entry_count (if any) owning_thread = ObjectSynchronizer::get_lock_owner(tlh.list(), hobj); if (owning_thread != nullptr) { - Handle th(current_thread, get_vthread_or_thread_oop(owning_thread)); + oop thread_oop = get_vthread_or_thread_oop(owning_thread); + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); + if (is_virtual) { + thread_oop = nullptr; + } + Handle th(current_thread, thread_oop); ret.owner = (jthread)jni_reference(calling_thread, th); // The recursions field of a monitor does not reflect recursions // as lightweight locks before inflating the monitor are not included. // We have to count the number of recursive monitor entries the hard way. // We pass a handle to survive any GCs along the way. - ret.entry_count = count_locked_objects(owning_thread, hobj); + ret.entry_count = is_virtual ? 0 : count_locked_objects(owning_thread, hobj); } // implied else: entry_count == 0 @@ -1513,6 +1518,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec // this object has a lightweight monitor } + jint skipped = 0; if (mon != nullptr) { // Robustness: the actual waiting list can be smaller. // The nWait count we got from the mon->waiters() may include the re-entering @@ -1522,11 +1528,16 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec for (ObjectWaiter* waiter = mon->first_waiter(); waiter != nullptr && (nWait == 0 || waiter != mon->first_waiter()); waiter = mon->next_waiter(waiter)) { + JavaThread *w = mon->thread_of_waiter(waiter); + oop thread_oop = get_vthread_or_thread_oop(w); + if (java_lang_VirtualThread::is_instance(thread_oop)) { + skipped++; + } nWait++; } } ret.waiter_count = nWant; - ret.notify_waiter_count = nWait; + ret.notify_waiter_count = nWait - skipped; // Allocate memory for heavyweight and lightweight monitor. jvmtiError err; @@ -1561,13 +1572,20 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec } if (ret.notify_waiter_count > 0) { // we have threads waiting to be notified in Object.wait() ObjectWaiter *waiter = mon->first_waiter(); + jint skipped = 0; for (int i = 0; i < nWait; i++) { JavaThread *w = mon->thread_of_waiter(waiter); + oop thread_oop = get_vthread_or_thread_oop(w); + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); assert(w != nullptr, "sanity check"); - // If the thread was found on the ObjectWaiter list, then - // it has not been notified. - Handle th(current_thread, get_vthread_or_thread_oop(w)); - ret.notify_waiters[i] = (jthread)jni_reference(calling_thread, th); + if (java_lang_VirtualThread::is_instance(thread_oop)) { + skipped++; + } else { + // If the thread was found on the ObjectWaiter list, then + // it has not been notified. + Handle th(current_thread, get_vthread_or_thread_oop(w)); + ret.notify_waiters[i - skipped] = (jthread)jni_reference(calling_thread, th); + } waiter = mon->next_waiter(waiter); } } @@ -2624,11 +2642,3 @@ GetFrameLocationClosure::do_vthread(Handle target_h) { _result = ((JvmtiEnvBase*)_env)->get_frame_location(target_h(), _depth, _method_ptr, _location_ptr); } - -void -VirtualThreadGetThreadClosure::do_thread(Thread *target) { - assert(target->is_Java_thread(), "just checking"); - JavaThread *jt = JavaThread::cast(target); - oop carrier_thread = java_lang_VirtualThread::carrier_thread(_vthread_h()); - *_carrier_thread_ptr = (jthread)JNIHandles::make_local(jt, carrier_thread); -} diff --git a/src/hotspot/share/prims/jvmtiEnvBase.hpp b/src/hotspot/share/prims/jvmtiEnvBase.hpp index 00de17a8a6b15..d984cc8bd378f 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.hpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.hpp @@ -784,24 +784,6 @@ class GetFrameLocationClosure : public JvmtiUnitedHandshakeClosure { void do_vthread(Handle target_h); }; -// HandshakeClosure to get virtual thread thread at safepoint. -class VirtualThreadGetThreadClosure : public HandshakeClosure { -private: - Handle _vthread_h; - jthread* _carrier_thread_ptr; - jvmtiError _result; - -public: - VirtualThreadGetThreadClosure(Handle vthread_h, jthread* carrier_thread_ptr) - : HandshakeClosure("VirtualThreadGetThread"), - _vthread_h(vthread_h), - _carrier_thread_ptr(carrier_thread_ptr), - _result(JVMTI_ERROR_NONE) {} - - void do_thread(Thread *target); - jvmtiError result() { return _result; } -}; - // ResourceTracker // // ResourceTracker works a little like a ResourceMark. All allocates diff --git a/src/hotspot/share/prims/jvmtiExtensions.cpp b/src/hotspot/share/prims/jvmtiExtensions.cpp index c17674542270f..ec6c668967349 100644 --- a/src/hotspot/share/prims/jvmtiExtensions.cpp +++ b/src/hotspot/share/prims/jvmtiExtensions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -130,6 +130,10 @@ static jvmtiError JNICALL GetCarrierThread(const jvmtiEnv* env, ...) { thread_ptr = va_arg(ap, jthread*); va_end(ap); + if (thread_ptr == nullptr) { + return JVMTI_ERROR_NULL_POINTER; + } + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); ThreadInVMfromNative tiv(current_thread); JvmtiVTMSTransitionDisabler disabler; @@ -156,12 +160,11 @@ static jvmtiError JNICALL GetCarrierThread(const jvmtiEnv* env, ...) { if (!java_lang_VirtualThread::is_instance(vthread_oop)) { return JVMTI_ERROR_INVALID_THREAD; } - if (thread_ptr == nullptr) { - return JVMTI_ERROR_NULL_POINTER; - } - VirtualThreadGetThreadClosure op(Handle(current_thread, vthread_oop), thread_ptr); - Handshake::execute(&op, &tlh, current_thread); - return op.result(); + + oop carrier_thread = java_lang_VirtualThread::carrier_thread(vthread_oop); + *thread_ptr = (jthread)JNIHandles::make_local(current_thread, carrier_thread); + + return JVMTI_ERROR_NONE; } // register extension functions and events. In this implementation we diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 275f095af37dd..8f5d2ad4acbf1 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -950,7 +950,7 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer ResourceMark rm(thread); InterpreterOopMap mask; if (query_oop_map_cache) { - m->mask_for(bci, &mask); + m->mask_for(m, bci, &mask); } else { OopMapCache::compute_one_oop_map(m, bci, &mask); } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 3c05ea985b656..6bfb260606bcb 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -233,6 +233,8 @@ const int ObjectAlignmentInBytes = 8; \ product(bool, UsePoly1305Intrinsics, false, DIAGNOSTIC, \ "Use intrinsics for sun.security.util.math.intpoly") \ + product(bool, UseIntPolyIntrinsics, false, DIAGNOSTIC, \ + "Use intrinsics for sun.security.util.math.intpoly.MontgomeryIntegerPolynomialP256") \ \ product(size_t, LargePageSizeInBytes, 0, \ "Maximum large page size used (0 will use the default large " \ diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 97be533341364..e4992f3684286 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -2230,8 +2230,8 @@ void JavaThread::pretouch_stack() { if (is_in_full_stack(here) && here > end) { size_t to_alloc = here - end; char* p2 = (char*) alloca(to_alloc); - log_trace(os, thread)("Pretouching thread stack from " PTR_FORMAT " to " PTR_FORMAT ".", - p2i(p2), p2i(end)); + log_trace(os, thread)("Pretouching thread stack for " UINTX_FORMAT ": " RANGEFMT ".", + (uintx) osthread()->thread_id(), RANGEFMTARGS(p2, to_alloc)); os::pretouch_memory(p2, p2 + to_alloc, NOT_AIX(os::vm_page_size()) AIX_ONLY(4096)); } diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index d281acdf00699..178f3e97d7108 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -829,7 +829,6 @@ void ObjectMonitor::EnterI(JavaThread* current) { // to defer the state transitions until absolutely necessary, // and in doing so avoid some transitions ... - int nWakeups = 0; int recheckInterval = 1; for (;;) { @@ -872,15 +871,14 @@ void ObjectMonitor::EnterI(JavaThread* current) { } // The lock is still contested. + // Keep a tally of the # of futile wakeups. // Note that the counter is not protected by a lock or updated by atomics. // That is by design - we trade "lossy" counters which are exposed to // races during updates for a lower probe effect. - // This PerfData object can be used in parallel with a safepoint. // See the work around in PerfDataManager::destroy(). OM_PERFDATA_OP(FutileWakeups, inc()); - ++nWakeups; // Assuming this is not a spurious wakeup we'll normally find _succ == current. // We can defer clearing _succ until after the spin completes @@ -981,12 +979,18 @@ void ObjectMonitor::ReenterI(JavaThread* current, ObjectWaiter* currentNode) { assert(current->thread_state() != _thread_blocked, "invariant"); - int nWakeups = 0; for (;;) { ObjectWaiter::TStates v = currentNode->TState; guarantee(v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant"); assert(owner_raw() != current, "invariant"); + // This thread has been notified so try to reacquire the lock. + if (TryLock(current) == TryLockResult::Success) { + break; + } + + // If that fails, spin again. Note that spin count may be zero so the above TryLock + // is necessary. if (TrySpin(current)) { break; } @@ -1011,11 +1015,6 @@ void ObjectMonitor::ReenterI(JavaThread* current, ObjectWaiter* currentNode) { } // The lock is still contested. - // Keep a tally of the # of futile wakeups. - // Note that the counter is not protected by a lock or updated by atomics. - // That is by design - we trade "lossy" counters which are exposed to - // races during updates for a lower probe effect. - ++nWakeups; // Assuming this is not a spurious wakeup we'll normally // find that _succ == current. @@ -1025,6 +1024,10 @@ void ObjectMonitor::ReenterI(JavaThread* current, ObjectWaiter* currentNode) { // *must* retry _owner before parking. OrderAccess::fence(); + // Keep a tally of the # of futile wakeups. + // Note that the counter is not protected by a lock or updated by atomics. + // That is by design - we trade "lossy" counters which are exposed to + // races during updates for a lower probe effect. // This PerfData object can be used in parallel with a safepoint. // See the work around in PerfDataManager::destroy(). OM_PERFDATA_OP(FutileWakeups, inc()); diff --git a/src/hotspot/share/runtime/serviceThread.cpp b/src/hotspot/share/runtime/serviceThread.cpp index a5082fad47937..f02e5062e672e 100644 --- a/src/hotspot/share/runtime/serviceThread.cpp +++ b/src/hotspot/share/runtime/serviceThread.cpp @@ -33,6 +33,7 @@ #include "gc/shared/oopStorage.hpp" #include "gc/shared/oopStorageSet.hpp" #include "memory/universe.hpp" +#include "interpreter/oopMapCache.hpp" #include "oops/oopHandle.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -95,6 +96,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { bool oop_handles_to_release = false; bool cldg_cleanup_work = false; bool jvmti_tagmap_work = false; + bool oopmap_cache_work = false; { // Need state transition ThreadBlockInVM so that this thread // will be handled by safepoint correctly when this thread is @@ -124,7 +126,8 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { (oopstorage_work = OopStorage::has_cleanup_work_and_reset()) | (oop_handles_to_release = JavaThread::has_oop_handles_to_release()) | (cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) | - (jvmti_tagmap_work = JvmtiTagMap::has_object_free_events_and_reset()) + (jvmti_tagmap_work = JvmtiTagMap::has_object_free_events_and_reset()) | + (oopmap_cache_work = OopMapCache::has_cleanup_work()) ) == 0) { // Wait until notified that there is some work to do or timer expires. // Some cleanup requests don't notify the ServiceThread so work needs to be done at periodic intervals. @@ -196,6 +199,10 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { if (jvmti_tagmap_work) { JvmtiTagMap::flush_all_object_free_events(); } + + if (oopmap_cache_work) { + OopMapCache::cleanup(); + } } } diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index f52255f504d90..74286a4ac98fb 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -132,6 +132,8 @@ address StubRoutines::_chacha20Block = nullptr; address StubRoutines::_base64_encodeBlock = nullptr; address StubRoutines::_base64_decodeBlock = nullptr; address StubRoutines::_poly1305_processBlocks = nullptr; +address StubRoutines::_intpoly_montgomeryMult_P256 = nullptr; +address StubRoutines::_intpoly_assign = nullptr; address StubRoutines::_md5_implCompress = nullptr; address StubRoutines::_md5_implCompressMB = nullptr; diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index fe32c9613c814..65b0c0d2f26f9 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -215,6 +215,8 @@ class StubRoutines: AllStatic { static address _base64_encodeBlock; static address _base64_decodeBlock; static address _poly1305_processBlocks; + static address _intpoly_montgomeryMult_P256; + static address _intpoly_assign; static address _md5_implCompress; static address _md5_implCompressMB; @@ -409,6 +411,8 @@ class StubRoutines: AllStatic { static address electronicCodeBook_encryptAESCrypt() { return _electronicCodeBook_encryptAESCrypt; } static address electronicCodeBook_decryptAESCrypt() { return _electronicCodeBook_decryptAESCrypt; } static address poly1305_processBlocks() { return _poly1305_processBlocks; } + static address intpoly_montgomeryMult_P256() { return _intpoly_montgomeryMult_P256; } + static address intpoly_assign() { return _intpoly_assign; } static address counterMode_AESCrypt() { return _counterMode_AESCrypt; } static address ghash_processBlocks() { return _ghash_processBlocks; } static address chacha20Block() { return _chacha20Block; } diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index d0749b8101d85..44c845986f375 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -593,8 +593,6 @@ class Thread: public ThreadShadow { static ByteSize tlab_top_offset() { return byte_offset_of(Thread, _tlab) + ThreadLocalAllocBuffer::top_offset(); } static ByteSize tlab_pf_top_offset() { return byte_offset_of(Thread, _tlab) + ThreadLocalAllocBuffer::pf_top_offset(); } - static ByteSize allocated_bytes_offset() { return byte_offset_of(Thread, _allocated_bytes); } - JFR_ONLY(DEFINE_THREAD_LOCAL_OFFSET_JFR;) public: diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index b92e5a90c5580..0e2edb7906b04 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1183,7 +1183,8 @@ void Threads::metadata_handles_do(void f(Metadata*)) { } #if INCLUDE_JVMTI -// Get count of Java threads that are waiting to enter or re-enter the specified monitor. +// Get Java threads that are waiting to enter or re-enter the specified monitor. +// Java threads that are executing mounted virtual threads are not included. GrowableArray* Threads::get_pending_threads(ThreadsList * t_list, int count, address monitor) { @@ -1194,14 +1195,16 @@ GrowableArray* Threads::get_pending_threads(ThreadsList * t_list, for (JavaThread* p : *t_list) { if (!p->can_call_java()) continue; + oop thread_oop = JvmtiEnvBase::get_vthread_or_thread_oop(p); + if (java_lang_VirtualThread::is_instance(thread_oop)) { + continue; + } // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. address pending = (address)p->current_pending_monitor(); address waiting = (address)p->current_waiting_monitor(); - oop thread_oop = JvmtiEnvBase::get_vthread_or_thread_oop(p); - bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); - jint state = is_virtual ? JvmtiEnvBase::get_vthread_state(thread_oop, p) - : JvmtiEnvBase::get_thread_state(thread_oop, p); + // do not include virtual threads to the list + jint state = JvmtiEnvBase::get_thread_state(thread_oop, p); if (pending == monitor || (waiting == monitor && (state & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER)) ) { // found a match diff --git a/src/hotspot/share/runtime/threads.hpp b/src/hotspot/share/runtime/threads.hpp index 6c4573827d93d..39e307122c8b8 100644 --- a/src/hotspot/share/runtime/threads.hpp +++ b/src/hotspot/share/runtime/threads.hpp @@ -129,7 +129,8 @@ class Threads: AllStatic { // Print threads busy compiling, and returns the number of printed threads. static unsigned print_threads_compiling(outputStream* st, char* buf, int buflen, bool short_form = false); - // Get count of Java threads that are waiting to enter or re-enter the specified monitor. + // Get Java threads that are waiting to enter or re-enter the specified monitor. + // Java threads that are executing mounted virtual threads are not included. static GrowableArray* get_pending_threads(ThreadsList * t_list, int count, address monitor); diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index 45f5dddafb238..c735f9af85362 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -33,6 +33,7 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.io.JdkConsoleImpl; import jdk.internal.io.JdkConsoleProvider; +import jdk.internal.javac.PreviewFeature; import jdk.internal.util.StaticProperty; import sun.security.action.GetPropertyAction; @@ -150,6 +151,69 @@ public Reader reader() { throw newUnsupportedOperationException(); } + /** + * Writes a string representation of the specified object to this console's + * output stream, terminates the line using {@link System#lineSeparator()} + * and then flushes the console. + * + *

The string representation of the specified object is obtained as if + * by calling {@link String#valueOf(Object)}. + * + * @param obj + * An object whose string representation is to be written, + * may be {@code null}. + * + * @return This console + * + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public Console println(Object obj) { + throw newUnsupportedOperationException(); + } + + /** + * Writes a string representation of the specified object to this console's + * output stream and then flushes the console. + * + *

The string representation of the specified object is obtained as if + * by calling {@link String#valueOf(Object)}. + * + * @param obj + * An object whose string representation is to be written, + * may be {@code null}. + * + * @return This console + * + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public Console print(Object obj) { + throw newUnsupportedOperationException(); + } + + /** + * Writes a prompt as if by calling {@code print}, then reads a single line + * of text from this console. + * + * @param prompt + * A prompt string, may be {@code null}. + * + * @throws IOError + * If an I/O error occurs. + * + * @return A string containing the line read from the console, not + * including any line-termination characters, or {@code null} + * if an end of stream has been reached without having read + * any characters. + * + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public String readln(String prompt) { + throw newUnsupportedOperationException(); + } + /** * Writes a formatted string to this console's output stream using * the specified format string and arguments with the diff --git a/src/java.base/share/classes/java/io/IO.java b/src/java.base/share/classes/java/io/IO.java new file mode 100644 index 0000000000000..7485f87f03fda --- /dev/null +++ b/src/java.base/share/classes/java/io/IO.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +import jdk.internal.javac.PreviewFeature; + +/** + * A collection of static convenience methods that provide access to + * {@linkplain System#console() system console} for implicitly declared classes. + * + *

Each of this class' methods throws {@link IOError} if the system console + * is {@code null}; otherwise, the effect is as if a similarly-named method + * had been called on that console. + * + *

Input and output from methods in this class use the character set of + * the system console as specified by {@link Console#charset}. + * + * @since 23 + */ +@PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) +public final class IO { + + private IO() { + throw new Error("no instances"); + } + + /** + * Writes a string representation of the specified object to the system + * console, terminates the line and then flushes that console. + * + *

The effect is as if {@link Console#println(Object) println(obj)} + * had been called on {@code System.console()}. + * + * @param obj the object to print, may be {@code null} + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + */ + public static void println(Object obj) { + con().println(obj); + } + + /** + * Writes a string representation of the specified object to the system + * console and then flushes that console. + * + *

The effect is as if {@link Console#print(Object) print(obj)} + * had been called on {@code System.console()}. + * + * @param obj the object to print, may be {@code null} + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + */ + public static void print(Object obj) { + con().print(obj); + } + + /** + * Writes a prompt as if by calling {@code print}, then reads a single line + * of text from the system console. + * + *

The effect is as if {@link Console#readln(String) readln(prompt)} + * had been called on {@code System.console()}. + * + * @param prompt the prompt string, may be {@code null} + * + * @return a string containing the line read from the system console, not + * including any line-termination characters. Returns {@code null} if an + * end of stream has been reached without having read any characters. + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + */ + public static String readln(String prompt) { + return con().readln(prompt); + } + + private static Console con() { + var con = System.console(); + if (con != null) { + return con; + } else { + throw new IOError(null); + } + } +} diff --git a/src/java.base/share/classes/java/io/ObjectInputStream.java b/src/java.base/share/classes/java/io/ObjectInputStream.java index 502db6a1a214d..74c34d80a7beb 100644 --- a/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -2358,7 +2358,13 @@ private void readExternalData(Externalizable obj, ObjectStreamClass desc) */ } - /** Reads a record. */ + /** + * Reads and returns a record. + * If an exception is marked for any of the fields, the dependency + * mechanism marks the record as having an exception. + * Null is returned from readRecord and later the exception is thrown at + * the exit of {@link #readObject(Class)}. + **/ private Object readRecord(ObjectStreamClass desc) throws IOException { ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); if (slots.length != 1) { @@ -2371,6 +2377,9 @@ private Object readRecord(ObjectStreamClass desc) throws IOException { } FieldValues fieldValues = new FieldValues(desc, true); + if (handles.lookupException(passHandle) != null) { + return null; // slot marked with exception, don't create record + } // get canonical record constructor adapted to take two arguments: // - byte[] primValues @@ -2464,8 +2473,11 @@ private void readSerialData(Object obj, ObjectStreamClass desc) if (slotValues != null) { slotValues[i] = values; } else if (obj != null) { - values.defaultCheckFieldValues(obj); - values.defaultSetFieldValues(obj); + if (handles.lookupException(passHandle) == null) { + // passHandle NOT marked with an exception; set field values + values.defaultCheckFieldValues(obj); + values.defaultSetFieldValues(obj); + } } } @@ -2484,7 +2496,8 @@ private void readSerialData(Object obj, ObjectStreamClass desc) } } - if (obj != null && slotValues != null) { + if (obj != null && slotValues != null && handles.lookupException(passHandle) == null) { + // passHandle NOT marked with an exception // Check that the non-primitive types are assignable for all slots // before assigning. for (int i = 0; i < slots.length; i++) { diff --git a/src/java.base/share/classes/java/io/ProxyingConsole.java b/src/java.base/share/classes/java/io/ProxyingConsole.java index 2179afa31c068..1babceb665fa9 100644 --- a/src/java.base/share/classes/java/io/ProxyingConsole.java +++ b/src/java.base/share/classes/java/io/ProxyingConsole.java @@ -81,6 +81,42 @@ public Reader reader() { return reader; } + /** + * {@inheritDoc} + */ + @Override + public Console println(Object obj) { + synchronized (writeLock) { + delegate.println(obj); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public Console print(Object obj) { + synchronized (writeLock) { + delegate.print(obj); + } + return this; + } + + /** + * {@inheritDoc} + * + * @throws IOError {@inheritDoc} + */ + @Override + public String readln(String prompt) { + synchronized (writeLock) { + synchronized (readLock) { + return delegate.readln(prompt); + } + } + } + /** * {@inheritDoc} */ diff --git a/src/java.base/share/classes/java/lang/classfile/Attributes.java b/src/java.base/share/classes/java/lang/classfile/Attributes.java index 75e06e7c3f31e..1e91090f8afda 100644 --- a/src/java.base/share/classes/java/lang/classfile/Attributes.java +++ b/src/java.base/share/classes/java/lang/classfile/Attributes.java @@ -24,77 +24,74 @@ */ package java.lang.classfile; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import java.lang.classfile.attribute.AnnotationDefaultAttribute; -import java.lang.classfile.attribute.BootstrapMethodsAttribute; -import java.lang.classfile.attribute.CharacterRangeInfo; -import java.lang.classfile.attribute.CharacterRangeTableAttribute; -import java.lang.classfile.attribute.CodeAttribute; -import java.lang.classfile.attribute.CompilationIDAttribute; -import java.lang.classfile.attribute.ConstantValueAttribute; -import java.lang.classfile.attribute.DeprecatedAttribute; -import java.lang.classfile.attribute.EnclosingMethodAttribute; -import java.lang.classfile.attribute.ExceptionsAttribute; -import java.lang.classfile.attribute.InnerClassInfo; -import java.lang.classfile.attribute.InnerClassesAttribute; -import java.lang.classfile.attribute.LineNumberInfo; -import java.lang.classfile.attribute.LineNumberTableAttribute; -import java.lang.classfile.attribute.LocalVariableInfo; -import java.lang.classfile.attribute.LocalVariableTableAttribute; -import java.lang.classfile.attribute.LocalVariableTypeInfo; -import java.lang.classfile.attribute.LocalVariableTypeTableAttribute; -import java.lang.classfile.attribute.MethodParameterInfo; -import java.lang.classfile.attribute.MethodParametersAttribute; -import java.lang.classfile.attribute.ModuleAttribute; -import java.lang.classfile.attribute.ModuleExportInfo; -import java.lang.classfile.attribute.ModuleHashInfo; -import java.lang.classfile.attribute.ModuleHashesAttribute; -import java.lang.classfile.attribute.ModuleMainClassAttribute; -import java.lang.classfile.attribute.ModuleOpenInfo; -import java.lang.classfile.attribute.ModulePackagesAttribute; -import java.lang.classfile.attribute.ModuleProvideInfo; -import java.lang.classfile.attribute.ModuleRequireInfo; -import java.lang.classfile.attribute.ModuleResolutionAttribute; -import java.lang.classfile.attribute.ModuleTargetAttribute; -import java.lang.classfile.attribute.NestHostAttribute; -import java.lang.classfile.attribute.NestMembersAttribute; -import java.lang.classfile.attribute.PermittedSubclassesAttribute; -import java.lang.classfile.attribute.RecordAttribute; -import java.lang.classfile.attribute.RecordComponentInfo; -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.SignatureAttribute; -import java.lang.classfile.attribute.SourceDebugExtensionAttribute; -import java.lang.classfile.attribute.SourceFileAttribute; -import java.lang.classfile.attribute.SourceIDAttribute; -import java.lang.classfile.attribute.StackMapTableAttribute; -import java.lang.classfile.attribute.SyntheticAttribute; -import java.lang.classfile.constantpool.Utf8Entry; -import jdk.internal.classfile.impl.AbstractAttributeMapper; -import jdk.internal.classfile.impl.BoundAttribute; -import jdk.internal.classfile.impl.CodeImpl; -import jdk.internal.classfile.impl.AbstractPoolEntry; -import jdk.internal.classfile.impl.StackMapDecoder; +import java.lang.classfile.AttributeMapper.AttributeStability; +import java.lang.classfile.attribute.*; +import jdk.internal.classfile.impl.AbstractAttributeMapper.*; import jdk.internal.javac.PreviewFeature; /** * Attribute mappers for standard classfile attributes. + *

+ * Unless otherwise specified, mappers returned by each method + * do not permit multiple attribute instances in a given location. + *

+ * The most stable {@link AttributeStability#STATELESS STATELESS} mappers are: + *

    + *
  • {@link #deprecated()} + *
  • {@link #moduleResolution()} + *
  • {@link #sourceDebugExtension()} + *
  • {@link #synthetic()} + *
+ * + * The mappers with {@link AttributeStability#CP_REFS CP_REFS} stability are: + *
    + *
  • {@link #annotationDefault()} + *
  • {@link #bootstrapMethods()} + *
  • {@link #code()} + *
  • {@link #compilationId()} + *
  • {@link #constantValue()} + *
  • {@link #enclosingMethod()} + *
  • {@link #exceptions()} + *
  • {@link #innerClasses()} + *
  • {@link #methodParameters()} + *
  • {@link #module()} + *
  • {@link #moduleHashes()} + *
  • {@link #moduleMainClass()} + *
  • {@link #modulePackages()} + *
  • {@link #moduleTarget()} + *
  • {@link #nestHost()} + *
  • {@link #nestMembers()} + *
  • {@link #permittedSubclasses()} + *
  • {@link #record()} + *
  • {@link #runtimeInvisibleAnnotations()} + *
  • {@link #runtimeInvisibleParameterAnnotations()} + *
  • {@link #runtimeVisibleAnnotations()} + *
  • {@link #runtimeVisibleParameterAnnotations()} + *
  • {@link #signature()} + *
  • {@link #sourceFile()} + *
  • {@link #sourceId()} + *
+ * + * The mappers with {@link AttributeStability#LABELS LABELS} stability are: + *
    + *
  • {@link #characterRangeTable()} + *
  • {@link #lineNumberTable()} + *
  • {@link #localVariableTable()} + *
  • {@link #localVariableTypeTable()} + *
+ * + * The {@link AttributeStability#UNSTABLE UNSTABLE} mappers are: + *
    + *
  • {@link #runtimeInvisibleTypeAnnotations()} + *
  • {@link #runtimeVisibleTypeAnnotations()} + *
* * @see AttributeMapper * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) -public class Attributes { +public final class Attributes { /** AnnotationDefault */ public static final String NAME_ANNOTATION_DEFAULT = "AnnotationDefault"; @@ -207,836 +204,297 @@ public class Attributes { private Attributes() { } - /** Attribute mapper for the {@code AnnotationDefault} attribute */ - public static final AttributeMapper - ANNOTATION_DEFAULT = new AbstractAttributeMapper<>(NAME_ANNOTATION_DEFAULT) { - @Override - public AnnotationDefaultAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundAnnotationDefaultAttr(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, AnnotationDefaultAttribute attr) { - attr.defaultValue().writeTo(buf); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code BootstrapMethods} attribute */ - public static final AttributeMapper - BOOTSTRAP_METHODS = new AbstractAttributeMapper<>(NAME_BOOTSTRAP_METHODS) { - @Override - public BootstrapMethodsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundBootstrapMethodsAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, BootstrapMethodsAttribute attr) { - buf.writeList(attr.bootstrapMethods()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code CharacterRangeTable} attribute */ - public static final AttributeMapper - CHARACTER_RANGE_TABLE = new AbstractAttributeMapper<>(NAME_CHARACTER_RANGE_TABLE, true) { - @Override - public CharacterRangeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundCharacterRangeTableAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, CharacterRangeTableAttribute attr) { - List ranges = attr.characterRangeTable(); - buf.writeU2(ranges.size()); - for (CharacterRangeInfo info : ranges) { - buf.writeU2(info.startPc()); - buf.writeU2(info.endPc()); - buf.writeInt(info.characterRangeStart()); - buf.writeInt(info.characterRangeEnd()); - buf.writeU2(info.flags()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - /** Attribute mapper for the {@code Code} attribute */ - public static final AttributeMapper - CODE = new AbstractAttributeMapper<>(NAME_CODE) { - @Override - public CodeAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new CodeImpl(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, CodeAttribute attr) { - throw new UnsupportedOperationException("Code attribute does not support direct write"); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - - /** Attribute mapper for the {@code CompilationID} attribute */ - public static final AttributeMapper - COMPILATION_ID = new AbstractAttributeMapper<>(NAME_COMPILATION_ID, true) { - @Override - public CompilationIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundCompilationIDAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, CompilationIDAttribute attr) { - buf.writeIndex(attr.compilationId()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ConstantValue} attribute */ - public static final AttributeMapper - CONSTANT_VALUE = new AbstractAttributeMapper<>(NAME_CONSTANT_VALUE) { - @Override - public ConstantValueAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundConstantValueAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ConstantValueAttribute attr) { - buf.writeIndex(attr.constant()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code Deprecated} attribute */ - public static final AttributeMapper - DEPRECATED = new AbstractAttributeMapper<>(NAME_DEPRECATED, true) { - @Override - public DeprecatedAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundDeprecatedAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, DeprecatedAttribute attr) { - // empty - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.STATELESS; - } - }; - - /** Attribute mapper for the {@code EnclosingMethod} attribute */ - public static final AttributeMapper - ENCLOSING_METHOD = new AbstractAttributeMapper<>(NAME_ENCLOSING_METHOD) { - @Override - public EnclosingMethodAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundEnclosingMethodAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, EnclosingMethodAttribute attr) { - buf.writeIndex(attr.enclosingClass()); - buf.writeIndexOrZero(attr.enclosingMethod().orElse(null)); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code Exceptions} attribute */ - public static final AttributeMapper - EXCEPTIONS = new AbstractAttributeMapper<>(NAME_EXCEPTIONS) { - @Override - public ExceptionsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundExceptionsAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ExceptionsAttribute attr) { - buf.writeListIndices(attr.exceptions()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code InnerClasses} attribute */ - public static final AttributeMapper - INNER_CLASSES = new AbstractAttributeMapper<>(NAME_INNER_CLASSES) { - @Override - public InnerClassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundInnerClassesAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, InnerClassesAttribute attr) { - List classes = attr.classes(); - buf.writeU2(classes.size()); - for (InnerClassInfo ic : classes) { - buf.writeIndex(ic.innerClass()); - buf.writeIndexOrZero(ic.outerClass().orElse(null)); - buf.writeIndexOrZero(ic.innerName().orElse(null)); - buf.writeU2(ic.flagsMask()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code LineNumberTable} attribute */ - public static final AttributeMapper - LINE_NUMBER_TABLE = new AbstractAttributeMapper<>(NAME_LINE_NUMBER_TABLE, true) { - @Override - public LineNumberTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundLineNumberTableAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, LineNumberTableAttribute attr) { - List lines = attr.lineNumbers(); - buf.writeU2(lines.size()); - for (LineNumberInfo line : lines) { - buf.writeU2(line.startPc()); - buf.writeU2(line.lineNumber()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - /** Attribute mapper for the {@code LocalVariableTable} attribute */ - public static final AttributeMapper - LOCAL_VARIABLE_TABLE = new AbstractAttributeMapper<>(NAME_LOCAL_VARIABLE_TABLE, true) { - @Override - public LocalVariableTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundLocalVariableTableAttribute(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, LocalVariableTableAttribute attr) { - List infos = attr.localVariables(); - buf.writeU2(infos.size()); - for (LocalVariableInfo info : infos) { - buf.writeU2(info.startPc()); - buf.writeU2(info.length()); - buf.writeIndex(info.name()); - buf.writeIndex(info.type()); - buf.writeU2(info.slot()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - /** Attribute mapper for the {@code LocalVariableTypeTable} attribute */ - public static final AttributeMapper - LOCAL_VARIABLE_TYPE_TABLE = new AbstractAttributeMapper<>(NAME_LOCAL_VARIABLE_TYPE_TABLE, true) { - @Override - public LocalVariableTypeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundLocalVariableTypeTableAttribute(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, LocalVariableTypeTableAttribute attr) { - List infos = attr.localVariableTypes(); - buf.writeU2(infos.size()); - for (LocalVariableTypeInfo info : infos) { - buf.writeU2(info.startPc()); - buf.writeU2(info.length()); - buf.writeIndex(info.name()); - buf.writeIndex(info.signature()); - buf.writeU2(info.slot()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - /** Attribute mapper for the {@code MethodParameters} attribute */ - public static final AttributeMapper - METHOD_PARAMETERS = new AbstractAttributeMapper<>(NAME_METHOD_PARAMETERS) { - @Override - public MethodParametersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundMethodParametersAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, MethodParametersAttribute attr) { - List parameters = attr.parameters(); - buf.writeU1(parameters.size()); - for (MethodParameterInfo info : parameters) { - buf.writeIndexOrZero(info.name().orElse(null)); - buf.writeU2(info.flagsMask()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code Module} attribute */ - public static final AttributeMapper - MODULE = new AbstractAttributeMapper<>(NAME_MODULE) { - @Override - public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleAttribute attr) { - buf.writeIndex(attr.moduleName()); - buf.writeU2(attr.moduleFlagsMask()); - buf.writeIndexOrZero(attr.moduleVersion().orElse(null)); - buf.writeU2(attr.requires().size()); - for (ModuleRequireInfo require : attr.requires()) { - buf.writeIndex(require.requires()); - buf.writeU2(require.requiresFlagsMask()); - buf.writeIndexOrZero(require.requiresVersion().orElse(null)); - } - buf.writeU2(attr.exports().size()); - for (ModuleExportInfo export : attr.exports()) { - buf.writeIndex(export.exportedPackage()); - buf.writeU2(export.exportsFlagsMask()); - buf.writeListIndices(export.exportsTo()); - } - buf.writeU2(attr.opens().size()); - for (ModuleOpenInfo open : attr.opens()) { - buf.writeIndex(open.openedPackage()); - buf.writeU2(open.opensFlagsMask()); - buf.writeListIndices(open.opensTo()); - } - buf.writeListIndices(attr.uses()); - buf.writeU2(attr.provides().size()); - for (ModuleProvideInfo provide : attr.provides()) { - buf.writeIndex(provide.provides()); - buf.writeListIndices(provide.providesWith()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ModuleHashes} attribute */ - public static final AttributeMapper - MODULE_HASHES = new AbstractAttributeMapper<>(NAME_MODULE_HASHES) { - @Override - public ModuleHashesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleHashesAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleHashesAttribute attr) { - buf.writeIndex(attr.algorithm()); - List hashes = attr.hashes(); - buf.writeU2(hashes.size()); - for (ModuleHashInfo hash : hashes) { - buf.writeIndex(hash.moduleName()); - buf.writeU2(hash.hash().length); - buf.writeBytes(hash.hash()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ModuleMainClass} attribute */ - public static final AttributeMapper - MODULE_MAIN_CLASS = new AbstractAttributeMapper<>(NAME_MODULE_MAIN_CLASS) { - @Override - public ModuleMainClassAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleMainClassAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleMainClassAttribute attr) { - buf.writeIndex(attr.mainClass()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ModulePackages} attribute */ - public static final AttributeMapper - MODULE_PACKAGES = new AbstractAttributeMapper<>(NAME_MODULE_PACKAGES) { - @Override - public ModulePackagesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModulePackagesAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) { - buf.writeListIndices(attr.packages()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ModuleResolution} attribute */ - public static final AttributeMapper - MODULE_RESOLUTION = new AbstractAttributeMapper<>(NAME_MODULE_RESOLUTION) { - @Override - public ModuleResolutionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleResolutionAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleResolutionAttribute attr) { - buf.writeU2(attr.resolutionFlags()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.STATELESS; - } - }; - - /** Attribute mapper for the {@code ModuleTarget} attribute */ - public static final AttributeMapper - MODULE_TARGET = new AbstractAttributeMapper<>(NAME_MODULE_TARGET) { - @Override - public ModuleTargetAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleTargetAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleTargetAttribute attr) { - buf.writeIndex(attr.targetPlatform()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code NestHost} attribute */ - public static final AttributeMapper - NEST_HOST = new AbstractAttributeMapper<>(NAME_NEST_HOST) { - @Override - public NestHostAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundNestHostAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, NestHostAttribute attr) { - buf.writeIndex(attr.nestHost()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code NestMembers} attribute */ - public static final AttributeMapper - NEST_MEMBERS = new AbstractAttributeMapper<>(NAME_NEST_MEMBERS) { - @Override - public NestMembersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundNestMembersAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, NestMembersAttribute attr) { - buf.writeListIndices(attr.nestMembers()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code PermittedSubclasses} attribute */ - public static final AttributeMapper - PERMITTED_SUBCLASSES = new AbstractAttributeMapper<>(NAME_PERMITTED_SUBCLASSES) { - @Override - public PermittedSubclassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundPermittedSubclassesAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, PermittedSubclassesAttribute attr) { - buf.writeListIndices(attr.permittedSubclasses()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code Record} attribute */ - public static final AttributeMapper - RECORD = new AbstractAttributeMapper<>(NAME_RECORD) { - @Override - public RecordAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRecordAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RecordAttribute attr) { - List components = attr.components(); - buf.writeU2(components.size()); - for (RecordComponentInfo info : components) { - buf.writeIndex(info.name()); - buf.writeIndex(info.descriptor()); - buf.writeList(info.attributes()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeInvisibleAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_INVISIBLE_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) { - @Override - public RuntimeInvisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { - return new BoundAttribute.BoundRuntimeInvisibleAnnotationsAttribute(cf, pos); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeInvisibleAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeInvisibleParameterAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) { - @Override - public RuntimeInvisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRuntimeInvisibleParameterAnnotationsAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeInvisibleParameterAnnotationsAttribute attr) { - List> lists = attr.parameterAnnotations(); - buf.writeU1(lists.size()); - for (List list : lists) - buf.writeList(list); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeInvisibleTypeAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) { - @Override - public RuntimeInvisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRuntimeInvisibleTypeAnnotationsAttribute(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.UNSTABLE; - } - }; - - /** Attribute mapper for the {@code RuntimeVisibleAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_VISIBLE_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_VISIBLE_ANNOTATIONS) { - @Override - public RuntimeVisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { - return new BoundAttribute.BoundRuntimeVisibleAnnotationsAttribute(cf, pos); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeVisibleAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeVisibleParameterAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) { - @Override - public RuntimeVisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRuntimeVisibleParameterAnnotationsAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeVisibleParameterAnnotationsAttribute attr) { - List> lists = attr.parameterAnnotations(); - buf.writeU1(lists.size()); - for (List list : lists) - buf.writeList(list); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeVisibleTypeAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_VISIBLE_TYPE_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) { - @Override - public RuntimeVisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRuntimeVisibleTypeAnnotationsAttribute(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.UNSTABLE; - } - }; - - /** Attribute mapper for the {@code Signature} attribute */ - public static final AttributeMapper - SIGNATURE = new AbstractAttributeMapper<>(NAME_SIGNATURE) { - @Override - public SignatureAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSignatureAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SignatureAttribute attr) { - buf.writeIndex(attr.signature()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code SourceDebugExtension} attribute */ - public static final AttributeMapper - SOURCE_DEBUG_EXTENSION = new AbstractAttributeMapper<>(NAME_SOURCE_DEBUG_EXTENSION) { - @Override - public SourceDebugExtensionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSourceDebugExtensionAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SourceDebugExtensionAttribute attr) { - buf.writeBytes(attr.contents()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.STATELESS; - } - }; - - /** Attribute mapper for the {@code SourceFile} attribute */ - public static final AttributeMapper - SOURCE_FILE = new AbstractAttributeMapper<>(NAME_SOURCE_FILE) { - @Override - public SourceFileAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSourceFileAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SourceFileAttribute attr) { - buf.writeIndex(attr.sourceFile()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code SourceID} attribute */ - public static final AttributeMapper - SOURCE_ID = new AbstractAttributeMapper<>(NAME_SOURCE_ID) { - @Override - public SourceIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSourceIDAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SourceIDAttribute attr) { - buf.writeIndex(attr.sourceId()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code StackMapTable} attribute */ - public static final AttributeMapper - STACK_MAP_TABLE = new AbstractAttributeMapper<>(NAME_STACK_MAP_TABLE) { - @Override - public StackMapTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundStackMapTableAttribute((CodeImpl)e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter b, StackMapTableAttribute attr) { - StackMapDecoder.writeFrames(b, attr.entries()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - - /** Attribute mapper for the {@code Synthetic} attribute */ - public static final AttributeMapper - SYNTHETIC = new AbstractAttributeMapper<>(NAME_SYNTHETIC, true) { - @Override - public SyntheticAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSyntheticAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SyntheticAttribute attr) { - // empty - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.STATELESS; - } - }; + /** + * {@return Attribute mapper for the {@code AnnotationDefault} attribute} + * @since 23 + */ + public static AttributeMapper annotationDefault() { + return AnnotationDefaultMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code BootstrapMethods} attribute} + * @since 23 + */ + public static AttributeMapper bootstrapMethods() { + return BootstrapMethodsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code CharacterRangeTable} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper characterRangeTable() { + return CharacterRangeTableMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Code} attribute} + * @since 23 + */ + public static AttributeMapper code() { + return CodeMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code CompilationID} attribute} + * @since 23 + */ + public static AttributeMapper compilationId() { + return CompilationIDMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ConstantValue} attribute} + * @since 23 + */ + public static AttributeMapper constantValue() { + return ConstantValueMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Deprecated} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper deprecated() { + return DeprecatedMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code EnclosingMethod} attribute} + * @since 23 + */ + public static AttributeMapper enclosingMethod() { + return EnclosingMethodMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Exceptions} attribute} + * @since 23 + */ + public static AttributeMapper exceptions() { + return ExceptionsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code InnerClasses} attribute} + * @since 23 + */ + public static AttributeMapper innerClasses() { + return InnerClassesMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code LineNumberTable} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper lineNumberTable() { + return LineNumberTableMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code LocalVariableTable} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper localVariableTable() { + return LocalVariableTableMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code LocalVariableTypeTable} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper localVariableTypeTable() { + return LocalVariableTypeTableMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code MethodParameters} attribute} + * @since 23 + */ + public static AttributeMapper methodParameters() { + return MethodParametersMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Module} attribute} + * @since 23 + */ + public static AttributeMapper module() { + return ModuleMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModuleHashes} attribute} + * @since 23 + */ + public static AttributeMapper moduleHashes() { + return ModuleHashesMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModuleMainClass} attribute} + * @since 23 + */ + public static AttributeMapper moduleMainClass() { + return ModuleMainClassMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModulePackages} attribute} + * @since 23 + */ + public static AttributeMapper modulePackages() { + return ModulePackagesMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModuleResolution} attribute} + * @since 23 + */ + public static AttributeMapper moduleResolution() { + return ModuleResolutionMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModuleTarget} attribute} + * @since 23 + */ + public static AttributeMapper moduleTarget() { + return ModuleTargetMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code NestHost} attribute} + * @since 23 + */ + public static AttributeMapper nestHost() { + return NestHostMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code NestMembers} attribute} + * @since 23 + */ + public static AttributeMapper nestMembers() { + return NestMembersMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code PermittedSubclasses} attribute} + * @since 23 + */ + public static AttributeMapper permittedSubclasses() { + return PermittedSubclassesMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Record} attribute} + * @since 23 + */ + public static AttributeMapper record() { + return RecordMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeInvisibleAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeInvisibleAnnotations() { + return RuntimeInvisibleAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeInvisibleParameterAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeInvisibleParameterAnnotations() { + return RuntimeInvisibleParameterAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeInvisibleTypeAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeInvisibleTypeAnnotations() { + return RuntimeInvisibleTypeAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeVisibleAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeVisibleAnnotations() { + return RuntimeVisibleAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeVisibleParameterAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeVisibleParameterAnnotations() { + return RuntimeVisibleParameterAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeVisibleTypeAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeVisibleTypeAnnotations() { + return RuntimeVisibleTypeAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Signature} attribute} + * @since 23 + */ + public static AttributeMapper signature() { + return SignatureMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code SourceDebugExtension} attribute} + * @since 23 + */ + public static AttributeMapper sourceDebugExtension() { + return SourceDebugExtensionMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code SourceFile} attribute} + * @since 23 + */ + public static AttributeMapper sourceFile() { + return SourceFileMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code SourceID} attribute} + * @since 23 + */ + public static AttributeMapper sourceId() { + return SourceIDMapper.INSTANCE; + } /** - * {@return the attribute mapper for a standard attribute} - * - * @param name the name of the attribute to find + * {@return Attribute mapper for the {@code StackMapTable} attribute} + * @since 23 */ - public static AttributeMapper standardAttribute(Utf8Entry name) { - return _ATTR_MAP.get(name); + public static AttributeMapper stackMapTable() { + return StackMapTableMapper.INSTANCE; } /** - * All standard attribute mappers. + * {@return Attribute mapper for the {@code Synthetic} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 */ - public static final Set> PREDEFINED_ATTRIBUTES = Set.of( - ANNOTATION_DEFAULT, - BOOTSTRAP_METHODS, - CHARACTER_RANGE_TABLE, - CODE, - COMPILATION_ID, - CONSTANT_VALUE, - DEPRECATED, - ENCLOSING_METHOD, - EXCEPTIONS, - INNER_CLASSES, - LINE_NUMBER_TABLE, - LOCAL_VARIABLE_TABLE, - LOCAL_VARIABLE_TYPE_TABLE, - METHOD_PARAMETERS, - MODULE, - MODULE_HASHES, - MODULE_MAIN_CLASS, - MODULE_PACKAGES, - MODULE_RESOLUTION, - MODULE_TARGET, - NEST_HOST, - NEST_MEMBERS, - PERMITTED_SUBCLASSES, - RECORD, - RUNTIME_INVISIBLE_ANNOTATIONS, - RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, - RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, - RUNTIME_VISIBLE_ANNOTATIONS, - RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, - RUNTIME_VISIBLE_TYPE_ANNOTATIONS, - SIGNATURE, - SOURCE_DEBUG_EXTENSION, - SOURCE_FILE, - SOURCE_ID, - STACK_MAP_TABLE, - SYNTHETIC); - - private static final Map> _ATTR_MAP; - //no lambdas here as this is on critical JDK boostrap path - static { - var map = new HashMap>(64); - for (var am : PREDEFINED_ATTRIBUTES) { - map.put(AbstractPoolEntry.rawUtf8EntryFromStandardAttributeName(am.name()), am); - } - _ATTR_MAP = Collections.unmodifiableMap(map); + public static AttributeMapper synthetic() { + return SyntheticMapper.INSTANCE; } } diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 95195ef81bfe1..6c75c0385fa78 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -2611,7 +2611,7 @@ static long mismatch(MemorySegment srcSegment, long srcFromOffset, long srcToOff *
  • Segments obtained from the {@linkplain Arena#global() global arena};
  • *
  • Segments obtained from a raw address, using the * {@link MemorySegment#ofAddress(long)} factory; and
  • - *
  • Zero-length memory segments.
  • + *
  • {@link MemorySegment##wrapping-addresses Zero-length memory segments}.
  • * *

    * Conversely, a bounded lifetime is modeled with a segment scope that can be diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 9ec60d9a1522d..c564b7b69f6df 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -26,6 +26,7 @@ package java.lang.runtime; import java.lang.Enum.EnumDesc; +import java.lang.classfile.ClassBuilder; import java.lang.classfile.CodeBuilder; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; @@ -48,6 +49,8 @@ import java.lang.classfile.ClassFile; import java.lang.classfile.Label; import java.lang.classfile.instruction.SwitchCase; + +import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.misc.PreviewFeatures; import jdk.internal.vm.annotation.Stable; @@ -74,28 +77,38 @@ private SwitchBootstraps() {} private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static final boolean previewEnabled = PreviewFeatures.isEnabled(); - private static final MethodHandle NULL_CHECK; - private static final MethodHandle IS_ZERO; - private static final MethodHandle CHECK_INDEX; - private static final MethodHandle MAPPED_ENUM_LOOKUP; + + private static final MethodType TYPES_SWITCH_TYPE = MethodType.methodType(int.class, + Object.class, + int.class, + BiPredicate.class, + List.class); private static final MethodTypeDesc TYPES_SWITCH_DESCRIPTOR = MethodTypeDesc.ofDescriptor("(Ljava/lang/Object;ILjava/util/function/BiPredicate;Ljava/util/List;)I"); - - static { - try { - NULL_CHECK = LOOKUP.findStatic(Objects.class, "isNull", - MethodType.methodType(boolean.class, Object.class)); - IS_ZERO = LOOKUP.findStatic(SwitchBootstraps.class, "isZero", - MethodType.methodType(boolean.class, int.class)); - CHECK_INDEX = LOOKUP.findStatic(Objects.class, "checkIndex", - MethodType.methodType(int.class, int.class, int.class)); - MAPPED_ENUM_LOOKUP = LOOKUP.findStatic(SwitchBootstraps.class, "mappedEnumLookup", - MethodType.methodType(int.class, Enum.class, MethodHandles.Lookup.class, - Class.class, EnumDesc[].class, EnumMap.class)); - } - catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); + private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR = + MethodTypeDesc.ofDescriptor("(II)I"); + + private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;"); + + private static class StaticHolders { + private static final MethodHandle NULL_CHECK; + private static final MethodHandle IS_ZERO; + private static final MethodHandle MAPPED_ENUM_LOOKUP; + + static { + try { + NULL_CHECK = LOOKUP.findStatic(Objects.class, "isNull", + MethodType.methodType(boolean.class, Object.class)); + IS_ZERO = LOOKUP.findStatic(SwitchBootstraps.class, "isZero", + MethodType.methodType(boolean.class, int.class)); + MAPPED_ENUM_LOOKUP = LOOKUP.findStatic(SwitchBootstraps.class, "mappedEnumLookup", + MethodType.methodType(int.class, Enum.class, MethodHandles.Lookup.class, + Class.class, EnumDesc[].class, EnumMap.class)); + } + catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } } } @@ -163,14 +176,13 @@ public static CallSite typeSwitch(MethodHandles.Lookup lookup, || (!invocationType.returnType().equals(int.class)) || !invocationType.parameterType(1).equals(int.class)) throw new IllegalArgumentException("Illegal invocation type " + invocationType); - requireNonNull(labels); - Stream.of(labels).forEach(l -> verifyLabel(l, selectorType)); + for (Object l : labels) { // implicit null-check + verifyLabel(l, selectorType); + } MethodHandle target = generateTypeSwitch(lookup, selectorType, labels); - target = withIndexCheck(target, labels.length); - return new ConstantCallSite(target); } @@ -282,18 +294,17 @@ public static CallSite enumSwitch(MethodHandles.Lookup lookup, //else if (idx == 0) return mappingArray[selector.ordinal()]; //mapping array created lazily //else return "typeSwitch(labels)" MethodHandle body = - MethodHandles.guardWithTest(MethodHandles.dropArguments(NULL_CHECK, 0, int.class), + MethodHandles.guardWithTest(MethodHandles.dropArguments(StaticHolders.NULL_CHECK, 0, int.class), MethodHandles.dropArguments(MethodHandles.constant(int.class, -1), 0, int.class, Object.class), - MethodHandles.guardWithTest(MethodHandles.dropArguments(IS_ZERO, 1, Object.class), + MethodHandles.guardWithTest(MethodHandles.dropArguments(StaticHolders.IS_ZERO, 1, Object.class), generateTypeSwitch(lookup, invocationType.parameterType(0), labels), - MethodHandles.insertArguments(MAPPED_ENUM_LOOKUP, 1, lookup, enumClass, labels, new EnumMap()))); + MethodHandles.insertArguments(StaticHolders.MAPPED_ENUM_LOOKUP, 1, lookup, enumClass, labels, new EnumMap()))); target = MethodHandles.permuteArguments(body, MethodType.methodType(int.class, Object.class, int.class), 1, 0); } else { target = generateTypeSwitch(lookup, invocationType.parameterType(0), labels); } target = target.asType(invocationType); - target = withIndexCheck(target, labels.length); return new ConstantCallSite(target); } @@ -339,12 +350,6 @@ private static > int mappedEnumLookup(T value, MethodHandles.L return enumMap.map[value.ordinal()]; } - private static MethodHandle withIndexCheck(MethodHandle target, int labelsCount) { - MethodHandle checkIndex = MethodHandles.insertArguments(CHECK_INDEX, 1, labelsCount + 1); - - return MethodHandles.filterArguments(target, 1, checkIndex); - } - private static final class ResolvedEnumLabels implements BiPredicate { private final MethodHandles.Lookup lookup; @@ -407,6 +412,11 @@ private static Consumer generateTypeSwitchSkeleton(Class selecto int EXTRA_CLASS_LABELS = 3; return cb -> { + // Objects.checkIndex(RESTART_IDX, labelConstants + 1) + cb.iload(RESTART_IDX); + cb.loadConstant(labelConstants.length + 1); + cb.invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR); + cb.pop(); cb.aload(SELECTOR_OBJ); Label nonNullLabel = cb.newLabel(); cb.if_nonnull(nonNullLabel); @@ -621,7 +631,7 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas List> enumDescs = new ArrayList<>(); List> extraClassLabels = new ArrayList<>(); - byte[] classBytes = ClassFile.of().build(ClassDesc.of(typeSwitchClassName(caller.lookupClass())), + byte[] classBytes = ClassFile.of().build(ReferenceClassDescImpl.ofValidatedBinaryName(typeSwitchClassName(caller.lookupClass())), clb -> { clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC) .withMethodBody("typeSwitch", @@ -636,12 +646,8 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas lookup = caller.defineHiddenClass(classBytes, true, NESTMATE, STRONG); MethodHandle typeSwitch = lookup.findStatic(lookup.lookupClass(), "typeSwitch", - MethodType.methodType(int.class, - Object.class, - int.class, - BiPredicate.class, - List.class)); - typeSwitch = MethodHandles.insertArguments(typeSwitch, 2, new ResolvedEnumLabels(caller, enumDescs.toArray(EnumDesc[]::new)), + TYPES_SWITCH_TYPE); + typeSwitch = MethodHandles.insertArguments(typeSwitch, 2, new ResolvedEnumLabels(caller, enumDescs.toArray(new EnumDesc[0])), List.copyOf(extraClassLabels)); typeSwitch = MethodHandles.explicitCastArguments(typeSwitch, MethodType.methodType(int.class, diff --git a/src/java.base/share/classes/java/net/Inet4Address.java b/src/java.base/share/classes/java/net/Inet4Address.java index bef9fa9500dcb..16cea2d10d797 100644 --- a/src/java.base/share/classes/java/net/Inet4Address.java +++ b/src/java.base/share/classes/java/net/Inet4Address.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -70,9 +70,9 @@ *

    When only one part is given, the value is stored directly in * the network address without any byte rearrangement. * - *

    These forms support parts specified in decimal format only. - * For example, the following forms are supported by methods capable - * of parsing textual representations of IPv4 addresses: + *

    For example, the following (decimal) forms are supported by the methods + * {@link Inet4Address#ofLiteral(String)} and {@link InetAddress#getByName(String)} + * which are capable of parsing textual representations of IPv4 addresses: * {@snippet : * // Dotted-decimal 'd.d.d.d' form with four part address literal * InetAddress.getByName("007.008.009.010"); // ==> /7.8.9.10 @@ -93,8 +93,16 @@ * Inet4Address.ofLiteral("02130706689"); // ==> /127.0.1.1 * } * + *

    The above forms adhere to "strict" decimal-only syntax. + * Additionally, the {@link Inet4Address#ofPosixLiteral(String)} + * method implements a POSIX {@code inet_addr} compatible "loose" + * parsing algorithm, allowing octal and hexadecimal address segments. + * Please refer to + * RFC 6943: Issues in Identifier Comparison for Security + * Purposes. Aside from {@code Inet4Address.ofPosixLiteral(String)}, all methods only + * support strict decimal parsing. *

    For methods that return a textual representation as output - * value, the first form, i.e. a dotted-quad string, is used. + * value, the first form, i.e. a dotted-quad string in strict decimal notation, is used. * *

    The Scope of a Multicast Address

    * @@ -112,6 +120,8 @@ * RFC 2365: Administratively Scoped IP Multicast * @spec https://www.rfc-editor.org/info/rfc790 * RFC 790: Assigned numbers + * @spec https://www.rfc-editor.org/rfc/rfc6943.html#section-3.1.1 + * RFC 6943: Issues in Identifier Comparison for Security Purposes * @since 1.4 */ @@ -180,6 +190,72 @@ public static Inet4Address ofLiteral(String ipv4AddressLiteral) { return parseAddressString(ipv4AddressLiteral, true); } + /** + * Creates an {@code Inet4Address} based on the provided {@linkplain + * Inet4Address##format-posix textual representation of an IPv4 address in + * POSIX {@code inet_addr} compatible form}. + *

    The method {@code ofPosixLiteral} + * implements + * POSIX {@code inet_addr} compatible parsing algorithm, allowing + * octal and hexadecimal address segments. {@code "0"} is the prefix + * for octal numbers, {@code "0x"} and {@code "0X"} are the prefixes + * for hexadecimal numbers. Non-zero address segments that start from + * non-zero digits are parsed as decimal numbers. The following + * (non-decimal) forms are supported by this method: + * {@snippet : + * // Dotted-quad 'x.x.x.x' form with four part address literal + * Inet4Address.ofPosixLiteral("0177.0.0.1"); // ==> /127.0.0.1 + * Inet4Address.ofPosixLiteral("0x7F.0.0.1"); // ==> /127.0.0.1 + * + * // Dotted-triple 'x.x.x' form with three part address literal, + * // the last part is placed in the rightmost two bytes + * // of the constructed address + * Inet4Address.ofPosixLiteral("0177.0.0402"); // ==> /127.0.1.2 + * Inet4Address.ofPosixLiteral("0x7F.0.0x102"); // ==> /127.0.1.2 + * + * // Dotted-double 'x.x' form with two part address literal, + * // the last part is placed in the rightmost three bytes + * // of the constructed address + * Inet4Address.ofPosixLiteral("0177.0201003"); // ==> /127.1.2.3 + * Inet4Address.ofPosixLiteral("0x7F.0x10203"); // ==> /127.1.2.3 + * Inet4Address.ofPosixLiteral("127.66051"); // ==> /127.1.2.3 + * + * // Dotless 'x' form with one value that is stored directly in + * // the constructed address bytes without any rearrangement + * Inet4Address.ofPosixLiteral("0100401404"); // ==> /1.2.3.4 + * Inet4Address.ofPosixLiteral("0x1020304"); // ==> /1.2.3.4 + * Inet4Address.ofPosixLiteral("16909060"); // ==> /1.2.3.4 + * } + *

    If the provided IPv4 address literal cannot represent a + * valid IPv4 address in {@linkplain Inet4Address##format-posix + * POSIX form} an {@code IllegalArgumentException} is thrown. + *

    This method doesn't block, i.e. no hostname lookup is performed. + * + * @apiNote + * This method produces different results compared to {@linkplain Inet4Address#ofLiteral} + * when {@code posixIPAddressLiteral} parameter contains address segments with + * leading zeroes. An address segment with a leading zero is always parsed as an octal + * number by this method, therefore {@code 0255} (octal) will be parsed as + * {@code 173} (decimal). On the other hand, {@link Inet4Address#ofLiteral + * Inet4Address.ofLiteral} ignores leading zeros, parses all numbers as decimal and produces + * {@code 255}. Where this method would parse {@code 0256.0256.0256.0256} (octal) and + * produce {@code 174.174.174.174} (decimal) in four dotted quad notation, + * {@link Inet4Address#ofLiteral Inet4Address.ofLiteral} will throw + * {@code IllegalArgumentException}. + * + * @param posixIPAddressLiteral a textual representation of an IPv4 address. + * @return an {@link Inet4Address} object with no hostname set, and constructed + * from the provided IPv4 address literal. + * @throws IllegalArgumentException if the {@code posixIPAddressLiteral} cannot be + * parsed as an IPv4 address literal. + * @throws NullPointerException if the {@code posixIPAddressLiteral} is {@code null}. + * @since 23 + */ + public static Inet4Address ofPosixLiteral(String posixIPAddressLiteral) { + Objects.requireNonNull(posixIPAddressLiteral); + return parseAddressStringPosix(posixIPAddressLiteral); + } + /** * Parses the given string as an IPv4 address literal. * If the given {@code addressLiteral} string cannot be parsed as an IPv4 address literal @@ -212,6 +288,45 @@ static Inet4Address parseAddressString(String addressLiteral, boolean throwIAE) return new Inet4Address(null, addrBytes); } + /** + * Parses the given string as an IPv4 address literal in + * {@linkplain Inet4Address##format-posix POSIX form.} + * + *

    If the given {@code addressLiteral} string cannot be parsed as an IPv4 address literal + * in POSIX form and {@code throwIAE} is {@code false}, {@code null} is returned. + * If the given {@code addressLiteral} string cannot be parsed as an IPv4 address literal + * and {@code throwIAE} is {@code true}, an {@code IllegalArgumentException} + * is thrown. + * + * @apiNote + * This method produces different results compared to {@linkplain Inet4Address#parseAddressString} + * when {@code addressLiteral} parameter contains address segments with leading + * zeroes. An address segment with a leading zero is always parsed as an octal + * number by this method, therefore {@code 0255} (octal) will be parsed as + * {@code 173} (decimal). On the other hand, {@link Inet4Address#parseAddressString} + * ignores leading zeros, parses all numbers as decimal and produces {@code 255}. + * Where this method would parse {@code 0256.0256.0256.0256} (octal) and produce + * {@code 174.174.174.174} (decimal) in four dotted quad notation, {@linkplain + * Inet4Address#parseAddressString} will either throw {@code IllegalArgumentException} + * or return {@code null}, depending on the value of {@code throwIAE}. + * + * @param addressLiteral IPv4 address literal to parse + * @param throwIAE whether to throw {@code IllegalArgumentException} if the + * given {@code addressLiteral} string cannot be parsed as + * an IPv4 address literal. + * @return {@code Inet4Address} object constructed from the address literal; + * or {@code null} if the literal cannot be parsed as an IPv4 address + * @throws IllegalArgumentException if the given {@code addressLiteral} string + * cannot be parsed as an IPv4 address literal and {@code throwIAE} is {@code true}. + */ + private static Inet4Address parseAddressStringPosix(String addressLiteral) { + byte [] parsedBytes = IPAddressUtil.parseBsdLiteralV4(addressLiteral); + if (parsedBytes == null) { + throw IPAddressUtil.invalidIpAddressLiteral(addressLiteral); + } + return new Inet4Address(null, parsedBytes); + } + /** * Replaces the object to be serialized with an InetAddress object. * diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index 534553a99f38b..7e0c39f9111ee 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -1722,6 +1722,7 @@ static InetAddress[] getAllByName0 (String host, boolean check) * @throws NullPointerException if the {@code ipAddressLiteral} is {@code null}. * @see Inet4Address#ofLiteral(String) * @see Inet6Address#ofLiteral(String) + * @see Inet4Address#ofPosixLiteral(String) * @since 22 */ public static InetAddress ofLiteral(String ipAddressLiteral) { diff --git a/src/java.base/share/classes/java/net/SocketOptions.java b/src/java.base/share/classes/java/net/SocketOptions.java index 340530d8cef8f..f534e0287d7e9 100644 --- a/src/java.base/share/classes/java/net/SocketOptions.java +++ b/src/java.base/share/classes/java/net/SocketOptions.java @@ -190,6 +190,13 @@ public interface SocketOptions { /** * See {@link StandardSocketOptions#SO_LINGER} for description of this socket option. + *

    + * Set the value to {@code Boolean.FALSE} or an integer less than {@code 0} with + * {@link #setOption(int, Object)} to disable this option. An integer greater than or equal to + * {@code 0} will enable the option and will represent the linger interval. + *

    + * If this option is enabled then {@link #getOption(int)} will return an integer value + * representing the linger interval, else the return value will be {@code Boolean.FALSE}. * * @see Socket#setSoLinger * @see Socket#getSoLinger diff --git a/src/java.base/share/classes/java/security/SecureRandom.java b/src/java.base/share/classes/java/security/SecureRandom.java index 6a1683e993c96..4242b5da04a0a 100644 --- a/src/java.base/share/classes/java/security/SecureRandom.java +++ b/src/java.base/share/classes/java/security/SecureRandom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package java.security; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; import sun.security.jca.GetInstance; import sun.security.jca.GetInstance.Instance; import sun.security.jca.Providers; @@ -149,10 +148,6 @@ * @since 1.1 */ -@RandomGeneratorProperties( - name = "SecureRandom", - isStochastic = true -) public class SecureRandom extends java.util.Random { private static final Debug pdebug = diff --git a/src/java.base/share/classes/java/util/Random.java b/src/java.base/share/classes/java/util/Random.java index b1163db0b18c9..661a29e303be3 100644 --- a/src/java.base/share/classes/java/util/Random.java +++ b/src/java.base/share/classes/java/util/Random.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2024, 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,8 +32,6 @@ import java.util.stream.IntStream; import java.util.stream.LongStream; -import jdk.internal.util.random.RandomSupport.*; - import static jdk.internal.util.random.RandomSupport.*; import jdk.internal.misc.Unsafe; @@ -77,11 +75,6 @@ * @author Frank Yellin * @since 1.0 */ -@RandomGeneratorProperties( - name = "Random", - i = 48, j = 0, k = 0, - equidistribution = 0 -) public class Random implements RandomGenerator, java.io.Serializable { /** diff --git a/src/java.base/share/classes/java/util/SplittableRandom.java b/src/java.base/share/classes/java/util/SplittableRandom.java index 4242322d68757..cb1801f56805d 100644 --- a/src/java.base/share/classes/java/util/SplittableRandom.java +++ b/src/java.base/share/classes/java/util/SplittableRandom.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, 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,7 +33,6 @@ import java.util.stream.Stream; import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport.AbstractSplittableGenerator; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A generator of uniform pseudorandom values (with period 264) @@ -87,11 +86,6 @@ * @author Doug Lea * @since 1.8 */ -@RandomGeneratorProperties( - name = "SplittableRandom", - i = 64, j = 0, k = 0, - equidistribution = 1 -) public final class SplittableRandom implements RandomGenerator, SplittableGenerator { /* diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java index dd1ea70195b3b..baa4c0e4f73af 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java @@ -85,12 +85,6 @@ * @since 1.7 * @author Doug Lea */ - -@RandomGeneratorProperties( - name = "ThreadLocalRandom", - i = 64, j = 0, k = 0, - equidistribution = 1 -) public final class ThreadLocalRandom extends Random { /* * This class implements the java.util.Random API (and subclasses diff --git a/src/java.base/share/classes/java/util/random/RandomGeneratorFactory.java b/src/java.base/share/classes/java/util/random/RandomGeneratorFactory.java index a7c063713684b..030f7f70a0a4b 100644 --- a/src/java.base/share/classes/java/util/random/RandomGeneratorFactory.java +++ b/src/java.base/share/classes/java/util/random/RandomGeneratorFactory.java @@ -25,24 +25,30 @@ package java.util.random; -import java.lang.reflect.Constructor; +import jdk.internal.random.L128X1024MixRandom; +import jdk.internal.random.L128X128MixRandom; +import jdk.internal.random.L128X256MixRandom; +import jdk.internal.random.L32X64MixRandom; +import jdk.internal.random.L64X1024MixRandom; +import jdk.internal.random.L64X128MixRandom; +import jdk.internal.random.L64X128StarStarRandom; +import jdk.internal.random.L64X256MixRandom; +import jdk.internal.random.Xoroshiro128PlusPlus; +import jdk.internal.random.Xoshiro256PlusPlus; + import java.math.BigInteger; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; +import java.security.SecureRandom; import java.util.Objects; -import java.util.function.Function; import java.util.Map; +import java.util.Random; +import java.util.SplittableRandom; +import java.util.concurrent.ThreadLocalRandom; import java.util.random.RandomGenerator.ArbitrarilyJumpableGenerator; import java.util.random.RandomGenerator.JumpableGenerator; import java.util.random.RandomGenerator.LeapableGenerator; import java.util.random.RandomGenerator.SplittableGenerator; import java.util.random.RandomGenerator.StreamableGenerator; -import java.util.ServiceLoader; -import java.util.ServiceLoader.Provider; -import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * This is a factory class for generating multiple random number generators @@ -107,137 +113,268 @@ * */ public final class RandomGeneratorFactory { - /** - * Instance provider class of random number algorithm. - */ - private final Provider provider; - /** - * Provider RandomGeneratorProperties annotation. - */ - private volatile RandomGeneratorProperties properties; + private static final String DEFAULT_ALGORITHM = "L32X64MixRandom"; - /** - * Default provider constructor. - */ - private volatile Constructor ctor; + private record RandomGeneratorProperties( + Class rgClass, + String name, + String group, + int i, + int j, + int k, + int equidistribution, + int flags) { - /** - * Provider constructor with long seed. - */ - private Constructor ctorLong; - - /** - * Provider constructor with byte[] seed. - */ - private Constructor ctorBytes; + /* single bit masks composable with operator | */ + private static final int INSTANTIABLE = 1 << 0; + private static final int LONG_SEED = 1 << 1; + private static final int BYTE_ARRAY_SEED = 1 << 2; + private static final int STOCHASTIC = 1 << 3; + private static final int HARDWARE = 1 << 4; + private static final int DEPRECATED = 1 << 5; + private static final int ALL_CONSTRUCTORS = INSTANTIABLE | LONG_SEED | BYTE_ARRAY_SEED; - private static class FactoryMapHolder { - static final Map> FACTORY_MAP = createFactoryMap(); + private static final Map FACTORY_MAP = createFactoryMap(); /** - * Returns the factory map, lazily constructing map on first use. + * Returns the factory map, lazily constructing it on first use. + *

    Although {@link ThreadLocalRandom} can only be accessed via + * {@link ThreadLocalRandom#current()}, a map entry is added nevertheless + * to record its properties that are otherwise not documented + * anywhere else. + *

    Currently, no algorithm is deprecated. * - * @return Map of RandomGeneratorFactory classes. + * @return Map of RandomGeneratorProperties. */ - private static Map> createFactoryMap() { - FactoryMapHolder.class.getModule().addUses(RandomGenerator.class); - return ServiceLoader - .load(RandomGenerator.class, ClassLoader.getPlatformClassLoader()) - .stream() - .filter(p -> !p.type().isInterface()) - .collect(Collectors.toMap(p -> p.type().getSimpleName(), Function.identity())); + private static Map createFactoryMap() { + return Map.ofEntries( + entry(SecureRandom.class, "SecureRandom", "Legacy", + 0, 0, 0, Integer.MAX_VALUE, + INSTANTIABLE | BYTE_ARRAY_SEED | STOCHASTIC | deprecationBit(SecureRandom.class)), + entry(Random.class, "Random", "Legacy", + 48, 0, 0, 0, + INSTANTIABLE | LONG_SEED | deprecationBit(Random.class)), + entry(SplittableRandom.class, "SplittableRandom", "Legacy", + 64, 0, 0, 1, + INSTANTIABLE | LONG_SEED | deprecationBit(SplittableRandom.class)), + entry(L32X64MixRandom.class, "L32X64MixRandom", "LXM", + 64, 1, 32, 1, + ALL_CONSTRUCTORS), + entry(L64X128MixRandom.class, "L64X128MixRandom", "LXM", + 128, 1, 64, 2, + ALL_CONSTRUCTORS), + entry(L64X128StarStarRandom.class, "L64X128StarStarRandom", "LXM", + 128, 1, 64, 2, + ALL_CONSTRUCTORS), + entry(L64X256MixRandom.class, "L64X256MixRandom", "LXM", + 256, 1, 64, 4, + ALL_CONSTRUCTORS), + entry(L64X1024MixRandom.class, "L64X1024MixRandom", "LXM", + 1024, 1, 64, 16, + ALL_CONSTRUCTORS), + entry(L128X128MixRandom.class, "L128X128MixRandom", "LXM", + 128, 1, 128, 1, + ALL_CONSTRUCTORS), + entry(L128X256MixRandom.class, "L128X256MixRandom", "LXM", + 256, 1, 128, 1, + ALL_CONSTRUCTORS), + entry(L128X1024MixRandom.class, "L128X1024MixRandom", "LXM", + 1024, 1, 128, 1, + ALL_CONSTRUCTORS), + entry(Xoroshiro128PlusPlus.class, "Xoroshiro128PlusPlus", "Xoroshiro", + 128, 1, 0, 1, + ALL_CONSTRUCTORS), + entry(Xoshiro256PlusPlus.class, "Xoshiro256PlusPlus", "Xoshiro", + 256, 1, 0, 3, + ALL_CONSTRUCTORS), + entry(ThreadLocalRandom.class, "ThreadLocalRandom", "Legacy", + 64, 0, 0, 1, + deprecationBit(ThreadLocalRandom.class)) + ); + } + + private static Map.Entry entry( + Class rgClass, String name, String group, + int i, int j, int k, int equidistribution, + int flags) { + return Map.entry(name, + new RandomGeneratorProperties(rgClass, name, group, + i, j, k, equidistribution, + flags)); + } + + private static int deprecationBit(Class rgClass) { + return rgClass.isAnnotationPresent(Deprecated.class) ? DEPRECATED : 0; + } + + private RandomGenerator create() { + return switch (name) { + case "Random" -> new Random(); + case "SecureRandom" -> new SecureRandom(); + case "SplittableRandom" -> new SplittableRandom(); + case "L32X64MixRandom" -> new L32X64MixRandom(); + case "L64X128MixRandom" -> new L64X128MixRandom(); + case "L64X128StarStarRandom" -> new L64X128StarStarRandom(); + case "L64X256MixRandom" -> new L64X256MixRandom(); + case "L64X1024MixRandom" -> new L64X1024MixRandom(); + case "L128X128MixRandom" -> new L128X128MixRandom(); + case "L128X256MixRandom" -> new L128X256MixRandom(); + case "L128X1024MixRandom" -> new L128X1024MixRandom(); + case "Xoroshiro128PlusPlus" -> new Xoroshiro128PlusPlus(); + case "Xoshiro256PlusPlus" -> new Xoshiro256PlusPlus(); + default -> throw new InternalError("should not happen"); + }; + } + + private RandomGenerator create(long seed) { + if (isInstantiable() && (flags & LONG_SEED) == 0) { + throw new UnsupportedOperationException("Random algorithm " + + name + " does not support a long seed"); + } + return switch (name) { + case "Random" -> new Random(seed); + case "SplittableRandom" -> new SplittableRandom(seed); + case "L32X64MixRandom" -> new L32X64MixRandom(seed); + case "L64X128MixRandom" -> new L64X128MixRandom(seed); + case "L64X128StarStarRandom" -> new L64X128StarStarRandom(seed); + case "L64X256MixRandom" -> new L64X256MixRandom(seed); + case "L64X1024MixRandom" -> new L64X1024MixRandom(seed); + case "L128X128MixRandom" -> new L128X128MixRandom(seed); + case "L128X256MixRandom" -> new L128X256MixRandom(seed); + case "L128X1024MixRandom" -> new L128X1024MixRandom(seed); + case "Xoroshiro128PlusPlus" -> new Xoroshiro128PlusPlus(seed); + case "Xoshiro256PlusPlus" -> new Xoshiro256PlusPlus(seed); + default -> throw new InternalError("should not happen"); + }; + } + + private RandomGenerator create(byte[] seed) { + if (isInstantiable() && (flags & BYTE_ARRAY_SEED) == 0) { + throw new UnsupportedOperationException("Random algorithm " + + name + " does not support a byte[] seed"); + } + return switch (name) { + case "SecureRandom" -> new SecureRandom(seed); + case "L32X64MixRandom" -> new L32X64MixRandom(seed); + case "L64X128MixRandom" -> new L64X128MixRandom(seed); + case "L64X128StarStarRandom" -> new L64X128StarStarRandom(seed); + case "L64X256MixRandom" -> new L64X256MixRandom(seed); + case "L64X1024MixRandom" -> new L64X1024MixRandom(seed); + case "L128X128MixRandom" -> new L128X128MixRandom(seed); + case "L128X256MixRandom" -> new L128X256MixRandom(seed); + case "L128X1024MixRandom" -> new L128X1024MixRandom(seed); + case "Xoroshiro128PlusPlus" -> new Xoroshiro128PlusPlus(seed); + case "Xoshiro256PlusPlus" -> new Xoshiro256PlusPlus(seed); + default -> throw new InternalError("should not happen"); + }; + } + + private boolean isStochastic() { + return (flags & STOCHASTIC) != 0; + } + + private boolean isHardware() { + return (flags & HARDWARE) != 0; + } + + private boolean isInstantiable() { + return (flags & INSTANTIABLE) != 0; + } + + private boolean isDeprecated() { + return (flags & DEPRECATED) != 0; + } + + private BigInteger period() { + /* + * 0 if i = j = k = 0 + * (2^i - j) 2^k otherwise + */ + return i == 0 && j == 0 && k == 0 + ? BigInteger.ZERO + : BigInteger.ONE.shiftLeft(i).subtract(BigInteger.valueOf(j)).shiftLeft(k); + } + + private int stateBits() { + return i == 0 && k == 0 ? Integer.MAX_VALUE : i + k; } } /** - * Private constructor. - * - * @param provider Provider class to wrap. + * Random generator properties. */ - private RandomGeneratorFactory(Provider provider) { - this.provider = provider; - } + private final RandomGeneratorProperties properties; /** - * Returns the factory map, lazily constructing map on first call. + * Private constructor. * - * @return Map of RandomGeneratorFactory classes. + * @param properties Random generator properties. */ - private static Map> getFactoryMap() { - return FactoryMapHolder.FACTORY_MAP; + private RandomGeneratorFactory(RandomGeneratorProperties properties) { + this.properties = properties; } /** - * Return the annotation for the specified provider. + * Returns the factory map, lazily constructing the map on first call. * - * @return RandomGeneratorProperties annotation for the specified provider. + * @return Map of random generator classes. */ - private RandomGeneratorProperties getProperties() { - if (properties == null) { - synchronized (provider) { - if (properties == null) { - properties = provider.type().getDeclaredAnnotation(RandomGeneratorProperties.class); - Objects.requireNonNull(properties, provider.type() + " missing annotation"); - } - } - } - - return properties; + private static Map getFactoryMap() { + return RandomGeneratorProperties.FACTORY_MAP; } /** - * Return true if the provider is a subclass of the category. + * Return true if the random generator class is a subclass of the category. * * @param category Interface category, sub-interface of {@link RandomGenerator}. * - * @return true if the provider is a subclass of the category. + * @return true if the random generator class is a subclass of the category. */ private boolean isSubclass(Class category) { - return isSubclass(category, provider); + return isSubclass(category, properties.rgClass()); } /** - * Return true if the provider is a subclass of the category. + * Return true if rgClass is a subclass of the category. * * @param category Interface category, sub-interface of {@link RandomGenerator}. - * @param provider Provider that is being filtered. + * @param rgClass Class that is being filtered. * - * @return true if the provider is a subclass of the category. + * @return true if rgClass is a subclass of the category. */ private static boolean isSubclass(Class category, - Provider provider) { - return provider != null && category.isAssignableFrom(provider.type()); + Class rgClass) { + return rgClass != null && category.isAssignableFrom(rgClass); } /** - * Returns the provider matching name and category. - * - * @param name Name of RandomGenerator - * @param category Interface category, sub-interface of {@link RandomGenerator}. + * Returns a RandomGeneratorProperties instance matching name and category. * - * @return A provider matching name and category. - * - * @throws IllegalArgumentException if provider is not a subclass of category. - */ - private static Provider findProvider(String name, - Class category) - throws IllegalArgumentException { - Map> fm = getFactoryMap(); - Provider provider = fm.get(name); - if (provider == null) { + * @param name Name of RandomGenerator + * @param category Interface category, sub-interface of {@link RandomGenerator}. + * @return A RandomGeneratorProperties instance matching name and category. + * @throws IllegalArgumentException if the resulting type is not a subclass of category. + */ + private static RandomGeneratorProperties findClass(String name, + Class category) throws IllegalArgumentException { + RandomGeneratorProperties properties = name != null + ? getFactoryMap().get(name) + : null; + if (properties == null || !properties.isInstantiable()) { throw new IllegalArgumentException("No implementation of the random number generator algorithm \"" + - name + - "\" is available"); - } else if (!isSubclass(category, provider)) { + name + + "\" is available"); + } + if (!isSubclass(category, properties.rgClass())) { throw new IllegalArgumentException("The random number generator algorithm \"" + - name + - "\" is not implemented with the interface \"" + - category.getSimpleName() + - "\""); + name + + "\" is not implemented with the interface \"" + + category.getSimpleName() + + "\""); } - return provider; + return properties; } /** @@ -255,8 +392,8 @@ private static Provider findProvider(String name, static T of(String name, Class category) throws IllegalArgumentException { @SuppressWarnings("unchecked") - T uncheckedRandomGenerator = (T)findProvider(name, category).get(); - return uncheckedRandomGenerator; + T instance = (T) findClass(name, category).create(); + return instance; } /** @@ -273,68 +410,7 @@ static T of(String name, Class category) */ static RandomGeneratorFactory factoryOf(String name, Class category) throws IllegalArgumentException { - Provider uncheckedProvider = findProvider(name, category); - return new RandomGeneratorFactory<>(uncheckedProvider); - } - - /** - * Fetch the required constructors for class of random number algorithm. - * - * @param randomGeneratorClass class of random number algorithm (provider) - */ - private void getConstructors(Class randomGeneratorClass) { - if (ctor == null) { - synchronized (provider) { - if (ctor == null) { - PrivilegedExceptionAction[]> ctorAction = randomGeneratorClass::getConstructors; - try { - @SuppressWarnings("removal") - Constructor[] ctors = AccessController.doPrivileged(ctorAction); - - Constructor tmpCtor = null; - Constructor tmpCtorLong = null; - Constructor tmpCtorBytes = null; - - - for (Constructor ctorGeneric : ctors) { - @SuppressWarnings("unchecked") - Constructor ctorSpecific = (Constructor) ctorGeneric; - final Class[] parameterTypes = ctorSpecific.getParameterTypes(); - - if (parameterTypes.length == 0) { - tmpCtor = ctorSpecific; - } else if (parameterTypes.length == 1) { - Class argType = parameterTypes[0]; - - if (argType == long.class) { - tmpCtorLong = ctorSpecific; - } else if (argType == byte[].class) { - tmpCtorBytes = ctorSpecific; - } - } - } - - if (tmpCtor == null) { - throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor"); - } - - // Store specialized constructors first, guarded by ctor - ctorBytes = tmpCtorBytes; - ctorLong = tmpCtorLong; - ctor = tmpCtor; - } catch (PrivilegedActionException ex) { - // Do nothing - } - } - } - } - } - - /** - * Ensure all the required constructors are fetched. - */ - private void ensureConstructors() { - getConstructors(provider.type()); + return new RandomGeneratorFactory<>(findClass(name, category)); } /** @@ -355,7 +431,7 @@ public static RandomGeneratorFactory of(String na Objects.requireNonNull(name); @SuppressWarnings("unchecked") RandomGeneratorFactory factory = - (RandomGeneratorFactory)factoryOf(name, RandomGenerator.class); + (RandomGeneratorFactory) factoryOf(name, RandomGenerator.class); return factory; } @@ -369,23 +445,21 @@ public static RandomGeneratorFactory of(String na * @return a {@link RandomGeneratorFactory} */ public static RandomGeneratorFactory getDefault() { - return factoryOf("L32X64MixRandom", RandomGenerator.class); + return factoryOf(DEFAULT_ALGORITHM, RandomGenerator.class); } /** * Returns a non-empty stream of available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}. - *

    + * * RandomGenerators that are marked as deprecated are not included in the result. * * @return a non-empty stream of all available {@link RandomGeneratorFactory RandomGeneratorFactory(s)}. */ public static Stream> all() { - Map> fm = getFactoryMap(); - return fm.values() - .stream() - .filter(p -> !p.type().isAnnotationPresent(Deprecated.class) && - p.type().isAnnotationPresent(RandomGeneratorProperties.class)) - .map(RandomGeneratorFactory::new); + return getFactoryMap().values() + .stream() + .filter(p -> p.isInstantiable() && !p.isDeprecated()) + .map(RandomGeneratorFactory::new); } /** @@ -395,7 +469,7 @@ public static Stream> all() { * @return Name of the algorithm. */ public String name() { - return provider.type().getSimpleName(); + return properties.name(); } /** @@ -405,7 +479,7 @@ public String name() { * @return Group name of the algorithm. */ public String group() { - return getProperties().group(); + return properties.group(); } /** @@ -416,11 +490,7 @@ public String group() { * to maintain state of seed. */ public int stateBits() { - RandomGeneratorProperties properties = getProperties(); - int i = properties.i(); - int k = properties.k(); - - return i == 0 && k == 0 ? Integer.MAX_VALUE : i + k; + return properties.stateBits(); } /** @@ -429,7 +499,7 @@ public int stateBits() { * @return the equidistribution of the algorithm. */ public int equidistribution() { - return getProperties().equidistribution(); + return properties.equidistribution(); } /** @@ -440,16 +510,7 @@ public int equidistribution() { * @return BigInteger period. */ public BigInteger period() { - RandomGeneratorProperties properties = getProperties(); - int i = properties.i(); - int j = properties.j(); - int k = properties.k(); - - if (i == 0 && j == 0 && k == 0) { - return BigInteger.ZERO; - } else { - return BigInteger.ONE.shiftLeft(i).subtract(BigInteger.valueOf(j)).shiftLeft(k); - } + return properties.period(); } /** @@ -460,7 +521,7 @@ public BigInteger period() { * @return true if random generator is statistical. */ public boolean isStatistical() { - return !getProperties().isStochastic(); + return !properties.isStochastic(); } /** @@ -470,7 +531,7 @@ public boolean isStatistical() { * @return true if random generator is stochastic. */ public boolean isStochastic() { - return getProperties().isStochastic(); + return properties.isStochastic(); } /** @@ -480,7 +541,7 @@ public boolean isStochastic() { * @return true if random generator is generated by hardware. */ public boolean isHardware() { - return getProperties().isHardware(); + return properties.isHardware(); } /** @@ -547,66 +608,64 @@ public boolean isStreamable() { * marked for deprecation */ public boolean isDeprecated() { - return provider.type().isAnnotationPresent(Deprecated.class); + return properties.isDeprecated(); } /** - * Create an instance of {@link RandomGenerator} based on + * Create an instance of {@link RandomGenerator} based on the * algorithm chosen. * - * @return new in instance of {@link RandomGenerator}. - * + * @return new instance of {@link RandomGenerator}. */ public T create() { - try { - ensureConstructors(); - return ctor.newInstance(); - } catch (Exception ex) { - // Should never happen. - throw new IllegalStateException("Random algorithm " + name() + " is missing a default constructor", ex); - } + @SuppressWarnings("unchecked") + T instance = (T) properties.create(); + return instance; } /** - * Create an instance of {@link RandomGenerator} based on - * algorithm chosen - * providing a starting long seed. If long seed is not supported by an - * algorithm then the no argument form of create is used. + * Create an instance of {@link RandomGenerator} based on the + * algorithm chosen, + * and the provided {@code seed}. + * If the {@link RandomGenerator} doesn't support instantiation through + * a {@code seed} of type {@code long} then this method throws + * an {@link UnsupportedOperationException}. * * @param seed long random seed value. * - * @return new in instance of {@link RandomGenerator}. + * @return new instance of {@link RandomGenerator}. + * + * @throws UnsupportedOperationException + * if a {@code seed} of type {@code long} in not supported. */ public T create(long seed) { - try { - ensureConstructors(); - return ctorLong.newInstance(seed); - } catch (Exception ex) { - return create(); - } + @SuppressWarnings("unchecked") + T instance = (T) properties.create(seed); + return instance; } /** - * Create an instance of {@link RandomGenerator} based on - * algorithm chosen - * providing a starting byte[] seed. If byte[] seed is not supported by an - * algorithm then the no - * argument form of create is used. + * Create an instance of {@link RandomGenerator} based on the + * algorithm chosen, + * and the provided {@code seed}. + * If the {@link RandomGenerator} doesn't support instantiation through + * a {@code seed} of type {@code byte[]} then this method throws + * an {@link UnsupportedOperationException}. * * @param seed byte array random seed value. * - * @return new in instance of {@link RandomGenerator}. + * @return new instance of {@link RandomGenerator}. + * + * @throws UnsupportedOperationException + * if a {@code seed} of type {@code byte[]} in not supported. * * @throws NullPointerException if seed is null. */ public T create(byte[] seed) { Objects.requireNonNull(seed, "seed must not be null"); - try { - ensureConstructors(); - return ctorBytes.newInstance(seed); - } catch (Exception ex) { - return create(); - } + @SuppressWarnings("unchecked") + T instance = (T) properties.create(seed); + return instance; } } diff --git a/src/java.base/share/classes/java/util/random/package-info.java b/src/java.base/share/classes/java/util/random/package-info.java index 2e16b319f44bb..9f9df0ff39533 100644 --- a/src/java.base/share/classes/java/util/random/package-info.java +++ b/src/java.base/share/classes/java/util/random/package-info.java @@ -81,8 +81,8 @@ *

    {@code import java.util.random.*;}
    * * Then one can choose a specific implementation by giving the name of a generator - * algorithm to the static method {@link RandomGenerator#of}, in which case the - * no-arguments constructor for that implementation is used: + * algorithm to the static method {@link RandomGenerator#of}, in which case + * a {@link RandomGenerator} is constructed without any seed value: * *
    {@code RandomGenerator g = RandomGenerator.of("L64X128MixRandom");}
    * @@ -125,8 +125,8 @@ * *

    Choosing a Random Number Generator Algorithm

    * - *

    There are three groups of random number generator algorithm provided - * in Java: the Legacy group, the LXM group, and the Xoroshiro/Xoshiro group. + *

    Random number generator algorithms are organized in groups, + * as described {@linkplain java.util.random##algorithms below}. * *

    The legacy group includes random number generators that existed * before JDK 17: Random, ThreadLocalRandom, SplittableRandom, and @@ -304,6 +304,13 @@ * 1 * * + * SecureRandom + * Legacy + * BigInteger.ZERO + * Integer.MAX_VALUE + * Integer.MAX_VALUE + * + * * ThreadLocalRandom * * Legacy * BigInteger.ONE.shiftLeft(64) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java index 861bcd3b6012d..9bb3f275ba1a2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java @@ -24,35 +24,45 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.Annotation; import java.lang.classfile.Attribute; import java.lang.classfile.AttributeMapper; +import java.lang.classfile.AttributedElement; import java.lang.classfile.BufWriter; +import java.lang.classfile.ClassReader; +import java.lang.classfile.attribute.*; +import java.util.List; -public abstract class AbstractAttributeMapper> +import static java.lang.classfile.Attributes.*; + +public sealed abstract class AbstractAttributeMapper> implements AttributeMapper { private final String name; + private final AttributeMapper.AttributeStability stability; private final boolean allowMultiple; protected abstract void writeBody(BufWriter buf, T attr); - public AbstractAttributeMapper(String name) { - this(name, false); + public AbstractAttributeMapper(String name, AttributeMapper.AttributeStability stability) { + this(name, stability, false); } public AbstractAttributeMapper(String name, + AttributeMapper.AttributeStability stability, boolean allowMultiple) { this.name = name; + this.stability = stability; this.allowMultiple = allowMultiple; } @Override - public String name() { + public final String name() { return name; } @Override - public void writeAttribute(BufWriter buf, T attr) { + public final void writeAttribute(BufWriter buf, T attr) { buf.writeIndex(buf.constantPool().utf8Entry(name)); buf.writeInt(0); int start = buf.size(); @@ -61,6 +71,11 @@ public void writeAttribute(BufWriter buf, T attr) { buf.patchInt(start - 4, 4, written); } + @Override + public AttributeMapper.AttributeStability stability() { + return stability; + } + @Override public boolean allowMultiple() { return allowMultiple; @@ -71,4 +86,739 @@ public String toString() { return String.format("AttributeMapper[name=%s, allowMultiple=%b, stability=%s]", name, allowMultiple, stability()); } + + public static final class AnnotationDefaultMapper extends AbstractAttributeMapper { + public static final AnnotationDefaultMapper INSTANCE = new AnnotationDefaultMapper(); + + private AnnotationDefaultMapper() { + super(NAME_ANNOTATION_DEFAULT, AttributeStability.CP_REFS); + } + + @Override + public AnnotationDefaultAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundAnnotationDefaultAttr(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, AnnotationDefaultAttribute attr) { + attr.defaultValue().writeTo(buf); + } + } + + public static final class BootstrapMethodsMapper extends AbstractAttributeMapper { + public static final BootstrapMethodsMapper INSTANCE = new BootstrapMethodsMapper(); + + private BootstrapMethodsMapper() { + super(NAME_BOOTSTRAP_METHODS, AttributeStability.CP_REFS); + } + + @Override + public BootstrapMethodsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundBootstrapMethodsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, BootstrapMethodsAttribute attr) { + buf.writeList(attr.bootstrapMethods()); + } + } + + public static final class CharacterRangeTableMapper extends AbstractAttributeMapper { + public static final CharacterRangeTableMapper INSTANCE = new CharacterRangeTableMapper(); + + private CharacterRangeTableMapper() { + super(NAME_CHARACTER_RANGE_TABLE, AttributeStability.LABELS, true); + } + + @Override + public CharacterRangeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundCharacterRangeTableAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, CharacterRangeTableAttribute attr) { + List ranges = attr.characterRangeTable(); + buf.writeU2(ranges.size()); + for (CharacterRangeInfo info : ranges) { + buf.writeU2(info.startPc()); + buf.writeU2(info.endPc()); + buf.writeInt(info.characterRangeStart()); + buf.writeInt(info.characterRangeEnd()); + buf.writeU2(info.flags()); + } + } + } + + public static final class CodeMapper extends AbstractAttributeMapper { + public static final CodeMapper INSTANCE = new CodeMapper(); + + private CodeMapper() { + super(NAME_CODE, AttributeStability.CP_REFS); + } + + @Override + public CodeAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new CodeImpl(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, CodeAttribute attr) { + throw new UnsupportedOperationException("Code attribute does not support direct write"); + } + } + + public static final class CompilationIDMapper extends AbstractAttributeMapper { + public static final CompilationIDMapper INSTANCE = new CompilationIDMapper(); + + private CompilationIDMapper() { + super(NAME_COMPILATION_ID, AttributeStability.CP_REFS); + } + + @Override + public CompilationIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundCompilationIDAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, CompilationIDAttribute attr) { + buf.writeIndex(attr.compilationId()); + } + } + + public static final class ConstantValueMapper extends AbstractAttributeMapper { + public static final ConstantValueMapper INSTANCE = new ConstantValueMapper(); + + private ConstantValueMapper() { + super(NAME_CONSTANT_VALUE, AttributeStability.CP_REFS); + } + + @Override + public ConstantValueAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundConstantValueAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ConstantValueAttribute attr) { + buf.writeIndex(attr.constant()); + } + } + + public static final class DeprecatedMapper extends AbstractAttributeMapper { + public static final DeprecatedMapper INSTANCE = new DeprecatedMapper(); + + private DeprecatedMapper() { + super(NAME_DEPRECATED, AttributeStability.STATELESS, true); + } + + @Override + public DeprecatedAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundDeprecatedAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, DeprecatedAttribute attr) { + // empty + } + } + + public static final class EnclosingMethodMapper extends AbstractAttributeMapper { + public static final EnclosingMethodMapper INSTANCE = new EnclosingMethodMapper(); + + private EnclosingMethodMapper() { + super(NAME_ENCLOSING_METHOD, AttributeStability.CP_REFS); + } + + @Override + public EnclosingMethodAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundEnclosingMethodAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, EnclosingMethodAttribute attr) { + buf.writeIndex(attr.enclosingClass()); + buf.writeIndexOrZero(attr.enclosingMethod().orElse(null)); + } + } + + public static final class ExceptionsMapper extends AbstractAttributeMapper { + public static final ExceptionsMapper INSTANCE = new ExceptionsMapper(); + + private ExceptionsMapper() { + super(NAME_EXCEPTIONS, AttributeStability.CP_REFS); + } + + @Override + public ExceptionsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundExceptionsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ExceptionsAttribute attr) { + buf.writeListIndices(attr.exceptions()); + } + } + + public static final class InnerClassesMapper extends AbstractAttributeMapper { + public static final InnerClassesMapper INSTANCE = new InnerClassesMapper(); + + private InnerClassesMapper() { + super(NAME_INNER_CLASSES, AttributeStability.CP_REFS); + } + + @Override + public InnerClassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundInnerClassesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, InnerClassesAttribute attr) { + List classes = attr.classes(); + buf.writeU2(classes.size()); + for (InnerClassInfo ic : classes) { + buf.writeIndex(ic.innerClass()); + buf.writeIndexOrZero(ic.outerClass().orElse(null)); + buf.writeIndexOrZero(ic.innerName().orElse(null)); + buf.writeU2(ic.flagsMask()); + } + } + } + + public static final class LineNumberTableMapper extends AbstractAttributeMapper { + public static final LineNumberTableMapper INSTANCE = new LineNumberTableMapper(); + + private LineNumberTableMapper() { + super(NAME_LINE_NUMBER_TABLE, AttributeStability.LABELS, true); + } + + @Override + public LineNumberTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundLineNumberTableAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, LineNumberTableAttribute attr) { + List lines = attr.lineNumbers(); + buf.writeU2(lines.size()); + for (LineNumberInfo line : lines) { + buf.writeU2(line.startPc()); + buf.writeU2(line.lineNumber()); + } + } + } + + public static final class LocalVariableTableMapper extends AbstractAttributeMapper { + public static final LocalVariableTableMapper INSTANCE = new LocalVariableTableMapper(); + + private LocalVariableTableMapper() { + super(NAME_LOCAL_VARIABLE_TABLE, AttributeStability.LABELS, true); + } + + @Override + public LocalVariableTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundLocalVariableTableAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, LocalVariableTableAttribute attr) { + List infos = attr.localVariables(); + buf.writeU2(infos.size()); + for (LocalVariableInfo info : infos) { + buf.writeU2(info.startPc()); + buf.writeU2(info.length()); + buf.writeIndex(info.name()); + buf.writeIndex(info.type()); + buf.writeU2(info.slot()); + } + } + } + + public static final class LocalVariableTypeTableMapper extends AbstractAttributeMapper { + public static final LocalVariableTypeTableMapper INSTANCE = new LocalVariableTypeTableMapper(); + + private LocalVariableTypeTableMapper() { + super(NAME_LOCAL_VARIABLE_TYPE_TABLE, AttributeStability.LABELS, true); + } + + @Override + public LocalVariableTypeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundLocalVariableTypeTableAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, LocalVariableTypeTableAttribute attr) { + List infos = attr.localVariableTypes(); + buf.writeU2(infos.size()); + for (LocalVariableTypeInfo info : infos) { + buf.writeU2(info.startPc()); + buf.writeU2(info.length()); + buf.writeIndex(info.name()); + buf.writeIndex(info.signature()); + buf.writeU2(info.slot()); + } + } + } + + public static final class MethodParametersMapper extends AbstractAttributeMapper { + public static final MethodParametersMapper INSTANCE = new MethodParametersMapper(); + + private MethodParametersMapper() { + super(NAME_METHOD_PARAMETERS, AttributeStability.CP_REFS); + } + + @Override + public MethodParametersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundMethodParametersAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, MethodParametersAttribute attr) { + List parameters = attr.parameters(); + buf.writeU1(parameters.size()); + for (MethodParameterInfo info : parameters) { + buf.writeIndexOrZero(info.name().orElse(null)); + buf.writeU2(info.flagsMask()); + } + } + } + + public static final class ModuleMapper extends AbstractAttributeMapper { + public static final ModuleMapper INSTANCE = new ModuleMapper(); + + private ModuleMapper() { + super(NAME_MODULE, AttributeStability.CP_REFS); + } + + @Override + public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleAttribute attr) { + buf.writeIndex(attr.moduleName()); + buf.writeU2(attr.moduleFlagsMask()); + buf.writeIndexOrZero(attr.moduleVersion().orElse(null)); + buf.writeU2(attr.requires().size()); + for (ModuleRequireInfo require : attr.requires()) { + buf.writeIndex(require.requires()); + buf.writeU2(require.requiresFlagsMask()); + buf.writeIndexOrZero(require.requiresVersion().orElse(null)); + } + buf.writeU2(attr.exports().size()); + for (ModuleExportInfo export : attr.exports()) { + buf.writeIndex(export.exportedPackage()); + buf.writeU2(export.exportsFlagsMask()); + buf.writeListIndices(export.exportsTo()); + } + buf.writeU2(attr.opens().size()); + for (ModuleOpenInfo open : attr.opens()) { + buf.writeIndex(open.openedPackage()); + buf.writeU2(open.opensFlagsMask()); + buf.writeListIndices(open.opensTo()); + } + buf.writeListIndices(attr.uses()); + buf.writeU2(attr.provides().size()); + for (ModuleProvideInfo provide : attr.provides()) { + buf.writeIndex(provide.provides()); + buf.writeListIndices(provide.providesWith()); + } + } + } + + public static final class ModuleHashesMapper extends AbstractAttributeMapper { + public static final ModuleHashesMapper INSTANCE = new ModuleHashesMapper(); + + private ModuleHashesMapper() { + super(NAME_MODULE_HASHES, AttributeStability.CP_REFS); + } + + @Override + public ModuleHashesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleHashesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleHashesAttribute attr) { + buf.writeIndex(attr.algorithm()); + List hashes = attr.hashes(); + buf.writeU2(hashes.size()); + for (ModuleHashInfo hash : hashes) { + buf.writeIndex(hash.moduleName()); + buf.writeU2(hash.hash().length); + buf.writeBytes(hash.hash()); + } + } + } + + public static final class ModuleMainClassMapper extends AbstractAttributeMapper { + public static final ModuleMainClassMapper INSTANCE = new ModuleMainClassMapper(); + + private ModuleMainClassMapper() { + super(NAME_MODULE_MAIN_CLASS, AttributeStability.CP_REFS); + } + + @Override + public ModuleMainClassAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleMainClassAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleMainClassAttribute attr) { + buf.writeIndex(attr.mainClass()); + } + } + + public static final class ModulePackagesMapper extends AbstractAttributeMapper { + public static final ModulePackagesMapper INSTANCE = new ModulePackagesMapper(); + + private ModulePackagesMapper() { + super(NAME_MODULE_PACKAGES, AttributeStability.CP_REFS); + } + + @Override + public ModulePackagesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModulePackagesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) { + buf.writeListIndices(attr.packages()); + } + } + + public static final class ModuleResolutionMapper extends AbstractAttributeMapper { + public static final ModuleResolutionMapper INSTANCE = new ModuleResolutionMapper(); + + private ModuleResolutionMapper() { + super(NAME_MODULE_RESOLUTION, AttributeStability.STATELESS); + } + + @Override + public ModuleResolutionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleResolutionAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleResolutionAttribute attr) { + buf.writeU2(attr.resolutionFlags()); + } + } + + public static final class ModuleTargetMapper extends AbstractAttributeMapper { + public static final ModuleTargetMapper INSTANCE = new ModuleTargetMapper(); + + private ModuleTargetMapper() { + super(NAME_MODULE_TARGET, AttributeStability.CP_REFS); + } + + @Override + public ModuleTargetAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleTargetAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleTargetAttribute attr) { + buf.writeIndex(attr.targetPlatform()); + } + } + + public static final class NestHostMapper extends AbstractAttributeMapper { + public static final NestHostMapper INSTANCE = new NestHostMapper(); + + private NestHostMapper() { + super(NAME_NEST_HOST, AttributeStability.CP_REFS); + } + + @Override + public NestHostAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundNestHostAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, NestHostAttribute attr) { + buf.writeIndex(attr.nestHost()); + } + } + + public static final class NestMembersMapper extends AbstractAttributeMapper { + public static final NestMembersMapper INSTANCE = new NestMembersMapper(); + + private NestMembersMapper() { + super(NAME_NEST_MEMBERS, AttributeStability.CP_REFS); + } + + @Override + public NestMembersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundNestMembersAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, NestMembersAttribute attr) { + buf.writeListIndices(attr.nestMembers()); + } + } + + public static final class PermittedSubclassesMapper extends AbstractAttributeMapper { + public static final PermittedSubclassesMapper INSTANCE = new PermittedSubclassesMapper(); + + private PermittedSubclassesMapper() { + super(NAME_PERMITTED_SUBCLASSES, AttributeStability.CP_REFS); + } + + @Override + public PermittedSubclassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundPermittedSubclassesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, PermittedSubclassesAttribute attr) { + buf.writeListIndices(attr.permittedSubclasses()); + } + } + + public static final class RecordMapper extends AbstractAttributeMapper { + public static final RecordMapper INSTANCE = new RecordMapper(); + + private RecordMapper() { + super(NAME_RECORD, AttributeStability.CP_REFS); + } + + @Override + public RecordAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRecordAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RecordAttribute attr) { + List components = attr.components(); + buf.writeU2(components.size()); + for (RecordComponentInfo info : components) { + buf.writeIndex(info.name()); + buf.writeIndex(info.descriptor()); + buf.writeList(info.attributes()); + } + } + } + + public static final class RuntimeInvisibleAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeInvisibleAnnotationsMapper INSTANCE = new RuntimeInvisibleAnnotationsMapper(); + + private RuntimeInvisibleAnnotationsMapper() { + super(NAME_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeInvisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { + return new BoundAttribute.BoundRuntimeInvisibleAnnotationsAttribute(cf, pos); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeInvisibleAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class RuntimeInvisibleParameterAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeInvisibleParameterAnnotationsMapper INSTANCE = new RuntimeInvisibleParameterAnnotationsMapper(); + + private RuntimeInvisibleParameterAnnotationsMapper() { + super(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeInvisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeInvisibleParameterAnnotationsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeInvisibleParameterAnnotationsAttribute attr) { + List> lists = attr.parameterAnnotations(); + buf.writeU1(lists.size()); + for (List list : lists) + buf.writeList(list); + } + } + + public static final class RuntimeInvisibleTypeAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeInvisibleTypeAnnotationsMapper INSTANCE = new RuntimeInvisibleTypeAnnotationsMapper(); + + private RuntimeInvisibleTypeAnnotationsMapper() { + super(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, AttributeStability.UNSTABLE); + } + + @Override + public RuntimeInvisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeInvisibleTypeAnnotationsAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class RuntimeVisibleAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeVisibleAnnotationsMapper INSTANCE = new RuntimeVisibleAnnotationsMapper(); + + private RuntimeVisibleAnnotationsMapper() { + super(NAME_RUNTIME_VISIBLE_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeVisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { + return new BoundAttribute.BoundRuntimeVisibleAnnotationsAttribute(cf, pos); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeVisibleAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class RuntimeVisibleParameterAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeVisibleParameterAnnotationsMapper INSTANCE = new RuntimeVisibleParameterAnnotationsMapper(); + + private RuntimeVisibleParameterAnnotationsMapper() { + super(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeVisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeVisibleParameterAnnotationsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeVisibleParameterAnnotationsAttribute attr) { + List> lists = attr.parameterAnnotations(); + buf.writeU1(lists.size()); + for (List list : lists) + buf.writeList(list); + } + } + + public static final class RuntimeVisibleTypeAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeVisibleTypeAnnotationsMapper INSTANCE = new RuntimeVisibleTypeAnnotationsMapper(); + + private RuntimeVisibleTypeAnnotationsMapper() { + super(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS, AttributeStability.UNSTABLE); + } + + @Override + public RuntimeVisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeVisibleTypeAnnotationsAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class SignatureMapper extends AbstractAttributeMapper { + public static final SignatureMapper INSTANCE = new SignatureMapper(); + + private SignatureMapper() { + super(NAME_SIGNATURE, AttributeStability.CP_REFS); + } + + @Override + public SignatureAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSignatureAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SignatureAttribute attr) { + buf.writeIndex(attr.signature()); + } + } + + public static final class SourceDebugExtensionMapper extends AbstractAttributeMapper { + public static final SourceDebugExtensionMapper INSTANCE = new SourceDebugExtensionMapper(); + + private SourceDebugExtensionMapper() { + super(NAME_SOURCE_DEBUG_EXTENSION, AttributeStability.STATELESS); + } + + @Override + public SourceDebugExtensionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSourceDebugExtensionAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SourceDebugExtensionAttribute attr) { + buf.writeBytes(attr.contents()); + } + } + + public static final class SourceFileMapper extends AbstractAttributeMapper { + public static final SourceFileMapper INSTANCE = new SourceFileMapper(); + + private SourceFileMapper() { + super(NAME_SOURCE_FILE, AttributeStability.CP_REFS); + } + + @Override + public SourceFileAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSourceFileAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SourceFileAttribute attr) { + buf.writeIndex(attr.sourceFile()); + } + } + + public static final class SourceIDMapper extends AbstractAttributeMapper { + public static final SourceIDMapper INSTANCE = new SourceIDMapper(); + + private SourceIDMapper() { + super(NAME_SOURCE_ID, AttributeStability.CP_REFS); + } + + @Override + public SourceIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSourceIDAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SourceIDAttribute attr) { + buf.writeIndex(attr.sourceId()); + } + } + + public static final class StackMapTableMapper extends AbstractAttributeMapper { + public static final StackMapTableMapper INSTANCE = new StackMapTableMapper(); + + private StackMapTableMapper() { + super(NAME_STACK_MAP_TABLE, AttributeStability.LABELS); + } + + @Override + public StackMapTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundStackMapTableAttribute((CodeImpl)e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter b, StackMapTableAttribute attr) { + StackMapDecoder.writeFrames(b, attr.entries()); + } + } + + public static final class SyntheticMapper extends AbstractAttributeMapper { + public static final SyntheticMapper INSTANCE = new SyntheticMapper(); + + private SyntheticMapper() { + super(NAME_SYNTHETIC, AttributeStability.STATELESS, true); + } + + @Override + public SyntheticAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSyntheticAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SyntheticAttribute attr) { + // empty + } + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java index aae8344fe0062..769ebd1516b5c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java @@ -43,6 +43,8 @@ import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.access.SharedSecrets; +import static java.lang.classfile.Attributes.*; + public abstract sealed class BoundAttribute> extends AbstractElement implements Attribute { @@ -140,7 +142,7 @@ public static List> readAttributes(AttributedElement enclosing, Cla throw new IllegalArgumentException("attribute " + name.stringValue() + " too big to handle"); } - var mapper = Attributes.standardAttribute(name); + var mapper = standardAttribute(name); if (mapper == null) { mapper = customAttributes.apply(name); } @@ -889,7 +891,7 @@ public static final class BoundRuntimeInvisibleAnnotationsAttribute public BoundRuntimeInvisibleAnnotationsAttribute(ClassReader cf, int payloadStart) { - super(cf, Attributes.RUNTIME_INVISIBLE_ANNOTATIONS, payloadStart); + super(cf, Attributes.runtimeInvisibleAnnotations(), payloadStart); } @Override @@ -907,7 +909,7 @@ public static final class BoundRuntimeVisibleAnnotationsAttribute public BoundRuntimeVisibleAnnotationsAttribute(ClassReader cf, int payloadStart) { - super(cf, Attributes.RUNTIME_VISIBLE_ANNOTATIONS, payloadStart); + super(cf, Attributes.runtimeVisibleAnnotations(), payloadStart); } @Override @@ -983,4 +985,88 @@ public byte[] codeArray() { return classReader.readBytes(payloadStart + 8, codeLength()); } } + + /** + * {@return the attribute mapper for a standard attribute} + * + * @param name the name of the attribute to find + */ + public static AttributeMapper standardAttribute(Utf8Entry name) { + // critical bootstrap path, so no lambdas nor method handles here + return switch (name.hashCode()) { + case 0x78147009 -> + name.equalsString(NAME_ANNOTATION_DEFAULT) ? annotationDefault() : null; + case 0x665e3a3a -> + name.equalsString(NAME_BOOTSTRAP_METHODS) ? bootstrapMethods() : null; + case 0xcb7e162 -> + name.equalsString(NAME_CHARACTER_RANGE_TABLE) ? characterRangeTable() : null; + case 0x21e41e7e -> + name.equalsString(NAME_CODE) ? code() : null; + case 0x5a306b41 -> + name.equalsString(NAME_COMPILATION_ID) ? compilationId() : null; + case 0x3e191c7c -> + name.equalsString(NAME_CONSTANT_VALUE) ? constantValue() : null; + case 0x5e88ed0c -> + name.equalsString(NAME_DEPRECATED) ? deprecated() : null; + case 0x7284695e -> + name.equalsString(NAME_ENCLOSING_METHOD) ? enclosingMethod() : null; + case 0x21df25db -> + name.equalsString(NAME_EXCEPTIONS) ? exceptions() : null; + case 0x11392da9 -> + name.equalsString(NAME_INNER_CLASSES) ? innerClasses() : null; + case 0x167536fc -> + name.equalsString(NAME_LINE_NUMBER_TABLE) ? lineNumberTable() : null; + case 0x46939abc -> + name.equalsString(NAME_LOCAL_VARIABLE_TABLE) ? localVariableTable() : null; + case 0x63ee67f4 -> + name.equalsString(NAME_LOCAL_VARIABLE_TYPE_TABLE) ? localVariableTypeTable() : null; + case 0x2b597e15 -> + name.equalsString(NAME_METHOD_PARAMETERS) ? methodParameters() : null; + case 0x19f20ade -> + name.equalsString(NAME_MODULE) ? module() : null; + case 0x47f6395e -> + name.equalsString(NAME_MODULE_HASHES) ? moduleHashes() : null; + case 0x54db809 -> + name.equalsString(NAME_MODULE_MAIN_CLASS) ? moduleMainClass() : null; + case 0x1abd1c2c -> + name.equalsString(NAME_MODULE_PACKAGES) ? modulePackages() : null; + case 0x6ba46dd -> + name.equalsString(NAME_MODULE_RESOLUTION) ? moduleResolution() : null; + case 0x46f7d91d -> + name.equalsString(NAME_MODULE_TARGET) ? moduleTarget() : null; + case 0x5137f53 -> + name.equalsString(NAME_NEST_HOST) ? nestHost() : null; + case 0x4a8fa3b6 -> + name.equalsString(NAME_NEST_MEMBERS) ? nestMembers() : null; + case 0x55c73cb6 -> + name.equalsString(NAME_PERMITTED_SUBCLASSES) ? permittedSubclasses() : null; + case 0x3fe76d4e -> + name.equalsString(NAME_RECORD) ? record() : null; + case 0x180d6925 -> + name.equalsString(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) ? runtimeInvisibleAnnotations() : null; + case 0x7be22752 -> + name.equalsString(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) ? runtimeInvisibleParameterAnnotations() : null; + case 0x5299824 -> + name.equalsString(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) ? runtimeInvisibleTypeAnnotations() : null; + case 0x3534786e -> + name.equalsString(NAME_RUNTIME_VISIBLE_ANNOTATIONS) ? runtimeVisibleAnnotations() : null; + case 0xb4b4ac6 -> + name.equalsString(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) ? runtimeVisibleParameterAnnotations() : null; + case 0x6926482 -> + name.equalsString(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) ? runtimeVisibleTypeAnnotations() : null; + case 0x16a42b7c -> + name.equalsString(NAME_SIGNATURE) ? signature() : null; + case 0x400ab245 -> + name.equalsString(NAME_SOURCE_DEBUG_EXTENSION) ? sourceDebugExtension() : null; + case 0x2af490d4 -> + name.equalsString(NAME_SOURCE_FILE) ? sourceFile() : null; + case 0x303e0c58 -> + name.equalsString(NAME_SOURCE_ID) ? sourceId() : null; + case 0x19c7d0cd -> + name.equalsString(NAME_STACK_MAP_TABLE) ? stackMapTable() : null; + case 0x3dc79b7a -> + name.equalsString(NAME_SYNTHETIC) ? synthetic() : null; + default -> null; + }; + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java index ab9f053668b7a..35075cb774a55 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,25 +26,33 @@ import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.function.Consumer; -import java.util.stream.Collectors; - import java.lang.classfile.constantpool.ClassEntry; import java.lang.reflect.AccessFlag; import java.lang.classfile.AccessFlags; import java.lang.classfile.Attribute; -import java.lang.classfile.AttributeMapper; import java.lang.classfile.Attributes; import java.lang.classfile.ClassElement; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassFileVersion; +import java.lang.classfile.CustomAttribute; import java.lang.classfile.constantpool.ConstantPool; import java.lang.classfile.FieldModel; import java.lang.classfile.Interfaces; import java.lang.classfile.MethodModel; import java.lang.classfile.Superclass; +import java.lang.classfile.attribute.InnerClassesAttribute; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.classfile.attribute.ModuleHashesAttribute; +import java.lang.classfile.attribute.ModuleMainClassAttribute; +import java.lang.classfile.attribute.ModulePackagesAttribute; +import java.lang.classfile.attribute.ModuleResolutionAttribute; +import java.lang.classfile.attribute.ModuleTargetAttribute; +import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.classfile.attribute.SourceDebugExtensionAttribute; +import java.lang.classfile.attribute.SourceFileAttribute; import jdk.internal.access.SharedSecrets; public final class ClassImpl @@ -196,28 +204,21 @@ public String toString() { } private boolean verifyModuleAttributes() { - if (findAttribute(Attributes.MODULE).isEmpty()) + if (findAttribute(Attributes.module()).isEmpty()) return false; - Set> found = attributes().stream() - .map(Attribute::attributeMapper) - .collect(Collectors.toSet()); - - found.removeAll(allowedModuleAttributes); - found.retainAll(Attributes.PREDEFINED_ATTRIBUTES); - return found.isEmpty(); - } - - private static final Set> allowedModuleAttributes - = Set.of(Attributes.MODULE, - Attributes.MODULE_HASHES, - Attributes.MODULE_MAIN_CLASS, - Attributes.MODULE_PACKAGES, - Attributes.MODULE_RESOLUTION, - Attributes.MODULE_TARGET, - Attributes.INNER_CLASSES, - Attributes.SOURCE_FILE, - Attributes.SOURCE_DEBUG_EXTENSION, - Attributes.RUNTIME_VISIBLE_ANNOTATIONS, - Attributes.RUNTIME_INVISIBLE_ANNOTATIONS); + return attributes().stream().allMatch(a -> + a instanceof ModuleAttribute + || a instanceof ModulePackagesAttribute + || a instanceof ModuleHashesAttribute + || a instanceof ModuleMainClassAttribute + || a instanceof ModuleResolutionAttribute + || a instanceof ModuleTargetAttribute + || a instanceof InnerClassesAttribute + || a instanceof SourceFileAttribute + || a instanceof SourceDebugExtensionAttribute + || a instanceof RuntimeVisibleAnnotationsAttribute + || a instanceof RuntimeInvisibleAnnotationsAttribute + || a instanceof CustomAttribute); + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java index 6de48a5bb14b0..8bacc019c2399 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -289,7 +289,7 @@ BootstrapMethodsAttribute bootstrapMethodsAttribute() { if (bootstrapMethodsAttribute == null) { bootstrapMethodsAttribute - = containedClass.findAttribute(Attributes.BOOTSTRAP_METHODS) + = containedClass.findAttribute(Attributes.bootstrapMethods()) .orElse(new UnboundAttribute.EmptyBootstrapAttribute()); } @@ -323,7 +323,7 @@ ClassModel getContainedClass() { boolean writeBootstrapMethods(BufWriter buf) { Optional a - = containedClass.findAttribute(Attributes.BOOTSTRAP_METHODS); + = containedClass.findAttribute(Attributes.bootstrapMethods()); if (a.isEmpty()) return false; a.get().writeTo(buf); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index 12113e43c5a40..e9e257fda52da 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -230,7 +230,7 @@ private void inflateLabel(int bci) { private void inflateLineNumbers() { for (Attribute a : attributes()) { - if (a.attributeMapper() == Attributes.LINE_NUMBER_TABLE) { + if (a.attributeMapper() == Attributes.lineNumberTable()) { BoundLineNumberTableAttribute attr = (BoundLineNumberTableAttribute) a; if (lineNumbers == null) lineNumbers = new int[codeLength + 1]; @@ -252,7 +252,7 @@ private void inflateLineNumbers() { } private void inflateJumpTargets() { - Optional a = findAttribute(Attributes.STACK_MAP_TABLE); + Optional a = findAttribute(Attributes.stackMapTable()); if (a.isEmpty()) { if (classReader.readU2(6) <= ClassFile.JAVA_6_VERSION) { //fallback to jump targets inflation without StackMapTableAttribute @@ -325,8 +325,8 @@ else if (frameType < 128) { } private void inflateTypeAnnotations() { - findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).ifPresent(RuntimeVisibleTypeAnnotationsAttribute::annotations); - findAttribute(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS).ifPresent(RuntimeInvisibleTypeAnnotationsAttribute::annotations); + findAttribute(Attributes.runtimeVisibleTypeAnnotations()).ifPresent(RuntimeVisibleTypeAnnotationsAttribute::annotations); + findAttribute(Attributes.runtimeInvisibleTypeAnnotations()).ifPresent(RuntimeInvisibleTypeAnnotationsAttribute::annotations); } private void generateCatchTargets(Consumer consumer) { @@ -345,7 +345,7 @@ public void accept(int s, int e, int h, int c) { private void generateDebugElements(Consumer consumer) { for (Attribute a : attributes()) { - if (a.attributeMapper() == Attributes.CHARACTER_RANGE_TABLE) { + if (a.attributeMapper() == Attributes.characterRangeTable()) { var attr = (BoundCharacterRangeTableAttribute) a; int cnt = classReader.readU2(attr.payloadStart); int p = attr.payloadStart + 2; @@ -357,7 +357,7 @@ private void generateDebugElements(Consumer consumer) { consumer.accept(instruction); } } - else if (a.attributeMapper() == Attributes.LOCAL_VARIABLE_TABLE) { + else if (a.attributeMapper() == Attributes.localVariableTable()) { var attr = (BoundLocalVariableTableAttribute) a; int cnt = classReader.readU2(attr.payloadStart); int p = attr.payloadStart + 2; @@ -369,7 +369,7 @@ else if (a.attributeMapper() == Attributes.LOCAL_VARIABLE_TABLE) { consumer.accept(instruction); } } - else if (a.attributeMapper() == Attributes.LOCAL_VARIABLE_TYPE_TABLE) { + else if (a.attributeMapper() == Attributes.localVariableTypeTable()) { var attr = (BoundLocalVariableTypeTableAttribute) a; int cnt = classReader.readU2(attr.payloadStart); int p = attr.payloadStart + 2; @@ -381,10 +381,10 @@ else if (a.attributeMapper() == Attributes.LOCAL_VARIABLE_TYPE_TABLE) { consumer.accept(instruction); } } - else if (a.attributeMapper() == Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS) { + else if (a.attributeMapper() == Attributes.runtimeVisibleTypeAnnotations()) { consumer.accept((BoundRuntimeVisibleTypeAnnotationsAttribute) a); } - else if (a.attributeMapper() == Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) { + else if (a.attributeMapper() == Attributes.runtimeInvisibleTypeAnnotations()) { consumer.accept((BoundRuntimeInvisibleTypeAnnotationsAttribute) a); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 9f68177351f80..b961a12031f59 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -230,7 +230,7 @@ private void buildContent() { if (context.debugElementsOption() == ClassFile.DebugElementsOption.PASS_DEBUG) { if (!characterRanges.isEmpty()) { - Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.CHARACTER_RANGE_TABLE) { + Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.characterRangeTable()) { @Override public void writeBody(BufWriter b) { @@ -262,7 +262,7 @@ public void writeBody(BufWriter b) { } if (!localVariables.isEmpty()) { - Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.LOCAL_VARIABLE_TABLE) { + Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) { @Override public void writeBody(BufWriter b) { int pos = b.size(); @@ -285,7 +285,7 @@ public void writeBody(BufWriter b) { } if (!localVariableTypes.isEmpty()) { - Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.LOCAL_VARIABLE_TYPE_TABLE) { + Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) { @Override public void writeBody(BufWriter b) { int pos = b.size(); @@ -312,7 +312,7 @@ public void writeBody(BufWriter b) { attributes.withAttribute(lineNumberWriter); } - content = new UnboundAttribute.AdHocAttribute<>(Attributes.CODE) { + content = new UnboundAttribute.AdHocAttribute<>(Attributes.code()) { private void writeCounters(boolean codeMatch, BufWriterImpl buf) { if (codeMatch) { @@ -368,7 +368,7 @@ public void writeBody(BufWriter b) { if (codeAndExceptionsMatch(codeLength)) { switch (context.stackMapsOption()) { case STACK_MAPS_WHEN_REQUIRED -> { - attributes.withAttribute(original.findAttribute(Attributes.STACK_MAP_TABLE).orElse(null)); + attributes.withAttribute(original.findAttribute(Attributes.stackMapTable()).orElse(null)); writeCounters(true, buf); } case GENERATE_STACK_MAPS -> @@ -401,7 +401,7 @@ private static class DedupLineNumberTableAttribute extends UnboundAttribute.AdHo private int lastPc, lastLine, writtenLine; public DedupLineNumberTableAttribute(ConstantPoolBuilder constantPool, ClassFileImpl context) { - super(Attributes.LINE_NUMBER_TABLE); + super(Attributes.lineNumberTable()); buf = new BufWriterImpl(constantPool, context); lastPc = -1; writtenLine = -1; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java index 0baaa5865aec8..9a96e586c5501 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java @@ -118,7 +118,7 @@ public void writeTo(BufWriter b) { @Override public Optional code() { - return findAttribute(Attributes.CODE).map(a -> (CodeModel) a); + return findAttribute(Attributes.code()).map(a -> (CodeModel) a); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index db2b4f030a327..8deac9e3f95f8 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -144,7 +144,7 @@ public boolean writeBootstrapMethods(BufWriter buf) { } else { Attribute a - = new UnboundAttribute.AdHocAttribute<>(Attributes.BOOTSTRAP_METHODS) { + = new UnboundAttribute.AdHocAttribute<>(Attributes.bootstrapMethods()) { @Override public void writeBody(BufWriter b) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 17fcc5046a15a..4a8677e876f65 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -380,7 +380,7 @@ private void removeRangeFromExcTable(int rangeStart, int rangeEnd) { * @return StackMapTableAttribute or null if stack map is empty */ public Attribute stackMapTableAttribute() { - return frames.isEmpty() ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.STACK_MAP_TABLE) { + return frames.isEmpty() ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { @Override public void writeBody(BufWriter b) { b.writeU2(frames.size()); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index bdb293493bfa1..70b58e423f69a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -149,7 +149,7 @@ public static final class UnboundConstantValueAttribute private final ConstantValueEntry entry; public UnboundConstantValueAttribute(ConstantValueEntry entry) { - super(Attributes.CONSTANT_VALUE); + super(Attributes.constantValue()); this.entry = entry; } @@ -164,7 +164,7 @@ public static final class UnboundDeprecatedAttribute extends UnboundAttribute implements DeprecatedAttribute { public UnboundDeprecatedAttribute() { - super(Attributes.DEPRECATED); + super(Attributes.deprecated()); } } @@ -172,7 +172,7 @@ public static final class UnboundSyntheticAttribute extends UnboundAttribute implements SyntheticAttribute { public UnboundSyntheticAttribute() { - super(Attributes.SYNTHETIC); + super(Attributes.synthetic()); } } @@ -182,7 +182,7 @@ public static final class UnboundSignatureAttribute private final Utf8Entry signature; public UnboundSignatureAttribute(Utf8Entry signature) { - super(Attributes.SIGNATURE); + super(Attributes.signature()); this.signature = signature; } @@ -198,7 +198,7 @@ public static final class UnboundExceptionsAttribute private final List exceptions; public UnboundExceptionsAttribute(List exceptions) { - super(Attributes.EXCEPTIONS); + super(Attributes.exceptions()); this.exceptions = List.copyOf(exceptions); } @@ -214,7 +214,7 @@ public static final class UnboundAnnotationDefaultAttribute private final AnnotationValue annotationDefault; public UnboundAnnotationDefaultAttribute(AnnotationValue annotationDefault) { - super(Attributes.ANNOTATION_DEFAULT); + super(Attributes.annotationDefault()); this.annotationDefault = annotationDefault; } @@ -229,7 +229,7 @@ public static final class UnboundSourceFileAttribute extends UnboundAttribute entries; public UnboundStackMapTableAttribute(List entries) { - super(Attributes.STACK_MAP_TABLE); + super(Attributes.stackMapTable()); this.entries = List.copyOf(entries); } @@ -261,7 +261,7 @@ public static final class UnboundInnerClassesAttribute private final List innerClasses; public UnboundInnerClassesAttribute(List innerClasses) { - super(Attributes.INNER_CLASSES); + super(Attributes.innerClasses()); this.innerClasses = List.copyOf(innerClasses); } @@ -277,7 +277,7 @@ public static final class UnboundRecordAttribute private final List components; public UnboundRecordAttribute(List components) { - super(Attributes.RECORD); + super(Attributes.record()); this.components = List.copyOf(components); } @@ -294,7 +294,7 @@ public static final class UnboundEnclosingMethodAttribute private final NameAndTypeEntry method; public UnboundEnclosingMethodAttribute(ClassEntry classEntry, NameAndTypeEntry method) { - super(Attributes.ENCLOSING_METHOD); + super(Attributes.enclosingMethod()); this.classEntry = classEntry; this.method = method; } @@ -316,7 +316,7 @@ public static final class UnboundMethodParametersAttribute private final List parameters; public UnboundMethodParametersAttribute(List parameters) { - super(Attributes.METHOD_PARAMETERS); + super(Attributes.methodParameters()); this.parameters = List.copyOf(parameters); } @@ -332,7 +332,7 @@ public static final class UnboundModuleTargetAttribute final Utf8Entry moduleTarget; public UnboundModuleTargetAttribute(Utf8Entry moduleTarget) { - super(Attributes.MODULE_TARGET); + super(Attributes.moduleTarget()); this.moduleTarget = moduleTarget; } @@ -348,7 +348,7 @@ public static final class UnboundModuleMainClassAttribute final ClassEntry mainClass; public UnboundModuleMainClassAttribute(ClassEntry mainClass) { - super(Attributes.MODULE_MAIN_CLASS); + super(Attributes.moduleMainClass()); this.mainClass = mainClass; } @@ -365,7 +365,7 @@ public static final class UnboundModuleHashesAttribute private final List hashes; public UnboundModuleHashesAttribute(Utf8Entry algorithm, List hashes) { - super(Attributes.MODULE_HASHES); + super(Attributes.moduleHashes()); this.algorithm = algorithm; this.hashes = List.copyOf(hashes); } @@ -387,7 +387,7 @@ public static final class UnboundModulePackagesAttribute private final Collection packages; public UnboundModulePackagesAttribute(Collection packages) { - super(Attributes.MODULE_PACKAGES); + super(Attributes.modulePackages()); this.packages = List.copyOf(packages); } @@ -403,7 +403,7 @@ public static final class UnboundModuleResolutionAttribute private final int resolutionFlags; public UnboundModuleResolutionAttribute(int flags) { - super(Attributes.MODULE_RESOLUTION); + super(Attributes.moduleResolution()); resolutionFlags = flags; } @@ -419,7 +419,7 @@ public static final class UnboundPermittedSubclassesAttribute private final List permittedSubclasses; public UnboundPermittedSubclassesAttribute(List permittedSubclasses) { - super(Attributes.PERMITTED_SUBCLASSES); + super(Attributes.permittedSubclasses()); this.permittedSubclasses = List.copyOf(permittedSubclasses); } @@ -435,7 +435,7 @@ public static final class UnboundNestMembersAttribute private final List memberEntries; public UnboundNestMembersAttribute(List memberEntries) { - super(Attributes.NEST_MEMBERS); + super(Attributes.nestMembers()); this.memberEntries = List.copyOf(memberEntries); } @@ -451,7 +451,7 @@ public static final class UnboundNestHostAttribute private final ClassEntry hostEntry; public UnboundNestHostAttribute(ClassEntry hostEntry) { - super(Attributes.NEST_HOST); + super(Attributes.nestHost()); this.hostEntry = hostEntry; } @@ -467,7 +467,7 @@ public static final class UnboundCompilationIDAttribute private final Utf8Entry idEntry; public UnboundCompilationIDAttribute(Utf8Entry idEntry) { - super(Attributes.COMPILATION_ID); + super(Attributes.compilationId()); this.idEntry = idEntry; } @@ -483,7 +483,7 @@ public static final class UnboundSourceIDAttribute private final Utf8Entry idEntry; public UnboundSourceIDAttribute(Utf8Entry idEntry) { - super(Attributes.SOURCE_ID); + super(Attributes.sourceId()); this.idEntry = idEntry; } @@ -499,7 +499,7 @@ public static final class UnboundSourceDebugExtensionAttribute private final byte[] contents; public UnboundSourceDebugExtensionAttribute(byte[] contents) { - super(Attributes.SOURCE_DEBUG_EXTENSION); + super(Attributes.sourceDebugExtension()); this.contents = contents; } @@ -515,7 +515,7 @@ public static final class UnboundCharacterRangeTableAttribute private final List ranges; public UnboundCharacterRangeTableAttribute(List ranges) { - super(Attributes.CHARACTER_RANGE_TABLE); + super(Attributes.characterRangeTable()); this.ranges = List.copyOf(ranges); } @@ -531,7 +531,7 @@ public static final class UnboundLineNumberTableAttribute private final List lines; public UnboundLineNumberTableAttribute(List lines) { - super(Attributes.LINE_NUMBER_TABLE); + super(Attributes.lineNumberTable()); this.lines = List.copyOf(lines); } @@ -547,7 +547,7 @@ public static final class UnboundLocalVariableTableAttribute private final List locals; public UnboundLocalVariableTableAttribute(List locals) { - super(Attributes.LOCAL_VARIABLE_TABLE); + super(Attributes.localVariableTable()); this.locals = List.copyOf(locals); } @@ -563,7 +563,7 @@ public static final class UnboundLocalVariableTypeTableAttribute private final List locals; public UnboundLocalVariableTypeTableAttribute(List locals) { - super(Attributes.LOCAL_VARIABLE_TYPE_TABLE); + super(Attributes.localVariableTypeTable()); this.locals = List.copyOf(locals); } @@ -579,7 +579,7 @@ public static final class UnboundRuntimeVisibleAnnotationsAttribute private final List elements; public UnboundRuntimeVisibleAnnotationsAttribute(List elements) { - super(Attributes.RUNTIME_VISIBLE_ANNOTATIONS); + super(Attributes.runtimeVisibleAnnotations()); this.elements = List.copyOf(elements); } @@ -595,7 +595,7 @@ public static final class UnboundRuntimeInvisibleAnnotationsAttribute private final List elements; public UnboundRuntimeInvisibleAnnotationsAttribute(List elements) { - super(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS); + super(Attributes.runtimeInvisibleAnnotations()); this.elements = List.copyOf(elements); } @@ -611,7 +611,7 @@ public static final class UnboundRuntimeVisibleParameterAnnotationsAttribute private final List> elements; public UnboundRuntimeVisibleParameterAnnotationsAttribute(List> elements) { - super(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS); + super(Attributes.runtimeVisibleParameterAnnotations()); this.elements = List.copyOf(elements); } @@ -627,7 +627,7 @@ public static final class UnboundRuntimeInvisibleParameterAnnotationsAttribute private final List> elements; public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List> elements) { - super(Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS); + super(Attributes.runtimeInvisibleParameterAnnotations()); this.elements = List.copyOf(elements); } @@ -643,7 +643,7 @@ public static final class UnboundRuntimeVisibleTypeAnnotationsAttribute private final List elements; public UnboundRuntimeVisibleTypeAnnotationsAttribute(List elements) { - super(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + super(Attributes.runtimeVisibleTypeAnnotations()); this.elements = List.copyOf(elements); } @@ -659,7 +659,7 @@ public static final class UnboundRuntimeInvisibleTypeAnnotationsAttribute private final List elements; public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List elements) { - super(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + super(Attributes.runtimeInvisibleTypeAnnotations()); this.elements = List.copyOf(elements); } @@ -845,7 +845,7 @@ public UnboundModuleAttribute(ModuleEntry moduleName, Collection uses, Collection provides) { - super(Attributes.MODULE); + super(Attributes.module()); this.moduleName = moduleName; this.moduleFlags = moduleFlags; this.moduleVersion = moduleVersion; @@ -921,7 +921,7 @@ public static final class EmptyBootstrapAttribute extends UnboundAttribute implements BootstrapMethodsAttribute { public EmptyBootstrapAttribute() { - super(Attributes.BOOTSTRAP_METHODS); + super(Attributes.bootstrapMethods()); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 7bff7e6f06dbb..0e969272c4028 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -214,7 +214,7 @@ public static void dumpMethod(SplitConstantPool cp, var cc = ClassFile.of(); var clm = cc.parse(cc.build(cp.classEntry(cls), cp, clb -> clb.withMethod(methodName, methodDesc, acc, mb -> - ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.CODE) { + ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override public void writeBody(BufWriter b) { b.writeU2(-1);//max stack diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java index 6be4a611e975d..fefc6b20cb2b1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java @@ -142,12 +142,12 @@ List exceptionTable() { } List localVariableTable() { - var attro = c.findAttribute(Attributes.LOCAL_VARIABLE_TABLE); + var attro = c.findAttribute(Attributes.localVariableTable()); return attro.map(lvta -> lvta.localVariables()).orElse(List.of()); } byte[] stackMapTableRawData() { - var attro = c.findAttribute(Attributes.STACK_MAP_TABLE); + var attro = c.findAttribute(Attributes.stackMapTable()); return attro.map(attr -> ((BoundAttribute) attr).contents()).orElse(null); } diff --git a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java index e8d73b08097f9..a1efc0fd10f1b 100644 --- a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java +++ b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java @@ -69,6 +69,17 @@ public static ReferenceClassDescImpl ofValidated(String descriptor) { return new ReferenceClassDescImpl(descriptor); } + /** + * Creates a {@linkplain ClassDesc} from a pre-validated descriptor string + * for a class or interface type or an array type. + * + * @param descriptor a field descriptor string for a class or interface type + * @jvms 4.3.2 Field Descriptors + */ + public static ClassDesc ofValidatedBinaryName(String typeSwitchClassName) { + return ofValidated("L" + binaryToInternal(typeSwitchClassName) + ";"); + } + @Override public String descriptorString() { return descriptor; diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java index 2d48748fbfc8a..6c911ed6fed88 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java @@ -38,6 +38,9 @@ public interface JdkConsole { PrintWriter writer(); Reader reader(); + JdkConsole println(Object obj); + JdkConsole print(Object obj); + String readln(String prompt); JdkConsole format(Locale locale, String format, Object ... args); String readLine(Locale locale, String format, Object ... args); String readLine(); diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java index e25626ead0c27..7930e00fbc059 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java @@ -57,6 +57,39 @@ public Reader reader() { return reader; } + @Override + public JdkConsole println(Object obj) { + pw.println(obj); + // automatic flushing covers println + return this; + } + + @Override + public JdkConsole print(Object obj) { + pw.print(obj); + pw.flush(); // automatic flushing does not cover print + return this; + } + + @Override + public String readln(String prompt) { + String line = null; + synchronized (writeLock) { + synchronized(readLock) { + pw.print(prompt); + pw.flush(); // automatic flushing does not cover print + try { + char[] ca = readline(false); + if (ca != null) + line = new String(ca); + } catch (IOException x) { + throw new IOError(x); + } + } + } + return line; + } + @Override public JdkConsole format(Locale locale, String format, Object ... args) { formatter.format(locale, format, args).flush(); diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index 43dcf25c263bf..f95ffd0e40293 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -69,9 +69,7 @@ public enum Feature { FOREIGN, @JEP(number=459, title="String Templates", status="Second Preview") STRING_TEMPLATES, - @JEP(number=445, title="Unnamed Classes and Instance Main Methods", status="Deprecated") - UNNAMED_CLASSES, - @JEP(number=463, title="Implicitly Declared Classes and Instance Main Methods", status="Preview") + @JEP(number=477, title="Implicitly Declared Classes and Instance Main Methods", status="Third Preview") IMPLICIT_CLASSES, @JEP(number=464, title="Scoped Values", status="Second Preview") SCOPED_VALUES, diff --git a/src/java.base/share/classes/jdk/internal/random/L128X1024MixRandom.java b/src/java.base/share/classes/jdk/internal/random/L128X1024MixRandom.java index e6f4f896dc0bf..4af9ecc3dd4d1 100644 --- a/src/java.base/share/classes/jdk/internal/random/L128X1024MixRandom.java +++ b/src/java.base/share/classes/jdk/internal/random/L128X1024MixRandom.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "splittable" pseudorandom number generator (PRNG) whose period @@ -75,12 +74,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "L128X1024MixRandom", - group = "LXM", - i = 1024, j = 1, k = 128, - equidistribution = 1 -) public final class L128X1024MixRandom extends AbstractSplittableWithBrineGenerator { /* diff --git a/src/java.base/share/classes/jdk/internal/random/L128X128MixRandom.java b/src/java.base/share/classes/jdk/internal/random/L128X128MixRandom.java index d03fcfc086485..1323139ea596e 100644 --- a/src/java.base/share/classes/jdk/internal/random/L128X128MixRandom.java +++ b/src/java.base/share/classes/jdk/internal/random/L128X128MixRandom.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "splittable" pseudorandom number generator (PRNG) whose period @@ -75,12 +74,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "L128X128MixRandom", - group = "LXM", - i = 128, j = 1, k = 128, - equidistribution = 1 -) public final class L128X128MixRandom extends AbstractSplittableWithBrineGenerator { /* diff --git a/src/java.base/share/classes/jdk/internal/random/L128X256MixRandom.java b/src/java.base/share/classes/jdk/internal/random/L128X256MixRandom.java index 81440d7316a50..19fd31b069af5 100644 --- a/src/java.base/share/classes/jdk/internal/random/L128X256MixRandom.java +++ b/src/java.base/share/classes/jdk/internal/random/L128X256MixRandom.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "splittable" pseudorandom number generator (PRNG) whose period @@ -75,12 +74,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "L128X256MixRandom", - group = "LXM", - i = 256, j = 1, k = 128, - equidistribution = 1 -) public final class L128X256MixRandom extends AbstractSplittableWithBrineGenerator { /* diff --git a/src/java.base/share/classes/jdk/internal/random/L32X64MixRandom.java b/src/java.base/share/classes/jdk/internal/random/L32X64MixRandom.java index 0f6beea7bc796..a9442bd0ef2d4 100644 --- a/src/java.base/share/classes/jdk/internal/random/L32X64MixRandom.java +++ b/src/java.base/share/classes/jdk/internal/random/L32X64MixRandom.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "splittable" pseudorandom number generator (PRNG) whose period @@ -75,12 +74,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "L32X64MixRandom", - group = "LXM", - i = 64, j = 1, k = 32, - equidistribution = 1 -) public final class L32X64MixRandom extends AbstractSplittableWithBrineGenerator { /* * Implementation Overview. diff --git a/src/java.base/share/classes/jdk/internal/random/L64X1024MixRandom.java b/src/java.base/share/classes/jdk/internal/random/L64X1024MixRandom.java index e4eb82d450ef2..074aac0c70e42 100644 --- a/src/java.base/share/classes/jdk/internal/random/L64X1024MixRandom.java +++ b/src/java.base/share/classes/jdk/internal/random/L64X1024MixRandom.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "splittable" pseudorandom number generator (PRNG) whose period @@ -75,12 +74,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "L64X1024MixRandom", - group = "LXM", - i = 1024, j = 1, k = 64, - equidistribution = 16 -) public final class L64X1024MixRandom extends AbstractSplittableWithBrineGenerator { /* diff --git a/src/java.base/share/classes/jdk/internal/random/L64X128MixRandom.java b/src/java.base/share/classes/jdk/internal/random/L64X128MixRandom.java index 7dd757f312b1e..37e10237c39b6 100644 --- a/src/java.base/share/classes/jdk/internal/random/L64X128MixRandom.java +++ b/src/java.base/share/classes/jdk/internal/random/L64X128MixRandom.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "splittable" pseudorandom number generator (PRNG) whose period @@ -75,12 +74,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "L64X128MixRandom", - group = "LXM", - i = 128, j = 1, k = 64, - equidistribution = 2 -) public final class L64X128MixRandom extends AbstractSplittableWithBrineGenerator { /* diff --git a/src/java.base/share/classes/jdk/internal/random/L64X128StarStarRandom.java b/src/java.base/share/classes/jdk/internal/random/L64X128StarStarRandom.java index 15b9bc312da3a..1d1a00ca006ad 100644 --- a/src/java.base/share/classes/jdk/internal/random/L64X128StarStarRandom.java +++ b/src/java.base/share/classes/jdk/internal/random/L64X128StarStarRandom.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "splittable" pseudorandom number generator (PRNG) whose period @@ -75,12 +74,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "L64X128StarStarRandom", - group = "LXM", - i = 128, j = 1, k = 64, - equidistribution = 2 -) public final class L64X128StarStarRandom extends AbstractSplittableWithBrineGenerator { /* diff --git a/src/java.base/share/classes/jdk/internal/random/L64X256MixRandom.java b/src/java.base/share/classes/jdk/internal/random/L64X256MixRandom.java index bb605df5fdc87..109148e3f01f8 100644 --- a/src/java.base/share/classes/jdk/internal/random/L64X256MixRandom.java +++ b/src/java.base/share/classes/jdk/internal/random/L64X256MixRandom.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import jdk.internal.util.random.RandomSupport; import jdk.internal.util.random.RandomSupport.AbstractSplittableWithBrineGenerator; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "splittable" pseudorandom number generator (PRNG) whose period @@ -75,12 +74,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "L64X256MixRandom", - group = "LXM", - i = 256, j = 1, k = 64, - equidistribution = 4 -) public final class L64X256MixRandom extends AbstractSplittableWithBrineGenerator { /* diff --git a/src/java.base/share/classes/jdk/internal/random/Xoroshiro128PlusPlus.java b/src/java.base/share/classes/jdk/internal/random/Xoroshiro128PlusPlus.java index d20b3cf9e6afa..3dc90fff4d055 100644 --- a/src/java.base/share/classes/jdk/internal/random/Xoroshiro128PlusPlus.java +++ b/src/java.base/share/classes/jdk/internal/random/Xoroshiro128PlusPlus.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import java.util.random.RandomGenerator.LeapableGenerator; import jdk.internal.util.random.RandomSupport; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "jumpable and leapable" pseudorandom number generator (PRNG) whose period @@ -72,12 +71,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "Xoroshiro128PlusPlus", - group = "Xoroshiro", - i = 128, j = 1, k = 0, - equidistribution = 1 -) public final class Xoroshiro128PlusPlus implements LeapableGenerator { /* diff --git a/src/java.base/share/classes/jdk/internal/random/Xoshiro256PlusPlus.java b/src/java.base/share/classes/jdk/internal/random/Xoshiro256PlusPlus.java index fdefe02dd035d..1ae4aeaac02f4 100644 --- a/src/java.base/share/classes/jdk/internal/random/Xoshiro256PlusPlus.java +++ b/src/java.base/share/classes/jdk/internal/random/Xoshiro256PlusPlus.java @@ -29,7 +29,6 @@ import java.util.random.RandomGenerator; import java.util.random.RandomGenerator.LeapableGenerator; import jdk.internal.util.random.RandomSupport; -import jdk.internal.util.random.RandomSupport.RandomGeneratorProperties; /** * A "jumpable and leapable" pseudorandom number generator (PRNG) whose period @@ -87,12 +86,6 @@ * @since 17 * */ -@RandomGeneratorProperties( - name = "Xoshiro256PlusPlus", - group = "Xoshiro", - i = 256, j = 1, k = 0, - equidistribution = 3 -) public final class Xoshiro256PlusPlus implements LeapableGenerator { /* diff --git a/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java b/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java index c80d67005ae1f..402be6b5dfe71 100644 --- a/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java +++ b/src/java.base/share/classes/jdk/internal/util/random/RandomSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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,10 +25,7 @@ package jdk.internal.util.random; -import java.lang.annotation.*; -import java.math.BigInteger; import java.util.Objects; -import java.util.Random; import java.util.function.Consumer; import java.util.function.DoubleConsumer; import java.util.function.IntConsumer; @@ -53,49 +50,6 @@ * @since 17 */ public class RandomSupport { - /** - * Annotation providing RandomGenerator properties. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.TYPE) - public @interface RandomGeneratorProperties { - /** - * Name of algorithm. - */ - String name(); - - /** - * Category of algorithm. - */ - String group() default "Legacy"; - - /** - * Algorithm period defined as: - * - * BigInteger.ONE.shiftLeft(i) - * .subtract(j) - * .shiftLeft(k) - */ - int i() default 0; - int j() default 0; - int k() default 0; - - /** - * The equidistribution of the algorithm. - */ - int equidistribution() default Integer.MAX_VALUE; - - /** - * Is the algorithm based on entropy (true random.) - */ - boolean isStochastic() default false; - - /** - * Is the algorithm assisted by hardware (fast true random.) - */ - boolean isHardware() default false; - } - /* * Implementation Overview. * diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index edbbad78c9da9..a8b0a0c992c41 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -419,19 +419,4 @@ provides java.nio.file.spi.FileSystemProvider with jdk.internal.jrtfs.JrtFileSystemProvider; - provides java.util.random.RandomGenerator with - java.security.SecureRandom, - java.util.Random, - java.util.SplittableRandom, - jdk.internal.random.L32X64MixRandom, - jdk.internal.random.L64X128MixRandom, - jdk.internal.random.L64X128StarStarRandom, - jdk.internal.random.L64X256MixRandom, - jdk.internal.random.L64X1024MixRandom, - jdk.internal.random.L128X128MixRandom, - jdk.internal.random.L128X256MixRandom, - jdk.internal.random.L128X1024MixRandom, - jdk.internal.random.Xoroshiro128PlusPlus, - jdk.internal.random.Xoshiro256PlusPlus; - } diff --git a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java b/src/java.base/share/classes/sun/net/util/IPAddressUtil.java index e81b65433939b..ecd60a9ffc469 100644 --- a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java +++ b/src/java.base/share/classes/sun/net/util/IPAddressUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, 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 @@ -666,40 +666,81 @@ public static int digit(char ch, int radix) { * {@code false} otherwise. */ public static boolean isBsdParsableV4(String input) { + return parseBsdLiteralV4(input) != null; + } + + /** + * Parse String as IPv4 address literal by following + * POSIX-style formatting rules. + * + * @param input a String representing an IPv4 address in POSIX format + * @return a byte array representing the IPv4 numeric address + * if input string is a parsable POSIX formatted IPv4 address literal, + * {@code null} otherwise. + */ + public static byte[] parseBsdLiteralV4(String input) { + + byte[] res = new byte[]{0,0,0,0}; + + int len = input.length(); + if (len == 0) { + return null; + } char firstSymbol = input.charAt(0); // Check if first digit is not a decimal digit if (parseAsciiDigit(firstSymbol, DECIMAL) == -1) { - return false; + return null; } // Last character is dot OR is not a supported digit: [0-9,A-F,a-f] - char lastSymbol = input.charAt(input.length() - 1); + char lastSymbol = input.charAt(len - 1); if (lastSymbol == '.' || parseAsciiHexDigit(lastSymbol) == -1) { - return false; + return null; } // Parse IP address fields CharBuffer charBuffer = CharBuffer.wrap(input); int fieldNumber = 0; + long fieldValue = -1L; while (charBuffer.hasRemaining()) { - long fieldValue = -1L; + fieldValue = -1L; // Try to parse fields in all supported radixes for (int radix : SUPPORTED_RADIXES) { fieldValue = parseV4FieldBsd(radix, charBuffer, fieldNumber); if (fieldValue >= 0) { + if (fieldValue < 256) { + // Store the parsed field in the byte buffer. + // If the field value is greater than 255, it can only be the last field. + // If it is not the last one, parseV4FieldBsd enforces this limit + // and returns TERMINAL_PARSE_ERROR. + res[fieldNumber] = (byte) fieldValue; + } fieldNumber++; break; } else if (fieldValue == TERMINAL_PARSE_ERROR) { - return false; + return null; } } // If field can't be parsed as one of supported radixes stop // parsing if (fieldValue < 0) { - return false; + return null; } } - return true; + // The last field value must be non-negative + if (fieldValue < 0) { + return null; + } + // If the last fieldValue is greater than 255 (fieldNumber < 4), + // it is written to the last (4 - (fieldNumber - 1)) octets + // in the network order + if (fieldNumber < 4) { + for (int i = 3; i >= fieldNumber - 1; --i) { + res[i] = (byte) (fieldValue & 255); + fieldValue >>= 8; + } + } + return res; } /** diff --git a/src/java.base/share/classes/sun/security/ec/ECDHKeyAgreement.java b/src/java.base/share/classes/sun/security/ec/ECDHKeyAgreement.java index 1fdbd94786ab3..be3bdfdd63990 100644 --- a/src/java.base/share/classes/sun/security/ec/ECDHKeyAgreement.java +++ b/src/java.base/share/classes/sun/security/ec/ECDHKeyAgreement.java @@ -31,6 +31,7 @@ import sun.security.util.ECUtil; import sun.security.util.NamedCurve; import sun.security.util.math.IntegerFieldModuloP; +import sun.security.util.math.IntegerMontgomeryFieldModuloP; import sun.security.util.math.MutableIntegerModuloP; import sun.security.util.math.SmallValue; @@ -265,6 +266,11 @@ byte[] deriveKeyImpl(ECPrivateKey priv, ECOperations ops, ECPublicKey pubKey) throws InvalidKeyException { IntegerFieldModuloP field = ops.getField(); + if (field instanceof IntegerMontgomeryFieldModuloP) { + // No point of doing a single SmallValue operation in Montgomery domain + field = ((IntegerMontgomeryFieldModuloP)field).residueField(); + } + // convert s array into field element and multiply by the cofactor MutableIntegerModuloP scalar = field.getElement(priv.getS()).mutable(); SmallValue cofactor = diff --git a/src/java.base/share/classes/sun/security/ec/ECDSAOperations.java b/src/java.base/share/classes/sun/security/ec/ECDSAOperations.java index 7bbcbd032f125..f58d7d8f2d783 100644 --- a/src/java.base/share/classes/sun/security/ec/ECDSAOperations.java +++ b/src/java.base/share/classes/sun/security/ec/ECDSAOperations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -252,7 +252,7 @@ public boolean verifySignedDigest(byte[] digest, byte[] sig, ECPoint pp) { MutablePoint p1 = ecOps.multiply(basePoint, temp1); MutablePoint p2 = ecOps.multiply(pp, temp2); - ecOps.setSum(p1, p2.asAffine()); + ecOps.setSum(p1, p2); IntegerModuloP result = p1.asAffine().getX(); b2a(result, orderField, temp1); return MessageDigest.isEqual(temp1, r); diff --git a/src/java.base/share/classes/sun/security/ec/ECOperations.java b/src/java.base/share/classes/sun/security/ec/ECOperations.java index d4959aed46315..2f94bb8534242 100644 --- a/src/java.base/share/classes/sun/security/ec/ECOperations.java +++ b/src/java.base/share/classes/sun/security/ec/ECOperations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -46,12 +46,7 @@ * Formulas are derived from "Complete addition formulas for prime order * elliptic curves" by Renes, Costello, and Batina. */ - public class ECOperations { - private static final ECOperations secp256r1Ops = - new ECOperations(IntegerPolynomialP256.ONE.getElement( - CurveDB.lookup(KnownOIDs.secp256r1.value()).getCurve().getB()), - P256OrderField.ONE); /* * An exception indicating a problem with an intermediate value produced @@ -64,7 +59,7 @@ static class IntermediateValueException extends Exception { } static final Map fields = Map.of( - IntegerPolynomialP256.MODULUS, IntegerPolynomialP256.ONE, + IntegerPolynomialP256.MODULUS, MontgomeryIntegerPolynomialP256.ONE, IntegerPolynomialP384.MODULUS, IntegerPolynomialP384.ONE, IntegerPolynomialP521.MODULUS, IntegerPolynomialP521.ONE ); @@ -207,11 +202,28 @@ public static boolean allZero(byte[] arr) { * @return the product */ public MutablePoint multiply(AffinePoint affineP, byte[] s) { - return PointMultiplier.of(this, affineP).pointMultiply(s); + PointMultiplier multiplier = null; + if (getField() instanceof IntegerMontgomeryFieldModuloP + && affineP.equals(Secp256R1GeneratorMontgomeryMultiplier.generator)) { + // Lazy class loading here + multiplier = Secp256R1GeneratorMontgomeryMultiplier.multiplier; + } else { + multiplier = new DefaultMultiplier(this, affineP); + } + + return multiplier.pointMultiply(s); } + /** + * Multiply an affine ecpoint point by a scalar and return the result as a + * mutable point. + * + * @param ecPoint the point + * @param s the scalar as a little-endian array + * @return the product + */ public MutablePoint multiply(ECPoint ecPoint, byte[] s) { - return PointMultiplier.of(this, ecPoint).pointMultiply(s); + return multiply(AffinePoint.fromECPoint(ecPoint, getField()), s); } /* @@ -264,21 +276,26 @@ private void setDouble(ProjectivePoint.Mutable p, MutableIntegerModuloP t0, } - /* - * Mixed point addition. This method constructs new temporaries each time - * it is called. For better efficiency, the method that reuses temporaries - * should be used if more than one sum will be computed. + /** + * Adds second Mutable (Projective) point to first. + * + * Used by ECDSAOperations. This method constructs new temporaries each time + * it is called. For better efficiency, the (private) method that reuses + * temporaries should be used if more than one sum will be computed. + * + * @param p first point and result + * @param p2 second point to add */ - public void setSum(MutablePoint p, AffinePoint p2) { - + public void setSum(MutablePoint p, MutablePoint p2) { IntegerModuloP zero = p.getField().get0(); MutableIntegerModuloP t0 = zero.mutable(); MutableIntegerModuloP t1 = zero.mutable(); MutableIntegerModuloP t2 = zero.mutable(); MutableIntegerModuloP t3 = zero.mutable(); MutableIntegerModuloP t4 = zero.mutable(); - setSum((ProjectivePoint.Mutable) p, p2, t0, t1, t2, t3, t4); + setSum((ProjectivePoint.Mutable) p, (ProjectivePoint.Mutable) p2, + t0, t1, t2, t3, t4); } /* @@ -289,18 +306,18 @@ private void setSum(ProjectivePoint.Mutable p, AffinePoint p2, MutableIntegerModuloP t2, MutableIntegerModuloP t3, MutableIntegerModuloP t4) { - t0.setValue(p.getX()).setProduct(p2.getX()); - t1.setValue(p.getY()).setProduct(p2.getY()); - t3.setValue(p2.getX()).setSum(p2.getY()); + t0.setValue(p.getX()).setProduct(p2.getX(false)); + t1.setValue(p.getY()).setProduct(p2.getY(false)); + t3.setValue(p2.getX(false)).setSum(p2.getY(false)); t4.setValue(p.getX()).setSum(p.getY()); t3.setProduct(t4); t4.setValue(t0).setSum(t1); t3.setDifference(t4); - t4.setValue(p2.getY()).setProduct(p.getZ()); + t4.setValue(p2.getY(false)).setProduct(p.getZ()); t4.setSum(p.getY()); - p.getY().setValue(p2.getX()).setProduct(p.getZ()); + p.getY().setValue(p2.getX(false)).setProduct(p.getZ()); p.getY().setSum(p.getX()); t2.setValue(p.getZ()); p.getZ().setProduct(b); @@ -412,11 +429,8 @@ public boolean checkOrder(ECPoint point) { return isNeutral(this.multiply(ap, scalar)); } - sealed interface PointMultiplier { - Map multipliers = Map.of( - Secp256R1GeneratorMultiplier.generator, - Secp256R1GeneratorMultiplier.multiplier); - + sealed interface PointMultiplier + permits DefaultMultiplier, Secp256R1GeneratorMontgomeryMultiplier { // Multiply the point by a scalar and return the result as a mutable // point. The multiplier point is specified by the implementation of // this interface, which could be a general EC point or EC generator @@ -429,26 +443,6 @@ sealed interface PointMultiplier { // in little endian byte array representation. ProjectivePoint.Mutable pointMultiply(byte[] scalar); - static PointMultiplier of(ECOperations ecOps, AffinePoint affPoint) { - PointMultiplier multiplier = multipliers.get(affPoint.toECPoint()); - if (multiplier == null) { - multiplier = new Default(ecOps, affPoint); - } - - return multiplier; - } - - static PointMultiplier of(ECOperations ecOps, ECPoint ecPoint) { - PointMultiplier multiplier = multipliers.get(ecPoint); - if (multiplier == null) { - AffinePoint affPoint = - AffinePoint.fromECPoint(ecPoint, ecOps.getField()); - multiplier = new Default(ecOps, affPoint); - } - - return multiplier; - } - private static void lookup( ProjectivePoint.Immutable[] ips, int index, ProjectivePoint.Mutable result) { @@ -465,232 +459,249 @@ private static void lookup( result.conditionalSet(pi, set); } } + } - final class Default implements PointMultiplier { - private final AffinePoint affineP; - private final ECOperations ecOps; + final static class DefaultMultiplier implements PointMultiplier { + private final ECOperations ecOps; + private final ProjectivePoint.Immutable[] pointMultiples; - private Default(ECOperations ecOps, AffinePoint affineP) { - this.ecOps = ecOps; - this.affineP = affineP; - } + DefaultMultiplier(ECOperations ecOps, AffinePoint affineP) { + this.ecOps = ecOps; - @Override - public ProjectivePoint.Mutable pointMultiply(byte[] s) { - // 4-bit windowed multiply with branchless lookup. - // The mixed addition is faster, so it is used to construct - // the array at the beginning of the operation. - - IntegerFieldModuloP field = affineP.getX().getField(); - ImmutableIntegerModuloP zero = field.get0(); - // temporaries - MutableIntegerModuloP t0 = zero.mutable(); - MutableIntegerModuloP t1 = zero.mutable(); - MutableIntegerModuloP t2 = zero.mutable(); - MutableIntegerModuloP t3 = zero.mutable(); - MutableIntegerModuloP t4 = zero.mutable(); - - ProjectivePoint.Mutable result = - new ProjectivePoint.Mutable(field); - result.getY().setValue(field.get1().mutable()); - - ProjectivePoint.Immutable[] pointMultiples = - new ProjectivePoint.Immutable[16]; - // 0P is neutral---same as initial result value - pointMultiples[0] = result.fixed(); - - ProjectivePoint.Mutable ps = new ProjectivePoint.Mutable(field); - ps.setValue(affineP); - // 1P = P - pointMultiples[1] = ps.fixed(); - - // the rest are calculated using mixed point addition - for (int i = 2; i < 16; i++) { - ecOps.setSum(ps, affineP, t0, t1, t2, t3, t4); - pointMultiples[i] = ps.fixed(); - } + // Precompute and cache point multiples + this.pointMultiples = new ProjectivePoint.Immutable[16]; - ProjectivePoint.Mutable lookupResult = ps.mutable(); + IntegerFieldModuloP field = ecOps.getField(); + ImmutableIntegerModuloP zero = field.get0(); + // temporaries + MutableIntegerModuloP t0 = zero.mutable(); + MutableIntegerModuloP t1 = zero.mutable(); + MutableIntegerModuloP t2 = zero.mutable(); + MutableIntegerModuloP t3 = zero.mutable(); + MutableIntegerModuloP t4 = zero.mutable(); - for (int i = s.length - 1; i >= 0; i--) { - double4(result, t0, t1, t2, t3, t4); + ProjectivePoint.Mutable ps = + new ProjectivePoint.Mutable(field); + ps.getY().setValue(field.get1().mutable()); - int high = (0xFF & s[i]) >>> 4; - lookup(pointMultiples, high, lookupResult); - ecOps.setSum(result, lookupResult, t0, t1, t2, t3, t4); + // 0P is neutral---same as initial result value + pointMultiples[0] = ps.fixed(); - double4(result, t0, t1, t2, t3, t4); + ps.setValue(affineP); + // 1P = P + pointMultiples[1] = ps.fixed(); - int low = 0xF & s[i]; - lookup(pointMultiples, low, lookupResult); - ecOps.setSum(result, lookupResult, t0, t1, t2, t3, t4); - } + // the rest are calculated using mixed point addition + for (int i = 2; i < 16; i++) { + ecOps.setSum(ps, affineP, t0, t1, t2, t3, t4); + pointMultiples[i] = ps.fixed(); + } + } - return result; + @Override + public ProjectivePoint.Mutable pointMultiply(byte[] s) { + // 4-bit windowed multiply with branchless lookup. + // The mixed addition is faster, so it is used to construct + // the array at the beginning of the operation. + + IntegerFieldModuloP field = ecOps.getField(); + ImmutableIntegerModuloP zero = field.get0(); + // temporaries + MutableIntegerModuloP t0 = zero.mutable(); + MutableIntegerModuloP t1 = zero.mutable(); + MutableIntegerModuloP t2 = zero.mutable(); + MutableIntegerModuloP t3 = zero.mutable(); + MutableIntegerModuloP t4 = zero.mutable(); + + ProjectivePoint.Mutable result = new ProjectivePoint.Mutable(field); + result.getY().setValue(field.get1().mutable()); + ProjectivePoint.Mutable lookupResult = new ProjectivePoint.Mutable(field); + + for (int i = s.length - 1; i >= 0; i--) { + double4(result, t0, t1, t2, t3, t4); + + int high = (0xFF & s[i]) >>> 4; + PointMultiplier.lookup(pointMultiples, high, lookupResult); + ecOps.setSum(result, lookupResult, t0, t1, t2, t3, t4); + + double4(result, t0, t1, t2, t3, t4); + + int low = 0xF & s[i]; + PointMultiplier.lookup(pointMultiples, low, lookupResult); + ecOps.setSum(result, lookupResult, t0, t1, t2, t3, t4); } - private void double4(ProjectivePoint.Mutable p, - MutableIntegerModuloP t0, MutableIntegerModuloP t1, - MutableIntegerModuloP t2, MutableIntegerModuloP t3, - MutableIntegerModuloP t4) { - for (int i = 0; i < 4; i++) { - ecOps.setDouble(p, t0, t1, t2, t3, t4); - } + return result; + } + + private void double4(ProjectivePoint.Mutable p, + MutableIntegerModuloP t0, MutableIntegerModuloP t1, + MutableIntegerModuloP t2, MutableIntegerModuloP t3, + MutableIntegerModuloP t4) { + for (int i = 0; i < 4; i++) { + ecOps.setDouble(p, t0, t1, t2, t3, t4); + } + } + } + + // Represents a multiplier with a larger precomputed table. Intended to be + // used for Basepoint multiplication + final static class Secp256R1GeneratorMontgomeryMultiplier + implements PointMultiplier { + private static final ECOperations secp256r1Ops = new ECOperations( + MontgomeryIntegerPolynomialP256.ONE.getElement( + CurveDB.P_256.getCurve().getB()), P256OrderField.ONE); + public static final AffinePoint generator = AffinePoint.fromECPoint( + CurveDB.P_256.getGenerator(), secp256r1Ops.getField()); + public static final PointMultiplier multiplier = + new Secp256R1GeneratorMontgomeryMultiplier(); + + private final ImmutableIntegerModuloP zero; + private final ImmutableIntegerModuloP one; + private final ProjectivePoint.Immutable[][] points; + private final BigInteger[] base; + + private Secp256R1GeneratorMontgomeryMultiplier() { + this(MontgomeryIntegerPolynomialP256.ONE, + new DefaultMultiplier(secp256r1Ops, generator)); + + // Check that the tables are correctly generated. + if (ECOperations.class.desiredAssertionStatus()) { + verifyTables(this); } } - final class Secp256R1GeneratorMultiplier implements PointMultiplier { - private static final ECPoint generator = - CurveDB.P_256.getGenerator(); - private static final PointMultiplier multiplier = - new Secp256R1GeneratorMultiplier(); - - private static final ImmutableIntegerModuloP zero = - IntegerPolynomialP256.ONE.get0(); - private static final ImmutableIntegerModuloP one = - IntegerPolynomialP256.ONE.get1(); - - @Override - public ProjectivePoint.Mutable pointMultiply(byte[] s) { - MutableIntegerModuloP t0 = zero.mutable(); - MutableIntegerModuloP t1 = zero.mutable(); - MutableIntegerModuloP t2 = zero.mutable(); - MutableIntegerModuloP t3 = zero.mutable(); - MutableIntegerModuloP t4 = zero.mutable(); - - ProjectivePoint.Mutable d = new ProjectivePoint.Mutable( - zero.mutable(), - one.mutable(), - zero.mutable()); - ProjectivePoint.Mutable r = d.mutable(); - for (int i = 15; i >= 0; i--) { - secp256r1Ops.setDouble(d, t0, t1, t2, t3, t4); - for (int j = 3; j >= 0; j--) { - int pos = i + j * 16; - int index = (bit(s, pos + 192) << 3) | - (bit(s, pos + 128) << 2) | - (bit(s, pos + 64) << 1) | - bit(s, pos); - - lookup(P256.points[j], index, r); - secp256r1Ops.setSum(d, r, t0, t1, t2, t3, t4); + private Secp256R1GeneratorMontgomeryMultiplier( + IntegerFieldModuloP field, PointMultiplier smallTableMultiplier) { + zero = field.get0(); + one = field.get1(); + + // Pre-computed table to speed up the point multiplication. + // + // This is a 4x16 array of ProjectivePoint.Immutable elements. + // The first row contains the following multiples of the + // generator. + // + // index | point + // --------+---------------- + // 0x0000 | 0G + // 0x0001 | 1G + // 0x0002 | (2^64)G + // 0x0003 | (2^64 + 1)G + // 0x0004 | 2^128G + // 0x0005 | (2^128 + 1)G + // 0x0006 | (2^128 + 2^64)G + // 0x0007 | (2^128 + 2^64 + 1)G + // 0x0008 | 2^192G + // 0x0009 | (2^192 + 1)G + // 0x000A | (2^192 + 2^64)G + // 0x000B | (2^192 + 2^64 + 1)G + // 0x000C | (2^192 + 2^128)G + // 0x000D | (2^192 + 2^128 + 1)G + // 0x000E | (2^192 + 2^128 + 2^64)G + // 0x000F | (2^192 + 2^128 + 2^64 + 1)G + // + // For the other 3 rows, points[i][j] = 2^16 * (points[i-1][j]. + + // Generate the pre-computed tables. This block may be + // replaced with hard-coded tables in order to speed up + // the class loading. + points = new ProjectivePoint.Immutable[4][16]; + BigInteger[] factors = new BigInteger[] { + BigInteger.ONE, + BigInteger.TWO.pow(64), + BigInteger.TWO.pow(128), + BigInteger.TWO.pow(192) + }; + + base = new BigInteger[16]; + base[0] = BigInteger.ZERO; + base[1] = BigInteger.ONE; + base[2] = factors[1]; + for (int i = 3; i < 16; i++) { + base[i] = BigInteger.ZERO; + for (int k = 0; k < 4; k++) { + if (((i >>> k) & 0x01) != 0) { + base[i] = base[i].add(factors[k]); } } + } - return d; + for (int d = 0; d < 4; d++) { + for (int w = 0; w < 16; w++) { + BigInteger bi = base[w]; + if (d != 0) { + bi = bi.multiply(BigInteger.TWO.pow(d * 16)); + } + if (w == 0) { + points[d][0] = new ProjectivePoint.Immutable( + zero.fixed(), one.fixed(), zero.fixed()); + } else { + byte[] s = bi.toByteArray(); + ArrayUtil.reverse(s); + ProjectivePoint.Mutable m = smallTableMultiplier.pointMultiply(s); + points[d][w] = m.fixed(); + } + } } + } - private static int bit(byte[] k, int i) { - return (k[i >> 3] >> (i & 0x07)) & 0x01; + public ProjectivePoint.Mutable pointMultiply(byte[] s) { + MutableIntegerModuloP t0 = zero.mutable(); + MutableIntegerModuloP t1 = zero.mutable(); + MutableIntegerModuloP t2 = zero.mutable(); + MutableIntegerModuloP t3 = zero.mutable(); + MutableIntegerModuloP t4 = zero.mutable(); + + ProjectivePoint.Mutable d = new ProjectivePoint.Mutable( + zero.mutable(), + one.mutable(), + zero.mutable()); + ProjectivePoint.Mutable r = d.mutable(); + for (int i = 15; i >= 0; i--) { + secp256r1Ops.setDouble(d, t0, t1, t2, t3, t4); + for (int j = 3; j >= 0; j--) { + int pos = i + j * 16; + int index = (bit(s, pos + 192) << 3) | + (bit(s, pos + 128) << 2) | + (bit(s, pos + 64) << 1) | + bit(s, pos); + + PointMultiplier.lookup(points[j], index, r); + secp256r1Ops.setSum(d, r, t0, t1, t2, t3, t4); + } } - // Lazy loading of the tables. - private static final class P256 { - // Pre-computed table to speed up the point multiplication. - // - // This is a 4x16 array of ProjectivePoint.Immutable elements. - // The first row contains the following multiples of the - // generator. - // - // index | point - // --------+---------------- - // 0x0000 | 0G - // 0x0001 | 1G - // 0x0002 | (2^64)G - // 0x0003 | (2^64 + 1)G - // 0x0004 | 2^128G - // 0x0005 | (2^128 + 1)G - // 0x0006 | (2^128 + 2^64)G - // 0x0007 | (2^128 + 2^64 + 1)G - // 0x0008 | 2^192G - // 0x0009 | (2^192 + 1)G - // 0x000A | (2^192 + 2^64)G - // 0x000B | (2^192 + 2^64 + 1)G - // 0x000C | (2^192 + 2^128)G - // 0x000D | (2^192 + 2^128 + 1)G - // 0x000E | (2^192 + 2^128 + 2^64)G - // 0x000F | (2^192 + 2^128 + 2^64 + 1)G - // - // For the other 3 rows, points[i][j] = 2^16 * (points[i-1][j]. - private static final ProjectivePoint.Immutable[][] points; - - // Generate the pre-computed tables. This block may be - // replaced with hard-coded tables in order to speed up - // the class loading. - static { - points = new ProjectivePoint.Immutable[4][16]; - BigInteger[] factors = new BigInteger[] { - BigInteger.ONE, - BigInteger.TWO.pow(64), - BigInteger.TWO.pow(128), - BigInteger.TWO.pow(192) - }; - - BigInteger[] base = new BigInteger[16]; - base[0] = BigInteger.ZERO; - base[1] = BigInteger.ONE; - base[2] = factors[1]; - for (int i = 3; i < 16; i++) { - base[i] = BigInteger.ZERO; - for (int k = 0; k < 4; k++) { - if (((i >>> k) & 0x01) != 0) { - base[i] = base[i].add(factors[k]); - } - } - } + return d; + } - for (int d = 0; d < 4; d++) { - for (int w = 0; w < 16; w++) { - BigInteger bi = base[w]; - if (d != 0) { - bi = bi.multiply(BigInteger.TWO.pow(d * 16)); - } - if (w == 0) { - points[d][0] = new ProjectivePoint.Immutable( - zero.fixed(), one.fixed(), zero.fixed()); - } else { - PointMultiplier multiplier = new Default( - secp256r1Ops, AffinePoint.fromECPoint( - generator, zero.getField())); - byte[] s = bi.toByteArray(); - ArrayUtil.reverse(s); - ProjectivePoint.Mutable m = - multiplier.pointMultiply(s); - points[d][w] = m.setValue(m.asAffine()).fixed(); - } - } - } + private static int bit(byte[] k, int i) { + return (k[i >> 3] >> (i & 0x07)) & 0x01; + } - // Check that the tables are correctly generated. - if (ECOperations.class.desiredAssertionStatus()) { - verifyTables(base); + protected void verifyTables(PointMultiplier multiplier) { + for (int d = 0; d < 4; d++) { + for (int w = 0; w < 16; w++) { + BigInteger bi = base[w]; + if (d != 0) { + bi = bi.multiply(BigInteger.TWO.pow(d * 16)); } - } - - private static void verifyTables(BigInteger[] base) { - for (int d = 0; d < 4; d++) { - for (int w = 0; w < 16; w++) { - BigInteger bi = base[w]; - if (d != 0) { - bi = bi.multiply(BigInteger.TWO.pow(d * 16)); - } - if (w != 0) { - byte[] s = new byte[32]; - byte[] b = bi.toByteArray(); - ArrayUtil.reverse(b); - System.arraycopy(b, 0, s, 0, b.length); - - ProjectivePoint.Mutable m = - multiplier.pointMultiply(s); - ProjectivePoint.Immutable v = - m.setValue(m.asAffine()).fixed(); - if (!v.getX().asBigInteger().equals( - points[d][w].getX().asBigInteger()) || - !v.getY().asBigInteger().equals( - points[d][w].getY().asBigInteger())) { - throw new RuntimeException(); - } - } + if (w != 0) { + byte[] s = new byte[32]; + byte[] b = bi.toByteArray(); + ArrayUtil.reverse(b); + System.arraycopy(b, 0, s, 0, b.length); + + // Compare this multiplier to the table + // (generated by Default multiplier) + AffinePoint m = multiplier.pointMultiply(s).asAffine(); + AffinePoint v = points[d][w].asAffine(); + if (!m.equals(v)) { + java.util.HexFormat hex = java.util.HexFormat.of(); + throw new RuntimeException( + "Bad multiple found at [" +d+"]["+w+"]" + + hex.formatHex(s) + " " + m.getX().asBigInteger() + ); } } } diff --git a/src/java.base/share/classes/sun/security/ec/point/AffinePoint.java b/src/java.base/share/classes/sun/security/ec/point/AffinePoint.java index bc227b0babfca..bc1530cd61bdb 100644 --- a/src/java.base/share/classes/sun/security/ec/point/AffinePoint.java +++ b/src/java.base/share/classes/sun/security/ec/point/AffinePoint.java @@ -26,6 +26,7 @@ import sun.security.util.math.ImmutableIntegerModuloP; import sun.security.util.math.IntegerFieldModuloP; +import sun.security.util.math.IntegerMontgomeryFieldModuloP; import java.security.spec.ECPoint; import java.util.Objects; @@ -54,14 +55,30 @@ public static AffinePoint fromECPoint( } public ECPoint toECPoint() { - return new ECPoint(x.asBigInteger(), y.asBigInteger()); + return new ECPoint(getX().asBigInteger(), getY().asBigInteger()); } public ImmutableIntegerModuloP getX() { + return getX(true); + } + + public ImmutableIntegerModuloP getX(boolean fieldCheck) { + IntegerFieldModuloP field = x.getField(); + if (fieldCheck && field instanceof IntegerMontgomeryFieldModuloP) { + return ((IntegerMontgomeryFieldModuloP)field).fromMontgomery(x); + } return x; } public ImmutableIntegerModuloP getY() { + return getY(true); + } + + public ImmutableIntegerModuloP getY(boolean fieldCheck) { + IntegerFieldModuloP field = y.getField(); + if (fieldCheck && field instanceof IntegerMontgomeryFieldModuloP) { + return ((IntegerMontgomeryFieldModuloP)field).fromMontgomery(y); + } return y; } @@ -71,8 +88,30 @@ public boolean equals(Object obj) { return false; } AffinePoint p = (AffinePoint) obj; - boolean xEquals = x.asBigInteger().equals(p.x.asBigInteger()); - boolean yEquals = y.asBigInteger().equals(p.y.asBigInteger()); + boolean xEquals, yEquals; + boolean thisMont = x.getField() instanceof IntegerMontgomeryFieldModuloP; + boolean objMont = p.x.getField() instanceof IntegerMontgomeryFieldModuloP; + if (thisMont ^ objMont == false) { + // both fields same + xEquals = x.asBigInteger().equals(p.x.asBigInteger()); + yEquals = y.asBigInteger().equals(p.y.asBigInteger()); + } else if (thisMont) { + // mismatched fields should not happen in production, but useful in + // testing + IntegerMontgomeryFieldModuloP field = + (IntegerMontgomeryFieldModuloP)x.getField(); + xEquals = x.asBigInteger().equals( + field.getElement(p.x.asBigInteger()).asBigInteger()); + yEquals = y.asBigInteger().equals( + field.getElement(p.y.asBigInteger()).asBigInteger()); + } else { + IntegerMontgomeryFieldModuloP field = + (IntegerMontgomeryFieldModuloP)p.x.getField(); + xEquals = field.getElement( + x.asBigInteger()).asBigInteger().equals(p.x.asBigInteger()); + yEquals = field.getElement( + y.asBigInteger()).asBigInteger().equals(p.y.asBigInteger()); + } return xEquals && yEquals; } diff --git a/src/java.base/share/classes/sun/security/ec/point/ProjectivePoint.java b/src/java.base/share/classes/sun/security/ec/point/ProjectivePoint.java index a3ebc532d4693..fbb6681b724ac 100644 --- a/src/java.base/share/classes/sun/security/ec/point/ProjectivePoint.java +++ b/src/java.base/share/classes/sun/security/ec/point/ProjectivePoint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ package sun.security.ec.point; import sun.security.util.math.*; +import jdk.internal.vm.annotation.ForceInline; /** * Elliptic curve point in projective coordinates (X, Y, Z) where @@ -145,6 +146,7 @@ public Mutable conditionalSet(Point p, int set) { return conditionalSet(pp, set); } + @ForceInline private Mutable conditionalSet(ProjectivePoint pp, int set) { @@ -157,9 +159,9 @@ Mutable conditionalSet(ProjectivePoint pp, int set) { @Override public Mutable setValue(AffinePoint p) { - x.setValue(p.getX()); - y.setValue(p.getY()); - z.setValue(p.getX().getField().get1()); + x.setValue(p.getX(false)); + y.setValue(p.getY(false)); + z.setValue(p.getX(false).getField().get1()); return this; } diff --git a/src/java.base/share/classes/sun/security/util/math/IntegerMontgomeryFieldModuloP.java b/src/java.base/share/classes/sun/security/util/math/IntegerMontgomeryFieldModuloP.java new file mode 100644 index 0000000000000..2987674a32b14 --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/math/IntegerMontgomeryFieldModuloP.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util.math; + +import java.math.BigInteger; + +/** + * An interface for the field of integers modulo a prime number. An + * implementation of this interface can be used to get properties of the + * field and to produce field elements of type ImmutableIntegerModuloP from + * other objects and representations of field elements. + */ + +public interface IntegerMontgomeryFieldModuloP extends IntegerFieldModuloP { + ImmutableIntegerModuloP fromMontgomery(ImmutableIntegerModuloP m); + IntegerFieldModuloP residueField(); +} diff --git a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java index 18ee87e0b240d..05b4a71bebb51 100644 --- a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java +++ b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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.nio.ByteOrder; import java.util.Arrays; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.IntrinsicCandidate; + /** * A large number polynomial representation using sparse limbs of signed * long (64-bit) values. Limb values will always fit within a long, so inputs @@ -62,10 +65,9 @@ public abstract sealed class IntegerPolynomial implements IntegerFieldModuloP permits IntegerPolynomial1305, IntegerPolynomial25519, IntegerPolynomial448, IntegerPolynomialP256, - IntegerPolynomialP384, IntegerPolynomialP521, - IntegerPolynomialModBinP, P256OrderField, - P384OrderField, P521OrderField, - Curve25519OrderField, + MontgomeryIntegerPolynomialP256, IntegerPolynomialP384, + IntegerPolynomialP521, IntegerPolynomialModBinP, P256OrderField, + P384OrderField, P521OrderField, Curve25519OrderField, Curve448OrderField { protected static final BigInteger TWO = BigInteger.valueOf(2); @@ -74,7 +76,8 @@ public abstract sealed class IntegerPolynomial implements IntegerFieldModuloP private final BigInteger modulus; protected final int bitsPerLimb; private final long[] posModLimbs; - private final int maxAdds; + private final int maxAddsMul; // max additions before a multiplication + private final int maxAddsAdd; // max additions before an addition /** * Reduce an IntegerPolynomial representation (a) and store the result @@ -87,11 +90,12 @@ public abstract sealed class IntegerPolynomial implements IntegerFieldModuloP * store the result in an IntegerPolynomial representation in a. Requires * that a.length == numLimbs. */ - protected void multByInt(long[] a, long b) { + protected int multByInt(long[] a, long b) { for (int i = 0; i < a.length; i++) { a[i] *= b; } reduce(a); + return 0; } /** @@ -100,7 +104,7 @@ protected void multByInt(long[] a, long b) { * a.length == b.length == r.length == numLimbs. It is allowed for a and r * to be the same array. */ - protected abstract void mult(long[] a, long[] b, long[] r); + protected abstract int mult(long[] a, long[] b, long[] r); /** * Multiply an IntegerPolynomial representation (a) with itself and store @@ -108,19 +112,23 @@ protected void multByInt(long[] a, long b) { * a.length == r.length == numLimbs. It is allowed for a and r * to be the same array. */ - protected abstract void square(long[] a, long[] r); + protected abstract int square(long[] a, long[] r); IntegerPolynomial(int bitsPerLimb, int numLimbs, - int maxAdds, + int maxAddsMul, BigInteger modulus) { this.numLimbs = numLimbs; this.modulus = modulus; this.bitsPerLimb = bitsPerLimb; - this.maxAdds = maxAdds; - + this.maxAddsMul = maxAddsMul; + if (bitsPerLimb>32) { + this.maxAddsAdd = 64 - bitsPerLimb; + } else { + this.maxAddsAdd = 32 - bitsPerLimb; + } posModLimbs = setPosModLimbs(); } @@ -135,7 +143,7 @@ protected int getNumLimbs() { } public int getMaxAdds() { - return maxAdds; + return maxAddsMul; } @Override @@ -327,10 +335,9 @@ private void setLimbsValue(BigInteger v, long[] limbs) { } protected void setLimbsValuePositive(BigInteger v, long[] limbs) { - assert bitsPerLimb < 32; long limbMask = (1L << bitsPerLimb) - 1; for (int i = 0; i < limbs.length; i++) { - limbs[i] = v.intValue() & limbMask; + limbs[i] = v.longValue() & limbMask; v = v.shiftRight(bitsPerLimb); } } @@ -449,6 +456,8 @@ protected void addLimbs(long[] a, long[] b, long[] dst) { * will be unchanged. If set==1, then the values of b will be assigned to a. * The behavior is undefined if swap has any value other than 0 or 1. */ + @ForceInline + @IntrinsicCandidate protected static void conditionalAssign(int set, long[] a, long[] b) { int maskValue = -set; for (int i = 0; i < a.length; i++) { @@ -557,14 +566,12 @@ public ImmutableElement add(IntegerModuloP genB) { Element b = (Element)genB; // Reduce if required. - // if (numAdds >= maxAdds) { - if (numAdds > 32 - bitsPerLimb) { + if (numAdds > maxAddsAdd) { reduce(limbs); numAdds = 0; } - // if (b.numAdds >= maxAdds) { - if (b.numAdds > 32 - bitsPerLimb) { + if (b.numAdds > maxAddsAdd) { reduce(b.limbs); b.numAdds = 0; } @@ -586,7 +593,7 @@ public ImmutableElement additiveInverse() { newLimbs[i] = -limbs[i]; } - return new ImmutableElement(newLimbs, numAdds); + return new ImmutableElement(newLimbs, numAdds+1); } protected long[] cloneLow(long[] limbs) { @@ -604,32 +611,32 @@ public ImmutableElement multiply(IntegerModuloP genB) { Element b = (Element)genB; // Reduce if required. - if (numAdds > maxAdds) { + if (numAdds > maxAddsMul) { reduce(limbs); numAdds = 0; } - if (b.numAdds > maxAdds) { + if (b.numAdds > maxAddsMul) { reduce(b.limbs); b.numAdds = 0; } long[] newLimbs = new long[limbs.length]; - mult(limbs, b.limbs, newLimbs); - return new ImmutableElement(newLimbs, 0); + int numAdds = mult(limbs, b.limbs, newLimbs); + return new ImmutableElement(newLimbs, numAdds); } @Override public ImmutableElement square() { // Reduce if required. - if (numAdds > maxAdds) { + if (numAdds > maxAddsMul) { reduce(limbs); numAdds = 0; } long[] newLimbs = new long[limbs.length]; - IntegerPolynomial.this.square(limbs, newLimbs); - return new ImmutableElement(newLimbs, 0); + int numAdds = IntegerPolynomial.this.square(limbs, newLimbs); + return new ImmutableElement(newLimbs, numAdds); } public void addModPowerTwo(IntegerModuloP arg, byte[] result) { @@ -637,12 +644,12 @@ public void addModPowerTwo(IntegerModuloP arg, byte[] result) { Element other = (Element)arg; // Reduce if required. - if (numAdds > 32 - bitsPerLimb) { + if (numAdds > maxAddsAdd) { reduce(limbs); numAdds = 0; } - if (other.numAdds > 32 - bitsPerLimb) { + if (other.numAdds > maxAddsAdd) { reduce(other.limbs); other.numAdds = 0; } @@ -734,32 +741,30 @@ public MutableElement setProduct(IntegerModuloP genB) { Element b = (Element)genB; // Reduce if required. - if (numAdds > maxAdds) { + if (numAdds > maxAddsMul) { reduce(limbs); numAdds = 0; } - if (b.numAdds > maxAdds) { + if (b.numAdds > maxAddsMul) { reduce(b.limbs); b.numAdds = 0; } - mult(limbs, b.limbs, limbs); - numAdds = 0; + numAdds = mult(limbs, b.limbs, limbs); return this; } @Override public MutableElement setProduct(SmallValue v) { // Reduce if required. - if (numAdds > maxAdds) { + if (numAdds > maxAddsMul) { reduce(limbs); numAdds = 0; } int value = ((Limb)v).value; - multByInt(limbs, value); - numAdds = 0; + numAdds += multByInt(limbs, value); return this; } @@ -769,14 +774,12 @@ public MutableElement setSum(IntegerModuloP genB) { Element b = (Element)genB; // Reduce if required. - // if (numAdds >= maxAdds) { - if (numAdds > 32 - bitsPerLimb) { + if (numAdds > maxAddsAdd) { reduce(limbs); numAdds = 0; } - // if (b.numAdds >= maxAdds) { - if (b.numAdds > 32 - bitsPerLimb) { + if (b.numAdds > maxAddsAdd) { reduce(b.limbs); b.numAdds = 0; } @@ -795,14 +798,12 @@ public MutableElement setDifference(IntegerModuloP genB) { Element b = (Element)genB; // Reduce if required. - // if (numAdds >= maxAdds) { - if (numAdds > 32 - bitsPerLimb) { + if (numAdds > maxAddsAdd) { reduce(limbs); numAdds = 0; } - // if (b.numAdds >= maxAdds) { - if (b.numAdds > 32 - bitsPerLimb) { + if (b.numAdds > maxAddsAdd) { reduce(b.limbs); b.numAdds = 0; } @@ -818,13 +819,12 @@ public MutableElement setDifference(IntegerModuloP genB) { @Override public MutableElement setSquare() { // Reduce if required. - if (numAdds > maxAdds) { + if (numAdds > maxAddsMul) { reduce(limbs); numAdds = 0; } - IntegerPolynomial.this.square(limbs, limbs); - numAdds = 0; + numAdds = IntegerPolynomial.this.square(limbs, limbs);; return this; } @@ -833,6 +833,7 @@ public MutableElement setAdditiveInverse() { for (int i = 0; i < limbs.length; i++) { limbs[i] = -limbs[i]; } + numAdds++; return this; } } diff --git a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java index 5015d186d37b9..706651330d389 100644 --- a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java +++ b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomial1305.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -50,7 +50,7 @@ private IntegerPolynomial1305() { super(BITS_PER_LIMB, NUM_LIMBS, 1, MODULUS); } - protected void mult(long[] a, long[] b, long[] r) { + protected int mult(long[] a, long[] b, long[] r) { // Use grade-school multiplication into primitives to avoid the // temporary array allocation. This is equivalent to the following @@ -73,6 +73,7 @@ protected void mult(long[] a, long[] b, long[] r) { long c8 = (a[4] * b[4]); carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8); + return 0; } private void carryReduce(long[] r, long c0, long c1, long c2, long c3, @@ -99,7 +100,7 @@ private void carryReduce(long[] r, long c0, long c1, long c2, long c3, } @Override - protected void square(long[] a, long[] r) { + protected int square(long[] a, long[] r) { // Use grade-school multiplication with a simple squaring optimization. // Multiply into primitives to avoid the temporary array allocation. // This is equivalent to the following code: @@ -122,6 +123,7 @@ protected void square(long[] a, long[] r) { long c8 = (a[4] * a[4]); carryReduce(r, c0, c1, c2, c3, c4, c5, c6, c7, c8); + return 0; } @Override diff --git a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomialModBinP.java b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomialModBinP.java index c6e58322d7cad..e57316ed964f6 100644 --- a/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomialModBinP.java +++ b/src/java.base/share/classes/sun/security/util/math/intpoly/IntegerPolynomialModBinP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,11 +131,12 @@ private void multOnly(long[] a, long[] b, long[] c) { } @Override - protected void mult(long[] a, long[] b, long[] r) { + protected int mult(long[] a, long[] b, long[] r) { long[] c = new long[2 * numLimbs]; multOnly(a, b, c); carryReduce(c, r); + return 0; } private void modReduceInBits(long[] limbs, int index, int bits, long x) { @@ -188,7 +189,7 @@ protected void reduce(long[] a) { } @Override - protected void square(long[] a, long[] r) { + protected int square(long[] a, long[] r) { long[] c = new long[2 * numLimbs]; for (int i = 0; i < numLimbs; i++) { @@ -199,7 +200,7 @@ protected void square(long[] a, long[] r) { } carryReduce(c, r); - + return 0; } /** diff --git a/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java b/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java new file mode 100644 index 0000000000000..d4c0348eb9d5a --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/math/intpoly/MontgomeryIntegerPolynomialP256.java @@ -0,0 +1,560 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util.math.intpoly; + +import sun.security.util.math.ImmutableIntegerModuloP; +import sun.security.util.math.IntegerMontgomeryFieldModuloP; +import sun.security.util.math.SmallValue; +import sun.security.util.math.IntegerFieldModuloP; +import java.lang.Math; +import java.math.BigInteger; +import jdk.internal.vm.annotation.IntrinsicCandidate; + +// Reference: +// - [1] Shay Gueron and Vlad Krasnov "Fast Prime Field Elliptic Curve +// Cryptography with 256 Bit Primes" +// +public final class MontgomeryIntegerPolynomialP256 extends IntegerPolynomial + implements IntegerMontgomeryFieldModuloP { + private static final int BITS_PER_LIMB = 52; + private static final int NUM_LIMBS = 5; + private static final int MAX_ADDS = 0; + public static final BigInteger MODULUS = evaluateModulus(); + private static final long LIMB_MASK = -1L >>> (64 - BITS_PER_LIMB); + + public static final MontgomeryIntegerPolynomialP256 ONE = new MontgomeryIntegerPolynomialP256(); + + // h = 2^(2*260)%p = 0x4fffffffdfffffffffffffffefffffffbffffffff000000000000000300 + // oneActual = 1 + // oneMont = (1*2^260) mod p + // modulus = p + private static final long[] h = new long[] { + 0x0000000000000300L, 0x000ffffffff00000L, 0x000ffffefffffffbL, + 0x000fdfffffffffffL, 0x0000000004ffffffL }; + private static final long[] oneActual = new long[] { + 0x0000000000000001L, 0x0000000000000000L, 0x0000000000000000L, + 0x0000000000000000L, 0x0000000000000000L }; + private static final long[] oneMont = new long[] { + 0x0000000000000010L, 0x000f000000000000L, 0x000fffffffffffffL, + 0x000ffeffffffffffL, 0x00000000000fffffL }; + private static final long[] zero = new long[] { + 0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L, + 0x0000000000000000L, 0x0000000000000000L }; + private static final long[] modulus = new long[] { + 0x000fffffffffffffL, 0x00000fffffffffffL, 0x0000000000000000L, + 0x0000001000000000L, 0x0000ffffffff0000L }; + + private MontgomeryIntegerPolynomialP256() { + super(BITS_PER_LIMB, NUM_LIMBS, MAX_ADDS, MODULUS); + } + + public IntegerFieldModuloP residueField() { + return IntegerPolynomialP256.ONE; + } + + // (224%nat,-1)::(192%nat,1)::(96%nat,1)::(0%nat,-1)::nil. + private static BigInteger evaluateModulus() { + BigInteger result = BigInteger.valueOf(2).pow(256); + result = result.subtract(BigInteger.valueOf(1).shiftLeft(224)); + result = result.add(BigInteger.valueOf(1).shiftLeft(192)); + result = result.add(BigInteger.valueOf(1).shiftLeft(96)); + result = result.subtract(BigInteger.valueOf(1)); + return result; + } + + @Override + public ImmutableElement get0() { + return new ImmutableElement(zero, 0); + } + + // One in montgomery domain: (1*2^260) mod p + @Override + public ImmutableElement get1() { + return new ImmutableElement(oneMont, 0); + } + + // Convert v to Montgomery domain + @Override + public ImmutableElement getElement(BigInteger v) { + long[] vLimbs = new long[NUM_LIMBS]; + long[] montLimbs = new long[NUM_LIMBS]; + setLimbsValuePositive(v, vLimbs); + + // Convert to Montgomery domain + int numAdds = mult(vLimbs, h, montLimbs); + return new ImmutableElement(montLimbs, numAdds); + } + + @Override + public SmallValue getSmallValue(int value) { + // Explicitely here as reminder that SmallValue stays in residue domain + // See multByInt below for how this is used + return super.getSmallValue(value); + } + + /* + * This function is used by IntegerPolynomial.setProduct(SmallValue v) to + * multiply by a small constant (i.e. (int) 1,2,3,4). Instead of doing a + * montgomery conversion followed by a montgomery multiplication, just use + * the spare top (64-BITS_PER_LIMB) bits to multiply by a constant. (See [1] + * Section 4 ) + * + * Will return an unreduced value + */ + @Override + protected int multByInt(long[] a, long b) { + assert (b < (1 << BITS_PER_LIMB)); + for (int i = 0; i < a.length; i++) { + a[i] *= b; + } + return (int) (b - 1); + } + + @Override + public ImmutableIntegerModuloP fromMontgomery(ImmutableIntegerModuloP n) { + assert n.getField() == MontgomeryIntegerPolynomialP256.ONE; + + ImmutableElement nn = (ImmutableElement) n; + long[] r1 = new long[NUM_LIMBS]; + long[] r2 = new long[2 * NUM_LIMBS]; + long[] limbs = nn.getLimbs(); + reduce(limbs); + MontgomeryIntegerPolynomialP256.ONE.mult(limbs, oneActual, r1); + reduce(r1); + halfLimbs(r1, r2); + return IntegerPolynomialP256.ONE.new ImmutableElement(r2, 0); + } + + private void halfLimbs(long[] a, long[] r) { + final long HALF_BITS_LIMB = BITS_PER_LIMB / 2; + final long HALF_LIMB_MASK = -1L >>> (64 - HALF_BITS_LIMB); + r[0] = a[0] & HALF_LIMB_MASK; + r[1] = a[0] >> HALF_BITS_LIMB; + r[2] = a[1] & HALF_LIMB_MASK; + r[3] = a[1] >> HALF_BITS_LIMB; + r[4] = a[2] & HALF_LIMB_MASK; + r[5] = a[2] >> HALF_BITS_LIMB; + r[6] = a[3] & HALF_LIMB_MASK; + r[7] = a[3] >> HALF_BITS_LIMB; + r[8] = a[4] & HALF_LIMB_MASK; + r[9] = a[4] >> HALF_BITS_LIMB; + } + + @Override + protected int square(long[] a, long[] r) { + return mult(a, a, r); + } + + /** + * Unrolled Word-by-Word Montgomery Multiplication r = a * b * 2^-260 (mod P) + * + * See [1] Figure 5. "Algorithm 2: Word-by-Word Montgomery Multiplication + * for a Montgomery Friendly modulus p". Note: Step 6. Skipped; Instead use + * numAdds to reuse existing overflow logic. + */ + @IntrinsicCandidate + protected int mult(long[] a, long[] b, long[] r) { + long aa0 = a[0]; + long aa1 = a[1]; + long aa2 = a[2]; + long aa3 = a[3]; + long aa4 = a[4]; + + long bb0 = b[0]; + long bb1 = b[1]; + long bb2 = b[2]; + long bb3 = b[3]; + long bb4 = b[4]; + + final long shift1 = 64 - BITS_PER_LIMB; // 12 + final long shift2 = BITS_PER_LIMB; // 40 + + long d0, d1, d2, d3, d4; // low digits from multiplication + long dd0, dd1, dd2, dd3, dd4; // high digits from multiplication + long n, n0, n1, n2, n3, n4, + nn0, nn1, nn2, nn3, nn4; // modulus multiple digits + long c0, c1, c2, c3, c4, c5, c6, c7, c8, c9; // multiplication result + // digits for each column + + // Row 0 - multiply by aa0 and reduce out c0 + d0 = aa0 * bb0; + dd0 = Math.unsignedMultiplyHigh(aa0, bb0) << shift1 | (d0 >>> shift2); + d0 &= LIMB_MASK; + n = d0; + d1 = aa0 * bb1; + dd1 = Math.unsignedMultiplyHigh(aa0, bb1) << shift1 | (d1 >>> shift2); + d1 &= LIMB_MASK; + d2 = aa0 * bb2; + dd2 = Math.unsignedMultiplyHigh(aa0, bb2) << shift1 | (d2 >>> shift2); + d2 &= LIMB_MASK; + d3 = aa0 * bb3; + dd3 = Math.unsignedMultiplyHigh(aa0, bb3) << shift1 | (d3 >>> shift2); + d3 &= LIMB_MASK; + d4 = aa0 * bb4; + dd4 = Math.unsignedMultiplyHigh(aa0, bb4) << shift1 | (d4 >>> shift2); + d4 &= LIMB_MASK; + + n0 = n * modulus[0]; + nn0 = Math.unsignedMultiplyHigh(n, modulus[0]) << shift1 | (n0 >>> shift2); + n0 &= LIMB_MASK; + n1 = n * modulus[1]; + nn1 = Math.unsignedMultiplyHigh(n, modulus[1]) << shift1 | (n1 >>> shift2); + n1 &= LIMB_MASK; + n2 = n * modulus[2]; + nn2 = Math.unsignedMultiplyHigh(n, modulus[2]) << shift1 | (n2 >>> shift2); + n2 &= LIMB_MASK; + n3 = n * modulus[3]; + nn3 = Math.unsignedMultiplyHigh(n, modulus[3]) << shift1 | (n3 >>> shift2); + n3 &= LIMB_MASK; + n4 = n * modulus[4]; + nn4 = Math.unsignedMultiplyHigh(n, modulus[4]) << shift1 | (n4 >>> shift2); + n4 &= LIMB_MASK; + + dd0 += nn0; + d0 += n0; + dd1 += nn1; + d1 += n1; + dd2 += nn2; + d2 += n2; + dd3 += nn3; + d3 += n3; + dd4 += nn4; + d4 += n4; + + c1 = d1 + dd0 + (d0 >>> BITS_PER_LIMB); + c2 = d2 + dd1; + c3 = d3 + dd2; + c4 = d4 + dd3; + c5 = dd4; + + // Row 1 - multiply by aa1 and reduce out c1 + d0 = aa1 * bb0; + dd0 = Math.unsignedMultiplyHigh(aa1, bb0) << shift1 | (d0 >>> shift2); + d0 &= LIMB_MASK; + d0 += c1; + n = d0 & LIMB_MASK; + d1 = aa1 * bb1; + dd1 = Math.unsignedMultiplyHigh(aa1, bb1) << shift1 | (d1 >>> shift2); + d1 &= LIMB_MASK; + d2 = aa1 * bb2; + dd2 = Math.unsignedMultiplyHigh(aa1, bb2) << shift1 | (d2 >>> shift2); + d2 &= LIMB_MASK; + d3 = aa1 * bb3; + dd3 = Math.unsignedMultiplyHigh(aa1, bb3) << shift1 | (d3 >>> shift2); + d3 &= LIMB_MASK; + d4 = aa1 * bb4; + dd4 = Math.unsignedMultiplyHigh(aa1, bb4) << shift1 | (d4 >>> shift2); + d4 &= LIMB_MASK; + + n0 = n * modulus[0]; + dd0 += Math.unsignedMultiplyHigh(n, modulus[0]) << shift1 | (n0 >>> shift2); + d0 += n0 & LIMB_MASK; + n1 = n * modulus[1]; + dd1 += Math.unsignedMultiplyHigh(n, modulus[1]) << shift1 | (n1 >>> shift2); + d1 += n1 & LIMB_MASK; + n2 = n * modulus[2]; + dd2 += Math.unsignedMultiplyHigh(n, modulus[2]) << shift1 | (n2 >>> shift2); + d2 += n2 & LIMB_MASK; + n3 = n * modulus[3]; + dd3 += Math.unsignedMultiplyHigh(n, modulus[3]) << shift1 | (n3 >>> shift2); + d3 += n3 & LIMB_MASK; + n4 = n * modulus[4]; + dd4 += Math.unsignedMultiplyHigh(n, modulus[4]) << shift1 | (n4 >>> shift2); + d4 += n4 & LIMB_MASK; + + c2 += d1 + dd0 + (d0 >>> BITS_PER_LIMB); + c3 += d2 + dd1; + c4 += d3 + dd2; + c5 += d4 + dd3; + c6 = dd4; + + // Row 2 - multiply by aa2 and reduce out c2 + d0 = aa2 * bb0; + dd0 = Math.unsignedMultiplyHigh(aa2, bb0) << shift1 | (d0 >>> shift2); + d0 &= LIMB_MASK; + d0 += c2; + n = d0 & LIMB_MASK; + d1 = aa2 * bb1; + dd1 = Math.unsignedMultiplyHigh(aa2, bb1) << shift1 | (d1 >>> shift2); + d1 &= LIMB_MASK; + d2 = aa2 * bb2; + dd2 = Math.unsignedMultiplyHigh(aa2, bb2) << shift1 | (d2 >>> shift2); + d2 &= LIMB_MASK; + d3 = aa2 * bb3; + dd3 = Math.unsignedMultiplyHigh(aa2, bb3) << shift1 | (d3 >>> shift2); + d3 &= LIMB_MASK; + d4 = aa2 * bb4; + dd4 = Math.unsignedMultiplyHigh(aa2, bb4) << shift1 | (d4 >>> shift2); + d4 &= LIMB_MASK; + + n0 = n * modulus[0]; + dd0 += Math.unsignedMultiplyHigh(n, modulus[0]) << shift1 | (n0 >>> shift2); + d0 += n0 & LIMB_MASK; + n1 = n * modulus[1]; + dd1 += Math.unsignedMultiplyHigh(n, modulus[1]) << shift1 | (n1 >>> shift2); + d1 += n1 & LIMB_MASK; + n2 = n * modulus[2]; + dd2 += Math.unsignedMultiplyHigh(n, modulus[2]) << shift1 | (n2 >>> shift2); + d2 += n2 & LIMB_MASK; + n3 = n * modulus[3]; + dd3 += Math.unsignedMultiplyHigh(n, modulus[3]) << shift1 | (n3 >>> shift2); + d3 += n3 & LIMB_MASK; + n4 = n * modulus[4]; + dd4 += Math.unsignedMultiplyHigh(n, modulus[4]) << shift1 | (n4 >>> shift2); + d4 += n4 & LIMB_MASK; + + c3 += d1 + dd0 + (d0 >>> BITS_PER_LIMB); + c4 += d2 + dd1; + c5 += d3 + dd2; + c6 += d4 + dd3; + c7 = dd4; + + // Row 3 - multiply by aa3 and reduce out c3 + d0 = aa3 * bb0; + dd0 = Math.unsignedMultiplyHigh(aa3, bb0) << shift1 | (d0 >>> shift2); + d0 &= LIMB_MASK; + d0 += c3; + n = d0 & LIMB_MASK; + d1 = aa3 * bb1; + dd1 = Math.unsignedMultiplyHigh(aa3, bb1) << shift1 | (d1 >>> shift2); + d1 &= LIMB_MASK; + d2 = aa3 * bb2; + dd2 = Math.unsignedMultiplyHigh(aa3, bb2) << shift1 | (d2 >>> shift2); + d2 &= LIMB_MASK; + d3 = aa3 * bb3; + dd3 = Math.unsignedMultiplyHigh(aa3, bb3) << shift1 | (d3 >>> shift2); + d3 &= LIMB_MASK; + d4 = aa3 * bb4; + dd4 = Math.unsignedMultiplyHigh(aa3, bb4) << shift1 | (d4 >>> shift2); + d4 &= LIMB_MASK; + + n0 = n * modulus[0]; + dd0 += Math.unsignedMultiplyHigh(n, modulus[0]) << shift1 | (n0 >>> shift2); + d0 += n0 & LIMB_MASK; + n1 = n * modulus[1]; + dd1 += Math.unsignedMultiplyHigh(n, modulus[1]) << shift1 | (n1 >>> shift2); + d1 += n1 & LIMB_MASK; + n2 = n * modulus[2]; + dd2 += Math.unsignedMultiplyHigh(n, modulus[2]) << shift1 | (n2 >>> shift2); + d2 += n2 & LIMB_MASK; + n3 = n * modulus[3]; + dd3 += Math.unsignedMultiplyHigh(n, modulus[3]) << shift1 | (n3 >>> shift2); + d3 += n3 & LIMB_MASK; + n4 = n * modulus[4]; + dd4 += Math.unsignedMultiplyHigh(n, modulus[4]) << shift1 | (n4 >>> shift2); + d4 += n4 & LIMB_MASK; + + c4 += d1 + dd0 + (d0 >>> BITS_PER_LIMB); + c5 += d2 + dd1; + c6 += d3 + dd2; + c7 += d4 + dd3; + c8 = dd4; + + // Row 4 - multiply by aa3 and reduce out c4 + d0 = aa4 * bb0; + dd0 = Math.unsignedMultiplyHigh(aa4, bb0) << shift1 | (d0 >>> shift2); + d0 &= LIMB_MASK; + d0 += c4; + n = d0 & LIMB_MASK; + d1 = aa4 * bb1; + dd1 = Math.unsignedMultiplyHigh(aa4, bb1) << shift1 | (d1 >>> shift2); + d1 &= LIMB_MASK; + d2 = aa4 * bb2; + dd2 = Math.unsignedMultiplyHigh(aa4, bb2) << shift1 | (d2 >>> shift2); + d2 &= LIMB_MASK; + d3 = aa4 * bb3; + dd3 = Math.unsignedMultiplyHigh(aa4, bb3) << shift1 | (d3 >>> shift2); + d3 &= LIMB_MASK; + d4 = aa4 * bb4; + dd4 = Math.unsignedMultiplyHigh(aa4, bb4) << shift1 | (d4 >>> shift2); + d4 &= LIMB_MASK; + + n0 = n * modulus[0]; + dd0 += Math.unsignedMultiplyHigh(n, modulus[0]) << shift1 | (n0 >>> shift2); + d0 += n0 & LIMB_MASK; + n1 = n * modulus[1]; + dd1 += Math.unsignedMultiplyHigh(n, modulus[1]) << shift1 | (n1 >>> shift2); + d1 += n1 & LIMB_MASK; + n2 = n * modulus[2]; + dd2 += Math.unsignedMultiplyHigh(n, modulus[2]) << shift1 | (n2 >>> shift2); + d2 += n2 & LIMB_MASK; + n3 = n * modulus[3]; + dd3 += Math.unsignedMultiplyHigh(n, modulus[3]) << shift1 | (n3 >>> shift2); + d3 += n3 & LIMB_MASK; + n4 = n * modulus[4]; + dd4 += Math.unsignedMultiplyHigh(n, modulus[4]) << shift1 | (n4 >>> shift2); + d4 += n4 & LIMB_MASK; + + c5 += d1 + dd0 + (d0 >>> BITS_PER_LIMB); + c6 += d2 + dd1 + (c5 >>> BITS_PER_LIMB); + c7 += d3 + dd2 + (c6 >>> BITS_PER_LIMB); + c8 += d4 + dd3 + (c7 >>> BITS_PER_LIMB); + c9 = dd4 + (c8 >>> BITS_PER_LIMB); + + c5 &= LIMB_MASK; + c6 &= LIMB_MASK; + c7 &= LIMB_MASK; + c8 &= LIMB_MASK; + + // At this point, the result could overflow by one modulus. + c0 = c5 - modulus[0]; + c1 = c6 - modulus[1] + (c0 >> BITS_PER_LIMB); + c0 &= LIMB_MASK; + c2 = c7 - modulus[2] + (c1 >> BITS_PER_LIMB); + c1 &= LIMB_MASK; + c3 = c8 - modulus[3] + (c2 >> BITS_PER_LIMB); + c2 &= LIMB_MASK; + c4 = c9 - modulus[4] + (c3 >> BITS_PER_LIMB); + c3 &= LIMB_MASK; + + long mask = c4 >> BITS_PER_LIMB; // Signed shift! + + r[0] = ((c5 & mask) | (c0 & ~mask)); + r[1] = ((c6 & mask) | (c1 & ~mask)); + r[2] = ((c7 & mask) | (c2 & ~mask)); + r[3] = ((c8 & mask) | (c3 & ~mask)); + r[4] = ((c9 & mask) | (c4 & ~mask)); + + return 0; + } + + @Override + protected void finalCarryReduceLast(long[] limbs) { + reduce(limbs); + } + + @Override + protected long carryValue(long x) { + return x >> BITS_PER_LIMB; + } + + @Override + protected void postEncodeCarry(long[] v) { + // not needed because carry is unsigned + } + + // Proof: + // carry * 2^256 (mod p) == carry * [2^256 - p] (mod p) + // == carry * [2^256 - (2^256 -2^224 +2^192 +2^96 -1)] (mod p) + // == carry * [2^224 -2^192 -2^96 +1] (mod p) + @Override + protected void reduce(long[] limbs) { + long b0 = limbs[0]; + long b1 = limbs[1]; + long b2 = limbs[2]; + long b3 = limbs[3]; + long b4 = limbs[4]; + long carry = b4 >> 48; // max 16-bits + b4 -= carry << 48; + + // 2^0 position + b0 += carry; + // -2^96 + b1 -= carry << 44; + // -2^192 + b3 -= carry << 36; + // 2^224 + b4 += carry << 16; + + b1 += b0 >> BITS_PER_LIMB; + b2 += b1 >> BITS_PER_LIMB; + b3 += b2 >> BITS_PER_LIMB; + b4 += b3 >> BITS_PER_LIMB; + + b0 &= LIMB_MASK; + b1 &= LIMB_MASK; + b2 &= LIMB_MASK; + b3 &= LIMB_MASK; + + long c0, c1, c2, c3, c4; + c0 = modulus[0] + b0; + c1 = modulus[1] + b1 + (c0 >> BITS_PER_LIMB); + c0 &= LIMB_MASK; + c2 = modulus[2] + b2 + (c1 >> BITS_PER_LIMB); + c1 &= LIMB_MASK; + c3 = modulus[3] + b3 + (c2 >> BITS_PER_LIMB); + c2 &= LIMB_MASK; + c4 = modulus[4] + b4 + (c3 >> BITS_PER_LIMB); + c3 &= LIMB_MASK; + + long mask = b4 >> BITS_PER_LIMB; // Signed shift! + + limbs[0] = (b0 & ~mask) | (c0 & mask); + limbs[1] = (b1 & ~mask) | (c1 & mask); + limbs[2] = (b2 & ~mask) | (c2 & mask); + limbs[3] = (b3 & ~mask) | (c3 & mask); + limbs[4] = (b4 & ~mask) | (c4 & mask); + } + + public ImmutableElement getElement(byte[] v, int offset, int length, + byte highByte) { + + long[] vLimbs = new long[NUM_LIMBS]; + long[] montLimbs = new long[NUM_LIMBS]; + super.encode(v, offset, length, highByte, vLimbs); + + // Convert to Montgomery domain + int numAdds = mult(vLimbs, h, montLimbs); + return new ImmutableElement(montLimbs, numAdds); + } + + /* + * This function 'moves/reduces' digit 'v' to the 'lower' limbs + * + * The result is not reduced further. Carry propagation is not performed + * (see IntegerPolynomial.reduceHigh() for how this method is used) + * + * Proof: + * v * 2^(i*52) (mod p) == v * 2^(52i) - v * 2^(52i-256) * p (mod p) + * == v * 2^(52i) - v * 2^(52i-256) * (2^256 -2^224 +2^192 +2^96 -1) (mod p) + * == v * 2^(52i) - v * [2^(52i-256+256) -2^(52i-256+224) +2^(52i-256+192) +2^(52i-256+96) -2^(52i-256)] (mod p) + * == v * 2^(52i) - v * [2^(52i) -2^(52i-32) +2^(52i-64) +2^(52i-160) -2^(52i-256)] (mod p) + * + * == v * [2^(52i-32) +2^(52i-52-12) +2^(52i-3*52-4) -2^(52i-4*52-48)] (mod p) + */ + @Override + protected void reduceIn(long[] limbs, long v, int i) { + // Since top term (2^(52i-32)) will leave top 20 bits back in the same + // position i, + // "repeat same reduction on top 20 bits" + v += v >> 32; + + // 2^(52i-32) + limbs[i - 1] += (v << 20) & LIMB_MASK; + + // 2^(52i-52-12) + limbs[i - 2] -= (v << 40) & LIMB_MASK; + limbs[i - 1] -= v >> 12; + + // 2^(52i-3*52-4) + limbs[i - 4] -= (v << 48) & LIMB_MASK; + limbs[i - 3] -= v >> 4; + + // 2^(52i-4*52-48) + limbs[i - 5] += (v << 4) & LIMB_MASK; + limbs[i - 4] += v >> 48; + } +} \ No newline at end of file diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 4c0f4cda13d23..5188362033d42 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1515,3 +1515,23 @@ jdk.tls.alpnCharset=ISO_8859_1 # # [1] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/bde93b0e-f3c9-4ddf-9f44-e1453be7af5a #jdk.security.krb5.s4u2proxy.acceptNonForwardableServiceTicket=false + +# +# Policy for name comparison in keytab and ccache entry lookup +# +# When looking up a keytab or credentials cache (ccache) entry for a Kerberos +# principal, the principal name is compared with the name in the entry. +# The comparison is by default case-insensitive. However, many Kerberos +# implementations consider principal names to be case-sensitive. Consequently, +# if two principals have names that differ only in case, there is a risk that +# an incorrect keytab or ccache entry might be selected. +# +# If this security property is set to "true", the comparison of principal +# names at keytab and ccache entry lookup is case-sensitive. +# +# The default value is "false". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +#jdk.security.krb5.name.case.sensitive=false diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java index 919ce5d42563c..28b913ed93d51 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java @@ -118,7 +118,7 @@ public R visitTypeAsRecord(TypeElement e, P p) { * @param p {@inheritDoc ElementKindVisitor6} * @return the result of {@code defaultAction} * - * @since 14 + * @since 16 */ @Override public R visitVariableAsBindingVariable(VariableElement e, P p) { diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java index 47a2029d85079..c5bde23b47e1f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java @@ -250,6 +250,8 @@ public R visitTypeParameter(TypeParameterElement e, P p) { * @param e {@inheritDoc ElementVisitor} * @param p {@inheritDoc ElementVisitor} * @return the result of scanning + * + * @since 14 */ @Override public R visitRecordComponent(RecordComponentElement e, P p) { diff --git a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java index e0bb999c05b7f..40224abbd509d 100644 --- a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java +++ b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java @@ -154,6 +154,8 @@ public JavaFileObject getJavaFileForOutput(Location location, * * @throws IllegalArgumentException {@inheritDoc} * @throws IllegalStateException {@inheritDoc} + * + * @since 18 */ @Override public JavaFileObject getJavaFileForOutputForOriginatingFiles(Location location, @@ -214,6 +216,8 @@ public FileObject getFileForOutput(Location location, * * @throws IllegalArgumentException {@inheritDoc} * @throws IllegalStateException {@inheritDoc} + * + * @since 18 */ @Override public FileObject getFileForOutputForOriginatingFiles(Location location, diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectorServer.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectorServer.java index 139b7653424c8..0502cb8a971ff 100644 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectorServer.java +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectorServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, 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 @@ -102,21 +102,23 @@ public class RMIConnectorServer extends JMXConnectorServer { "jmx.remote.rmi.server.socket.factory"; /** - * Name of the attribute that specifies an - * {@link ObjectInputFilter} pattern string to filter classes acceptable - * for {@link RMIServer#newClient(java.lang.Object) RMIServer.newClient()} - * remote method call. - *

    - * The filter pattern must be in same format as used in - * {@link java.io.ObjectInputFilter.Config#createFilter} - *

    - * This list of classes allowed by filter should correspond to the - * transitive closure of the credentials class (or classes) used by the - * installed {@linkplain JMXAuthenticator} associated with the - * {@linkplain RMIServer} implementation. - * If the attribute is not set then any class is deemed acceptable. - * @see ObjectInputFilter - */ + * Name of the attribute that specifies an + * {@link ObjectInputFilter} pattern string to filter classes acceptable + * for {@link RMIServer#newClient(java.lang.Object) RMIServer.newClient()} + * remote method call. + *

    + * The filter pattern must be in same format as used in + * {@link java.io.ObjectInputFilter.Config#createFilter} + *

    + * This list of classes allowed by filter should correspond to the + * transitive closure of the credentials class (or classes) used by the + * installed {@linkplain JMXAuthenticator} associated with the + * {@linkplain RMIServer} implementation. + * If the attribute is not set then any class is deemed acceptable. + * @see ObjectInputFilter + * + * @since 10 + */ public static final String CREDENTIALS_FILTER_PATTERN = "jmx.remote.rmi.server.credentials.filter.pattern"; @@ -152,6 +154,8 @@ public class RMIConnectorServer extends JMXConnectorServer { * an allow-list that is too narrow or a reject-list that is too wide may * prevent legitimate clients from interoperating with the * {@code JMXConnectorServer}. + * + * @since 10 */ public static final String SERIAL_FILTER_PATTERN = "jmx.remote.rmi.server.serial.filter.pattern"; diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/package-info.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/package-info.java new file mode 100644 index 0000000000000..d26c797e6888e --- /dev/null +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/package-info.java @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2002, 2024, 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. + */ + +/** + *

    The RMI connector is a connector for the JMX Remote API that + * uses RMI to transmit client requests to a remote MBean server. + * This package defines the classes that the user of an RMI + * connector needs to reference directly, for both the client and + * server sides. It also defines certain classes that the user + * will not usually reference directly, but that must be defined so + * that different implementations of the RMI connector can + * interoperate.

    + * + *

    The RMI connector supports the JRMP transport for RMI.

    + * + *

    Like most connectors in the JMX Remote API, an RMI connector + * usually has an address, which + * is a {@link javax.management.remote.JMXServiceURL + * JMXServiceURL}. The protocol part of this address is + * rmi for a connector that uses the default RMI + * transport (JRMP).

    + * + *

    There are two forms for RMI connector addresses:

    + * + *
      + *
    • + * In the JNDI form, the URL indicates where to find + * an RMI stub for the connector. This RMI stub is a Java + * object of type {@link javax.management.remote.rmi.RMIServer + * RMIServer} that gives remote access to the connector server. + * With this address form, the RMI stub is obtained from an + * external directory entry included in the URL. An external + * directory is any directory recognized by {@link javax.naming + * JNDI}, typically the RMI registry, LDAP, or COS Naming. + * + *
    • + * In the encoded form, the URL directly includes the + * information needed to connect to the connector server. When + * using RMI/JRMP, the encoded form is the serialized RMI stub + * for the server object, encoded using BASE64 without embedded + * newlines. + *
    + * + *

    Addresses are covered in more detail below.

    + * + * + *

    Creating an RMI connector server

    + * + *

    The usual way to create an RMI connector server is to supply an + * RMI connector address to the method {@link + * javax.management.remote.JMXConnectorServerFactory#newJMXConnectorServer + * JMXConnectorServerFactory.newJMXConnectorServer}. The MBean + * server to which the connector server is attached can be + * specified as a parameter to that method. Alternatively, the + * connector server can be registered as an MBean in that MBean + * server.

    + * + *

    An RMI connector server can also be created by constructing an + * instance of {@link + * javax.management.remote.rmi.RMIConnectorServer + * RMIConnectorServer}, explicitly or through the MBean server's + * createMBean method.

    + * + *

    Choosing the RMI transport

    + * + *

    You can choose the RMI transport by specifying + * rmi in the protocol part of the + * serviceURL when creating the connector server. You + * can also create specialized connector servers by instantiating + * an appropriate subclass of {@link + * javax.management.remote.rmi.RMIServerImpl RMIServerImpl} and + * supplying it to the RMIConnectorServer + * constructor.

    + * + * + *

    Connector addresses generated by the + * server

    + * + *

    If the serviceURL you specify has an empty URL + * path (after the optional host and port), or if you do not + * specify a serviceURL, then the connector server + * will fabricate a new JMXServiceURL that clients can + * use to connect:

    + * + *
      + * + *
    • If the serviceURL looks like:

      + * + *
      + *  service:jmx:rmi://host:port
      + *  
      + * + *

      then the connector server will generate an {@link + * javax.management.remote.rmi.RMIJRMPServerImpl + * RMIJRMPServerImpl} and the returned JMXServiceURL + * looks like:

      + * + *
      + *  service:jmx:rmi://host:port/stub/XXXX
      + *  
      + * + *

      where XXXX is the serialized form of the + * stub for the generated object, encoded in BASE64 without + * newlines.

      + * + *
    • If there is no serviceURL, there must be a + * user-provided RMIServerImpl. The connector server + * will generate a JMXServiceURL using the rmi + * form.

      + * + *
    + * + *

    The host in a user-provided + * serviceURL is optional. If present, it is copied + * into the generated JMXServiceURL but otherwise + * ignored. If absent, the generated JXMServiceURL + * will have the local host name.

    + * + *

    The port in a user-provided + * serviceURL is also optional. If present, it is + * also copied into the generated JMXServiceURL; + * otherwise, the generated JMXServiceURL has no port. + * For an serviceURL using the rmi + * protocol, the port, if present, indicates + * what port the generated remote object should be exported on. It + * has no other effect.

    + * + *

    If the user provides an RMIServerImpl rather than a + * JMXServiceURL, then the generated + * JMXServiceURL will have the local host name in its + * host part and no + * port.

    + * + * + *

    Connector addresses based on directory + * entries

    + * + *

    As an alternative to the generated addresses just described, + * the serviceURL address supplied when creating a + * connector server can specify a directory address in + * which to store the provided or generated RMIServer + * stub. This directory address is then used by both client and + * server.

    + * + *

    In this case, the serviceURL has the following form:

    + * + *
    + *    service:jmx:rmi://host:port/jndi/jndi-name
    + *    
    + * + *

    Here, jndi-name is a string that can be + * supplied to {@link javax.naming.InitialContext#bind + * javax.naming.InitialContext.bind}.

    + * + *

    As usual, the host and + * :port can be omitted.

    + * + *

    The connector server will generate an + * RMIServerImpl based on the protocol + * (rmi) and the port if any. When + * the connector server is started, it will derive a stub from this + * object using its {@link + * javax.management.remote.rmi.RMIServerImpl#toStub toStub} method + * and store the object using the given + * jndi-name. The properties defined by the + * JNDI API are consulted as usual.

    + * + *

    For example, if the JMXServiceURL is: + * + *

    + *      service:jmx:rmi://ignoredhost/jndi/rmi://myhost/myname
    + *      
    + * + * then the connector server will generate an + * RMIJRMPServerImpl and store its stub using the JNDI + * name + * + *
    + *      rmi://myhost/myname
    + *      
    + * + * which means entry myname in the RMI registry + * running on the default port of host myhost. Note + * that the RMI registry only allows registration from the local + * host. So, in this case, myhost must be the name + * (or a name) of the host that the connector server is running + * on. + * + *

    In this JMXServiceURL, the first rmi: + * specifies the RMI + * connector, while the second rmi: specifies the RMI + * registry. + * + *

    As another example, if the JMXServiceURL is: + * + *

    + *      service:jmx:rmi://ignoredhost/jndi/ldap://dirhost:9999/cn=this,ou=that
    + *      
    + * + * then the connector server will generate an + * RMIJRMPServerImpl and store its stub using the JNDI + * name + * + *
    + *      ldap://dirhost:9999/cn=this,ou=that
    + *      
    + * + * which means entry cn=this,ou=that in the LDAP + * directory running on port 9999 of host dirhost. + * + *

    If the JMXServiceURL is: + * + *

    + *      service:jmx:rmi://ignoredhost/jndi/cn=this,ou=that
    + *      
    + * + * then the connector server will generate an + * RMIJRMPServerImpl and store its stub using the JNDI + * name + * + *
    + *      cn=this,ou=that
    + *      
    + * + * For this case to work, the JNDI API must have been configured + * appropriately to supply the information about what directory to + * use. + * + *

    In these examples, the host name ignoredhost is + * not used by the connector server or its clients. It can be + * omitted, for example:

    + * + *
    + *      service:jmx:rmi:///jndi/cn=this,ou=that
    + *      
    + * + *

    However, it is good practice to use the name of the host + * where the connector server is running. This is often different + * from the name of the directory host.

    + * + * + *

    Connector server attributes

    + * + *

    When using the default JRMP transport, RMI socket factories can + * be specified using the attributes + * jmx.remote.rmi.client.socket.factory and + * jmx.remote.rmi.server.socket.factory in the + * environment given to the + * RMIConnectorServer constructor. The values of these + * attributes must be of type {@link + * java.rmi.server.RMIClientSocketFactory} and {@link + * java.rmi.server.RMIServerSocketFactory}, respectively. These + * factories are used when creating the RMI objects associated with + * the connector.

    + * + *

    Creating an RMI connector client

    + * + *

    An RMI connector client is usually constructed using {@link + * javax.management.remote.JMXConnectorFactory}, with a + * JMXServiceURL that has rmi as its protocol.

    + * + *

    If the JMXServiceURL was generated by the server, + * as described above under "connector + * addresses generated by the server", then the client will + * need to obtain it directly or indirectly from the server. + * Typically, the server makes the JMXServiceURL + * available by storing it in a file or a lookup service.

    + * + *

    If the JMXServiceURL uses the directory syntax, as + * described above under "connector addresses + * based on directory entries", then the client may obtain it + * as just explained, or client and server may both know the + * appropriate directory entry to use. For example, if the + * connector server for the Whatsit agent uses the entry + * whatsit-agent-connector in the RMI registry on host + * myhost, then client and server can both know + * that the appropriate JMXServiceURL is:

    + * + *
    + *    service:jmx:rmi:///jndi/rmi://myhost/whatsit-agent-connector
    + *    
    + * + *

    If you have an RMI stub of type {@link + * javax.management.remote.rmi.RMIServer RMIServer}, you can + * construct an RMI connection directly by using the appropriate + * constructor of {@link javax.management.remote.rmi.RMIConnector + * RMIConnector}.

    + * + *

    Dynamic code downloading

    + * + *

    If an RMI connector client or server receives from its peer an + * instance of a class that it does not know, and if dynamic code + * downloading is active for the RMI connection, then the class can + * be downloaded from a codebase specified by the peer. + * {@extLink rmi_guide Java RMI Guide} explains this in more detail.

    + * + * @see RFC 2045, + * section 6.8, "Base64 Content-Transfer-Encoding" + * + * + * @since 1.5 + * + */ +package javax.management.remote.rmi; diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/package.html b/src/java.management.rmi/share/classes/javax/management/remote/rmi/package.html deleted file mode 100644 index 9afd476f2470b..0000000000000 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/package.html +++ /dev/null @@ -1,329 +0,0 @@ - - - RMI connector - - - -

    The RMI connector is a connector for the JMX Remote API that - uses RMI to transmit client requests to a remote MBean server. - This package defines the classes that the user of an RMI - connector needs to reference directly, for both the client and - server sides. It also defines certain classes that the user - will not usually reference directly, but that must be defined so - that different implementations of the RMI connector can - interoperate.

    - -

    The RMI connector supports the JRMP transport for RMI.

    - -

    Like most connectors in the JMX Remote API, an RMI connector - usually has an address, which - is a {@link javax.management.remote.JMXServiceURL - JMXServiceURL}. The protocol part of this address is - rmi for a connector that uses the default RMI - transport (JRMP).

    - -

    There are two forms for RMI connector addresses:

    - -
      -
    • - In the JNDI form, the URL indicates where to find - an RMI stub for the connector. This RMI stub is a Java - object of type {@link javax.management.remote.rmi.RMIServer - RMIServer} that gives remote access to the connector server. - With this address form, the RMI stub is obtained from an - external directory entry included in the URL. An external - directory is any directory recognized by {@link javax.naming - JNDI}, typically the RMI registry, LDAP, or COS Naming. - -
    • - In the encoded form, the URL directly includes the - information needed to connect to the connector server. When - using RMI/JRMP, the encoded form is the serialized RMI stub - for the server object, encoded using BASE64 without embedded - newlines. -
    - -

    Addresses are covered in more detail below.

    - - -

    Creating an RMI connector server

    - -

    The usual way to create an RMI connector server is to supply an - RMI connector address to the method {@link - javax.management.remote.JMXConnectorServerFactory#newJMXConnectorServer - JMXConnectorServerFactory.newJMXConnectorServer}. The MBean - server to which the connector server is attached can be - specified as a parameter to that method. Alternatively, the - connector server can be registered as an MBean in that MBean - server.

    - -

    An RMI connector server can also be created by constructing an - instance of {@link - javax.management.remote.rmi.RMIConnectorServer - RMIConnectorServer}, explicitly or through the MBean server's - createMBean method.

    - -

    Choosing the RMI transport

    - -

    You can choose the RMI transport by specifying - rmi in the protocol part of the - serviceURL when creating the connector server. You - can also create specialized connector servers by instantiating - an appropriate subclass of {@link - javax.management.remote.rmi.RMIServerImpl RMIServerImpl} and - supplying it to the RMIConnectorServer - constructor.

    - - -

    Connector addresses generated by the - server

    - -

    If the serviceURL you specify has an empty URL - path (after the optional host and port), or if you do not - specify a serviceURL, then the connector server - will fabricate a new JMXServiceURL that clients can - use to connect:

    - -
      - -
    • If the serviceURL looks like:

      - -
      -	service:jmx:rmi://host:port
      -	
      - -

      then the connector server will generate an {@link - javax.management.remote.rmi.RMIJRMPServerImpl - RMIJRMPServerImpl} and the returned JMXServiceURL - looks like:

      - -
      -	service:jmx:rmi://host:port/stub/XXXX
      -	
      - -

      where XXXX is the serialized form of the - stub for the generated object, encoded in BASE64 without - newlines.

      - -
    • If there is no serviceURL, there must be a - user-provided RMIServerImpl. The connector server - will generate a JMXServiceURL using the rmi - form.

      - -
    - -

    The host in a user-provided - serviceURL is optional. If present, it is copied - into the generated JMXServiceURL but otherwise - ignored. If absent, the generated JXMServiceURL - will have the local host name.

    - -

    The port in a user-provided - serviceURL is also optional. If present, it is - also copied into the generated JMXServiceURL; - otherwise, the generated JMXServiceURL has no port. - For an serviceURL using the rmi - protocol, the port, if present, indicates - what port the generated remote object should be exported on. It - has no other effect.

    - -

    If the user provides an RMIServerImpl rather than a - JMXServiceURL, then the generated - JMXServiceURL will have the local host name in its - host part and no - port.

    - - -

    Connector addresses based on directory - entries

    - -

    As an alternative to the generated addresses just described, - the serviceURL address supplied when creating a - connector server can specify a directory address in - which to store the provided or generated RMIServer - stub. This directory address is then used by both client and - server.

    - -

    In this case, the serviceURL has the following form:

    - -
    -    service:jmx:rmi://host:port/jndi/jndi-name
    -    
    - -

    Here, jndi-name is a string that can be - supplied to {@link javax.naming.InitialContext#bind - javax.naming.InitialContext.bind}.

    - -

    As usual, the host and - :port can be omitted.

    - -

    The connector server will generate an - RMIServerImpl based on the protocol - (rmi) and the port if any. When - the connector server is started, it will derive a stub from this - object using its {@link - javax.management.remote.rmi.RMIServerImpl#toStub toStub} method - and store the object using the given - jndi-name. The properties defined by the - JNDI API are consulted as usual.

    - -

    For example, if the JMXServiceURL is: - -

    -      service:jmx:rmi://ignoredhost/jndi/rmi://myhost/myname
    -      
    - - then the connector server will generate an - RMIJRMPServerImpl and store its stub using the JNDI - name - -
    -      rmi://myhost/myname
    -      
    - - which means entry myname in the RMI registry - running on the default port of host myhost. Note - that the RMI registry only allows registration from the local - host. So, in this case, myhost must be the name - (or a name) of the host that the connector server is running - on. - -

    In this JMXServiceURL, the first rmi: - specifies the RMI - connector, while the second rmi: specifies the RMI - registry. - -

    As another example, if the JMXServiceURL is: - -

    -      service:jmx:rmi://ignoredhost/jndi/ldap://dirhost:9999/cn=this,ou=that
    -      
    - - then the connector server will generate an - RMIJRMPServerImpl and store its stub using the JNDI - name - -
    -      ldap://dirhost:9999/cn=this,ou=that
    -      
    - - which means entry cn=this,ou=that in the LDAP - directory running on port 9999 of host dirhost. - -

    If the JMXServiceURL is: - -

    -      service:jmx:rmi://ignoredhost/jndi/cn=this,ou=that
    -      
    - - then the connector server will generate an - RMIJRMPServerImpl and store its stub using the JNDI - name - -
    -      cn=this,ou=that
    -      
    - - For this case to work, the JNDI API must have been configured - appropriately to supply the information about what directory to - use. - -

    In these examples, the host name ignoredhost is - not used by the connector server or its clients. It can be - omitted, for example:

    - -
    -      service:jmx:rmi:///jndi/cn=this,ou=that
    -      
    - -

    However, it is good practice to use the name of the host - where the connector server is running. This is often different - from the name of the directory host.

    - - -

    Connector server attributes

    - -

    When using the default JRMP transport, RMI socket factories can - be specified using the attributes - jmx.remote.rmi.client.socket.factory and - jmx.remote.rmi.server.socket.factory in the - environment given to the - RMIConnectorServer constructor. The values of these - attributes must be of type {@link - java.rmi.server.RMIClientSocketFactory} and {@link - java.rmi.server.RMIServerSocketFactory}, respectively. These - factories are used when creating the RMI objects associated with - the connector.

    - -

    Creating an RMI connector client

    - -

    An RMI connector client is usually constructed using {@link - javax.management.remote.JMXConnectorFactory}, with a - JMXServiceURL that has rmi as its protocol.

    - -

    If the JMXServiceURL was generated by the server, - as described above under "connector - addresses generated by the server", then the client will - need to obtain it directly or indirectly from the server. - Typically, the server makes the JMXServiceURL - available by storing it in a file or a lookup service.

    - -

    If the JMXServiceURL uses the directory syntax, as - described above under "connector addresses - based on directory entries", then the client may obtain it - as just explained, or client and server may both know the - appropriate directory entry to use. For example, if the - connector server for the Whatsit agent uses the entry - whatsit-agent-connector in the RMI registry on host - myhost, then client and server can both know - that the appropriate JMXServiceURL is:

    - -
    -    service:jmx:rmi:///jndi/rmi://myhost/whatsit-agent-connector
    -    
    - -

    If you have an RMI stub of type {@link - javax.management.remote.rmi.RMIServer RMIServer}, you can - construct an RMI connection directly by using the appropriate - constructor of {@link javax.management.remote.rmi.RMIConnector - RMIConnector}.

    - -

    Dynamic code downloading

    - -

    If an RMI connector client or server receives from its peer an - instance of a class that it does not know, and if dynamic code - downloading is active for the RMI connection, then the class can - be downloaded from a codebase specified by the peer. - {@extLink rmi_guide Java RMI Guide} explains this in more detail.

    - - @see RFC 2045, - section 6.8, "Base64 Content-Transfer-Encoding" - - - @since 1.5 - - - diff --git a/src/java.se/share/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec index df23a602b1381..5206a0c6ae95d 100644 --- a/src/java.se/share/data/jdwp/jdwp.spec +++ b/src/java.se/share/data/jdwp/jdwp.spec @@ -1617,11 +1617,14 @@ JDWP "Java(tm) Debug Wire Protocol" (object object "The object ID") ) (Reply - (threadObject owner "The monitor owner, or null if it is not currently owned.") - (int entryCount "The number of times the monitor has been entered.") - (Repeat waiters "The total number of threads that are waiting to enter or re-enter " - "the monitor, or waiting to be notified by the monitor." - (threadObject thread "A thread waiting for this monitor.") + (threadObject owner "The platform thread owning this monitor, or null " + "if owned by a virtual thread or not owned.") + (int entryCount "The number of times the owning platform thread has entered the monitor, " + "or 0 if owned by a virtual thread or not owned.") + (Repeat waiters "The total number of platform threads that are waiting to enter or re-enter " + "the monitor, or waiting to be notified by the monitor, or 0 if " + "only virtual threads are waiting or no threads are waiting." + (threadObject thread "A platform thread waiting for this monitor.") ) ) (ErrorSet @@ -2871,7 +2874,7 @@ JDWP "Java(tm) Debug Wire Protocol" "if not explicitly requested." (int requestID - "Request that generated event (or 0 if this " + "Request that generated event, or 0 if this " "event is automatically generated.") (threadObject thread "Initial thread") ) diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java b/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java index d11c96a661380..130f2c23f8670 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, 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 @@ -109,6 +109,12 @@ public class PrincipalName implements Cloneable { public static final String NAME_REALM_SEPARATOR_STR = "@"; public static final String REALM_COMPONENT_SEPARATOR_STR = "."; + private static final boolean NAME_CASE_SENSITIVE_IN_MATCH + = "true".equalsIgnoreCase( + SecurityProperties.privilegedGetOverridable( + "jdk.security.krb5.name.case.sensitive")); + + // Instance fields. /** @@ -607,33 +613,47 @@ public byte[] asn1Encode() throws Asn1Exception, IOException { /** - * Checks if two PrincipalName objects have identical values in their corresponding data fields. + * Checks if two PrincipalName objects have identical values + * in their corresponding data fields. + *

    + * If {@systemProperty jdk.security.krb5.name.case.sensitive} is set to true, + * the name comparison is case-sensitive. Otherwise, it's case-insensitive. + *

    + * It is used in {@link sun.security.krb5.internal.ccache.FileCredentialsCache} + * and {@link sun.security.krb5.internal.ktab.KeyTab} to retrieve ccache + * or keytab entry for a principal. * * @param pname the other PrincipalName object. * @return true if two have identical values, otherwise, return false. */ - // It is used in sun.security.krb5.internal.ccache package. public boolean match(PrincipalName pname) { - boolean matched = true; - //name type is just a hint, no two names can be the same ignoring name type. - // if (this.nameType != pname.nameType) { - // matched = false; - // } - if ((this.nameRealm != null) && (pname.nameRealm != null)) { + // No need to check name type. It's just a hint, no two names can be + // the same ignoring name type. + if (NAME_CASE_SENSITIVE_IN_MATCH) { + if (!(this.nameRealm.toString().equals(pname.nameRealm.toString()))) { + return false; + } + } else { if (!(this.nameRealm.toString().equalsIgnoreCase(pname.nameRealm.toString()))) { - matched = false; + return false; } } if (this.nameStrings.length != pname.nameStrings.length) { - matched = false; + return false; } else { for (int i = 0; i < this.nameStrings.length; i++) { - if (!(this.nameStrings[i].equalsIgnoreCase(pname.nameStrings[i]))) { - matched = false; + if (NAME_CASE_SENSITIVE_IN_MATCH) { + if (!(this.nameStrings[i].equals(pname.nameStrings[i]))) { + return false; + } + } else { + if (!(this.nameStrings[i].equalsIgnoreCase(pname.nameStrings[i]))) { + return false; + } } } } - return matched; + return true; } /** diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java index facdb8efdafa8..62fa36fa6b7db 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java @@ -61,7 +61,8 @@ public interface CaseTree extends Tree { * For default case, returns an empty list. * * @return labels for this case - * @since 12 + * + * @since 14 */ List getExpressions(); @@ -98,7 +99,8 @@ public interface CaseTree extends Tree { * {@linkplain CaseKind#STATEMENT}. * * @return case value or null - * @since 12 + * + * @since 14 */ public default Tree getBody() { return null; @@ -108,7 +110,8 @@ public default Tree getBody() { * Returns the kind of this case. * * @return the kind of this case - * @since 12 + * + * @since 14 */ public default CaseKind getCaseKind() { return CaseKind.STATEMENT; @@ -121,7 +124,7 @@ public default CaseKind getCaseKind() { *

  • RULE: {@code case -> /}
  • * * - * @since 12 + * @since 14 */ public enum CaseKind { /** diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java index 4a60ea53f99c2..2327c7a3f49e9 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/SwitchExpressionTree.java @@ -39,7 +39,7 @@ * * @jls 15.29 Switch Expressions * - * @since 12 + * @since 14 */ public interface SwitchExpressionTree extends ExpressionTree { /** diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java index 0bd3823307b74..4b7df6185d626 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java @@ -284,7 +284,7 @@ public enum Kind { /** * Used for instances of {@link SwitchExpressionTree}. * - * @since 12 + * @since 14 */ SWITCH_EXPRESSION(SwitchExpressionTree.class), @@ -702,7 +702,7 @@ public enum Kind { /** * Used for instances of {@link YieldTree}. * - * @since 13 + * @since 14 */ YIELD(YieldTree.class); diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java index 3f7a683350c2e..b7851d8ff9a58 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java @@ -413,7 +413,8 @@ public interface TreeVisitor { * @param node the node being visited * @param p a parameter value * @return a result value - * @since 12 + * + * @since 14 */ R visitSwitchExpression(SwitchExpressionTree node, P p); @@ -608,7 +609,8 @@ public interface TreeVisitor { * @param node the node being visited * @param p a parameter value * @return a result value - * @since 13 + * + * @since 14 */ R visitYield(YieldTree node, P p); } diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/YieldTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/YieldTree.java index 181d0495774ea..eeda36d84aed6 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/YieldTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/YieldTree.java @@ -35,7 +35,7 @@ * * @jls 14.21 The yield Statement * - * @since 13 + * @since 14 */ public interface YieldTree extends StatementTree { diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java index 2dd83d85a5dda..d2d0753dbf287 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java @@ -229,6 +229,8 @@ public R visitDocRoot(DocRootTree node, P p) { * @param node {@inheritDoc} * @param p {@inheritDoc} * @return the result of scanning + * + * @since 10 */ @Override public R visitDocType(DocTypeTree node, P p) { diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java index 6d2e60e58a33c..45a452bd0dd54 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTrees.java @@ -276,6 +276,8 @@ public abstract void printMessage(Diagnostic.Kind kind, CharSequence msg, * @param tree the tree containing the entity * @return a string containing the characters * @spec https://www.w3.org/TR/html52 HTML Standard + * + * @since 16 */ public abstract String getCharacters(EntityTree tree); } diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/Plugin.java b/src/jdk.compiler/share/classes/com/sun/source/util/Plugin.java index 9a41396d84d9c..aee626929f4cd 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/Plugin.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/Plugin.java @@ -74,6 +74,8 @@ public interface Plugin { * command-line option. * * @return whether or not this plugin should be automatically started + * + * @since 14 */ default boolean autoStart() { return false; diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java index 5179061b4bb78..1a123a49faa12 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleTreeVisitor.java @@ -299,6 +299,8 @@ public R visitSwitch(SwitchTree node, P p) { * @param node {@inheritDoc} * @param p {@inheritDoc} * @return the result of {@code defaultAction} + * + * @since 14 */ @Override public R visitSwitchExpression(SwitchExpressionTree node, P p) { @@ -1047,6 +1049,8 @@ public R visitOther(Tree node, P p) { * @param node {@inheritDoc} * @param p {@inheritDoc} * @return the result of {@code defaultAction} + * + * @since 14 */ @Override public R visitYield(YieldTree node, P p) { diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java index 49bec302100e8..4327c6f5f314e 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java @@ -376,6 +376,8 @@ public R visitSwitch(SwitchTree node, P p) { * @param node {@inheritDoc} * @param p {@inheritDoc} * @return the result of scanning + * + * @since 14 */ @Override public R visitSwitchExpression(SwitchExpressionTree node, P p) { @@ -1200,6 +1202,8 @@ public R visitErroneous(ErroneousTree node, P p) { * @param node {@inheritDoc} * @param p {@inheritDoc} * @return the result of scanning + * + * @since 14 */ @Override public R visitYield(YieldTree node, P p) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java index ef62222438b8c..ca420eecdc5e5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java @@ -1552,9 +1552,11 @@ public RecordComponent findRecordComponentToRemove(JCVariableDecl var) { RecordComponent toRemove = null; for (RecordComponent rc : recordComponents) { /* it could be that a record erroneously declares two record components with the same name, in that - * case we need to use the position to disambiguate + * case we need to use the position to disambiguate, but if we loaded the record from a class file + * all positions will be -1, in that case we have to ignore the position and match only based on the + * name */ - if (rc.name == var.name && var.pos == rc.pos) { + if (rc.name == var.name && (var.pos == rc.pos || rc.pos == -1)) { toRemove = rc; } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index 89de932ab72a5..17173e480f1c1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -230,6 +230,7 @@ public static Symtab instance(Context context) { public final Type valueBasedInternalType; public final Type classDescType; public final Type enumDescType; + public final Type ioType; // For serialization lint checking public final Type objectStreamFieldType; @@ -616,6 +617,7 @@ public R accept(ElementVisitor v, P p) { valueBasedInternalType = enterSyntheticAnnotation("jdk.internal.ValueBased+Annotation"); classDescType = enterClass("java.lang.constant.ClassDesc"); enumDescType = enterClass("java.lang.Enum$EnumDesc"); + ioType = enterClass("java.io.IO"); // For serialization lint checking objectStreamFieldType = enterClass("java.io.ObjectStreamField"); objectInputStreamType = enterClass("java.io.ObjectInputStream"); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index fc96eaa0be186..4d9f001273374 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -4818,7 +4818,6 @@ void checkSwitchCaseLabelDominated(JCCaseLabel unconditionalCaseLabel, List env) { sym.owner.complete(); } - private void importJavaLang(JCCompilationUnit tree, Env env, ImportFilter typeImportFilter) { + private void implicitImports(JCCompilationUnit tree, Env env) { // Import-on-demand java.lang. PackageSymbol javaLang = syms.enterPackage(syms.java_base, names.java_lang); if (javaLang.members().isEmpty() && !javaLang.exists()) { @@ -332,6 +332,28 @@ private void importJavaLang(JCCompilationUnit tree, Env env, Import } importAll(make.at(tree.pos()).Import(make.Select(make.QualIdent(javaLang.owner), javaLang), false), javaLang, env); + + List defs = tree.getTypeDecls(); + boolean isImplicitClass = !defs.isEmpty() && + defs.head instanceof JCClassDecl cls && + (cls.mods.flags & IMPLICIT_CLASS) != 0; + if (isImplicitClass) { + doModuleImport(make.ModuleImport(make.QualIdent(syms.java_base))); + if (peekTypeExists(syms.ioType.tsym)) { + doImport(make.Import(make.Select(make.QualIdent(syms.ioType.tsym), + names.asterisk), true)); + } + } + } + + private boolean peekTypeExists(TypeSymbol type) { + try { + type.complete(); + return !type.type.isErroneous(); + } catch (CompletionFailure cf) { + //does not exist + return false; + } } private void resolveImports(JCCompilationUnit tree, Env env) { @@ -356,7 +378,7 @@ private void resolveImports(JCCompilationUnit tree, Env env) { (origin, sym) -> sym.kind == TYP && chk.importAccessible(sym, packge); - importJavaLang(tree, env, typeImportFilter); + implicitImports(tree, env); JCModuleDecl decl = tree.getModuleDecl(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index 37846b8b966aa..b9bfe587c6c1b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -172,8 +172,8 @@ protected Gen(Context context) { Chain switchExpressionFalseChain; List stackBeforeSwitchExpression; LocalItem switchResult; - Set invocationsWithPatternMatchingCatch = Set.of(); - ListBuffer patternMatchingInvocationRanges; + PatternMatchingCatchConfiguration patternMatchingCatchConfiguration = + new PatternMatchingCatchConfiguration(Set.of(), null, null, null); /** Cache the symbol to reflect the qualifying type. * key: corresponding type @@ -1087,21 +1087,31 @@ public void visitBlock(JCBlock tree) { } private void visitBlockWithPatterns(JCBlock tree) { - Set prevInvocationsWithPatternMatchingCatch = invocationsWithPatternMatchingCatch; - ListBuffer prevRanges = patternMatchingInvocationRanges; - State startState = code.state.dup(); + PatternMatchingCatchConfiguration prevConfiguration = patternMatchingCatchConfiguration; try { - invocationsWithPatternMatchingCatch = tree.patternMatchingCatch.calls2Handle(); - patternMatchingInvocationRanges = new ListBuffer<>(); + patternMatchingCatchConfiguration = + new PatternMatchingCatchConfiguration(tree.patternMatchingCatch.calls2Handle(), + new ListBuffer(), + tree.patternMatchingCatch.handler(), + code.state.dup()); internalVisitBlock(tree); } finally { + generatePatternMatchingCatch(env); + patternMatchingCatchConfiguration = prevConfiguration; + } + } + + private void generatePatternMatchingCatch(Env env) { + if (patternMatchingCatchConfiguration.handler != null && + !patternMatchingCatchConfiguration.ranges.isEmpty()) { Chain skipCatch = code.branch(goto_); - JCCatch handler = tree.patternMatchingCatch.handler(); - code.entryPoint(startState, handler.param.sym.type); - genPatternMatchingCatch(handler, env, patternMatchingInvocationRanges.toList()); + JCCatch handler = patternMatchingCatchConfiguration.handler(); + code.entryPoint(patternMatchingCatchConfiguration.startState(), + handler.param.sym.type); + genPatternMatchingCatch(handler, + env, + patternMatchingCatchConfiguration.ranges.toList()); code.resolve(skipCatch); - invocationsWithPatternMatchingCatch = prevInvocationsWithPatternMatchingCatch; - patternMatchingInvocationRanges = prevRanges; } } @@ -1926,12 +1936,26 @@ public void visitApply(JCMethodInvocation tree) { if (!msym.isDynamic()) { code.statBegin(tree.pos); } - if (invocationsWithPatternMatchingCatch.contains(tree)) { + if (patternMatchingCatchConfiguration.invocations().contains(tree)) { int start = code.curCP(); result = m.invoke(); - patternMatchingInvocationRanges.add(new int[] {start, code.curCP()}); + patternMatchingCatchConfiguration.ranges().add(new int[] {start, code.curCP()}); } else { - result = m.invoke(); + if (msym.isConstructor() && TreeInfo.isConstructorCall(tree)) { + //if this is a this(...) or super(...) call, there is a pending + //"uninitialized this" before this call. One catch handler cannot + //handle exceptions that may come from places with "uninitialized this" + //and (initialized) this, hence generate one set of handlers here + //for the "uninitialized this" case, and another set of handlers + //will be generated at the end of the method for the initialized this, + //if needed: + generatePatternMatchingCatch(env); + result = m.invoke(); + patternMatchingCatchConfiguration = + patternMatchingCatchConfiguration.restart(code.state.dup()); + } else { + result = m.invoke(); + } } } @@ -2555,4 +2579,15 @@ void addCont(Chain c) { } } + record PatternMatchingCatchConfiguration(Set invocations, + ListBuffer ranges, + JCCatch handler, + State startState) { + public PatternMatchingCatchConfiguration restart(State newState) { + return new PatternMatchingCatchConfiguration(invocations(), + new ListBuffer(), + handler(), + newState); + } + } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/ProgramDescriptor.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/ProgramDescriptor.java index 087b1708acd9e..fd99838427b4c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/ProgramDescriptor.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/ProgramDescriptor.java @@ -32,6 +32,7 @@ import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; +import java.lang.module.InvalidModuleDescriptorException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -39,6 +40,10 @@ import java.util.Optional; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.lang.model.SourceVersion; /** * Describes a launch-able Java compilation unit. @@ -113,25 +118,62 @@ public boolean isModular() { } public Set computePackageNames() { - try (var stream = Files.find(sourceRootPath, 99, (path, attr) -> attr.isDirectory())) { - var names = new TreeSet(); - stream.filter(ProgramDescriptor::containsAtLeastOneRegularFile) - .map(sourceRootPath::relativize) - .map(Path::toString) - .filter(string -> !string.isEmpty()) - .map(string -> string.replace(File.separatorChar, '.')) - .forEach(names::add); - return names; - } catch (IOException exception) { - throw new UncheckedIOException(exception); + return explodedPackages(sourceRootPath); + } + + // -- exploded directories --> based on jdk.internal.module.ModulePath + + private static Set explodedPackages(Path dir) { + String separator = dir.getFileSystem().getSeparator(); + try (Stream stream = Files.find(dir, Integer.MAX_VALUE, + (path, attrs) -> attrs.isRegularFile() && !isHidden(path))) { + return stream.map(dir::relativize) + .map(path -> toPackageName(path, separator)) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } + + /** + * Maps the relative path of an entry in an exploded module to a package + * name. + * + * @throws InvalidModuleDescriptorException if the name is a class file in + * the top-level directory (and it's not module-info.class) + */ + private static Optional toPackageName(Path file, String separator) { + assert file.getRoot() == null; + + Path parent = file.getParent(); + if (parent == null) { + String name = file.toString(); + if (name.endsWith(".class") && !name.equals("module-info.class")) { + String msg = name + " found in top-level directory" + + " (unnamed package not allowed in module)"; + throw new InvalidModuleDescriptorException(msg); + } + return Optional.empty(); + } + + String pn = parent.toString().replace(separator, "."); + if (SourceVersion.isName(pn)) { + return Optional.of(pn); + } else { + // not a valid package name + return Optional.empty(); } } - private static boolean containsAtLeastOneRegularFile(Path directory) { - try (var stream = Files.newDirectoryStream(directory, Files::isRegularFile)) { - return stream.iterator().hasNext(); - } catch (IOException exception) { - throw new UncheckedIOException(exception); + /** + * Returns true if the given file exists and is a hidden file + */ + private static boolean isHidden(Path file) { + try { + return Files.isHidden(file); + } catch (IOException ioe) { + return false; } } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java index df4ba222139ca..32496bde02d4c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -371,9 +371,10 @@ public void put(String name, String value) { } } void printArgumentsToFile(String... params) { - Path out = Paths.get(String.format("javac.%s.args", + Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir")); + Path out = tmpDir.resolve(String.format("javac.%s.args", new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime()))); - String strOut = ""; + String strOut = "# javac crashed, this report includes the parameters passed to it in the @-file format\n"; try { try (Writer w = Files.newBufferedWriter(out)) { for (String param : params) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index 54917c90dc283..f2edd5c97e9e7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -303,6 +303,16 @@ public void visitLambda(JCLambda tree) { } } + /** + * Is the given method invocation an invocation of this(...) or super(...)? + */ + public static boolean isConstructorCall(JCMethodInvocation invoke) { + Name name = TreeInfo.name(invoke.meth); + Names names = name.table.names; + + return (name == names._this || name == names._super); + } + /** Finds super() invocations and translates them using the given mapping. */ public static void mapSuperCalls(JCBlock block, Function mapper) { diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java index aa90f68c1cf41..cb327b3f6e054 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java @@ -84,6 +84,30 @@ public Reader reader() { return terminal.reader(); } + @Override + public JdkConsole println(Object obj) { + writer().println(obj); + writer().flush(); + return this; + } + + @Override + public JdkConsole print(Object obj) { + writer().print(obj); + writer().flush(); + return this; + } + + @Override + public String readln(String prompt) { + try { + initJLineIfNeeded(); + return jline.readLine(prompt == null ? "null" : prompt.replace("%", "%%")); + } catch (EndOfFileException eofe) { + return null; + } + } + @Override public JdkConsole format(Locale locale, String format, Object ... args) { writer().format(locale, format, args).flush(); diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java b/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java index a4cfc59eb2098..b28078916c58b 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java @@ -284,7 +284,7 @@ public void accept(ClassElement cle) { case MethodModel mm -> { if (isPublic(mm.flags())) { Set exceptionSet = new HashSet<>(); - mm.findAttribute(Attributes.EXCEPTIONS).ifPresent(ea -> + mm.findAttribute(Attributes.exceptions()).ifPresent(ea -> ea.exceptions().forEach(e -> exceptionSet.add(e.asInternalName()))); // treat type descriptor as a proxy for signature because signature diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java index 23bec4e7298f6..839ac2fd041b7 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java @@ -478,7 +478,7 @@ public void write(Attribute a, CodeAttribute lr) { println("Record:"); indent(+1); for (var componentInfo : attr.components()) { - var sigAttr = componentInfo.findAttribute(Attributes.SIGNATURE); + var sigAttr = componentInfo.findAttribute(Attributes.signature()); print(getJavaName( new ClassWriter.SignaturePrinter(options.verbose).print( sigAttr.map(SignatureAttribute::asTypeSignature) diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java index c5ac15ee7dab9..798d2f2d3a8d2 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java @@ -141,7 +141,7 @@ public boolean write(ClassModel cm) { } } - cm.findAttribute(Attributes.SOURCE_FILE).ifPresent(sfa -> + cm.findAttribute(Attributes.sourceFile()).ifPresent(sfa -> println("Compiled from \"" + sfa.sourceFile().stringValue() + "\"")); if (options.sysInfo || options.verbose) { @@ -151,7 +151,7 @@ public boolean write(ClassModel cm) { writeModifiers(getClassModifiers(cm.flags().flagsMask())); if ((classModel.flags().flagsMask() & ACC_MODULE) != 0) { - var attr = classModel.findAttribute(Attributes.MODULE); + var attr = classModel.findAttribute(Attributes.module()); if (attr.isPresent()) { var modAttr = attr.get(); if ((modAttr.moduleFlagsMask() & ACC_OPEN) != 0) { @@ -178,7 +178,7 @@ public boolean write(ClassModel cm) { } try { - var sigAttr = classModel.findAttribute(Attributes.SIGNATURE).orElse(null); + var sigAttr = classModel.findAttribute(Attributes.signature()).orElse(null); if (sigAttr == null) { // use info from class file header if ((classModel.flags().flagsMask() & ACC_INTERFACE) == 0 @@ -399,13 +399,13 @@ protected void writeField(FieldModel f) { writeModifiers(flags.flags().stream().filter(fl -> fl.sourceModifier()) .map(fl -> Modifier.toString(fl.mask())).toList()); print(() -> sigPrinter.print( - f.findAttribute(Attributes.SIGNATURE) + f.findAttribute(Attributes.signature()) .map(SignatureAttribute::asTypeSignature) .orElseGet(() -> Signature.of(f.fieldTypeSymbol())))); print(" "); print(() -> f.fieldName().stringValue()); if (options.showConstants) { - var a = f.findAttribute(Attributes.CONSTANT_VALUE); + var a = f.findAttribute(Attributes.constantValue()); if (a.isPresent()) { print(" = "); var cv = a.get(); @@ -480,7 +480,7 @@ protected void writeMethod(MethodModel m) { writeModifiers(modifiers); try { - var sigAttr = m.findAttribute(Attributes.SIGNATURE); + var sigAttr = m.findAttribute(Attributes.signature()); MethodSignature d; if (sigAttr.isEmpty()) { d = MethodSignature.parseFrom(m.methodType().stringValue()); @@ -507,7 +507,7 @@ protected void writeMethod(MethodModel m) { break; } - var e_attr = m.findAttribute(Attributes.EXCEPTIONS); + var e_attr = m.findAttribute(Attributes.exceptions()); // if there are generic exceptions, there must be erased exceptions if (e_attr.isPresent()) { var exceptions = e_attr.get(); @@ -559,9 +559,9 @@ protected void writeMethod(MethodModel m) { } if (options.showLineAndLocalVariableTables) { - code.findAttribute(Attributes.LINE_NUMBER_TABLE) + code.findAttribute(Attributes.lineNumberTable()) .ifPresent(a -> attrWriter.write(a, code)); - code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE) + code.findAttribute(Attributes.localVariableTable()) .ifPresent(a -> attrWriter.write(a, code)); } } @@ -589,7 +589,7 @@ void writeModifiers(Collection items) { public static final int ACC_STATIC_PHASE = 0x0040; void writeDirectives() { - var attr = classModel.findAttribute(Attributes.MODULE); + var attr = classModel.findAttribute(Attributes.module()); if (attr.isEmpty()) return; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java index 1c32fff24e06a..ac8ab164e629b 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java @@ -674,7 +674,7 @@ protected int writeClass(ClassWriter classWriter, String className) if (options.showInnerClasses) { ClassModel cm = cfInfo.cm; - var a = cm.findAttribute(java.lang.classfile.Attributes.INNER_CLASSES); + var a = cm.findAttribute(java.lang.classfile.Attributes.innerClasses()); if (a.isPresent()) { var inners = a.get(); try { diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTableWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTableWriter.java index d6b57ca4c48f2..f19d8fce4bbb5 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTableWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTableWriter.java @@ -80,7 +80,7 @@ protected LocalVariableTableWriter(Context context) { public void reset(CodeModel attr) { codeAttr = attr; pcMap = new HashMap<>(); - var lvt = attr.findAttribute(Attributes.LOCAL_VARIABLE_TABLE); + var lvt = attr.findAttribute(Attributes.localVariableTable()); if (lvt.isEmpty()) return; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java index f9ac8c70e0f93..04e7b3fd0e0b8 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java @@ -80,7 +80,7 @@ protected LocalVariableTypeTableWriter(Context context) { public void reset(CodeModel attr) { codeAttr = attr; pcMap = new HashMap<>(); - var lvt = attr.findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE); + var lvt = attr.findAttribute(Attributes.localVariableTypeTable()); if (lvt.isEmpty()) return; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/SourceWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/SourceWriter.java index 1d06727ff63a9..884c0fa9f80bc 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/SourceWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/SourceWriter.java @@ -105,7 +105,7 @@ public boolean hasSource() { private void setLineMap(CodeModel attr) { SortedMap> map = new TreeMap<>(); SortedSet allLines = new TreeSet<>(); - for (var t : attr.findAttributes(Attributes.LINE_NUMBER_TABLE)) { + for (var t : attr.findAttributes(Attributes.lineNumberTable())) { for (var e: t.lineNumbers()) { int start_pc = e.startPc(); int line = e.lineNumber(); @@ -145,7 +145,7 @@ private String readSource(ClassModel cf) { // InnerClasses and EnclosingMethod attributes. try { String className = cf.thisClass().asInternalName(); - var sf = cf.findAttribute(Attributes.SOURCE_FILE); + var sf = cf.findAttribute(Attributes.sourceFile()); if (sf.isEmpty()) { report(messages.getMessage("err.no.SourceFile.attribute")); return null; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java index 9a83fddbb87de..a1d939bcc4f23 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java @@ -62,7 +62,7 @@ public void reset(CodeAttribute code) { } void setStackMap(CodeAttribute code) { - StackMapTableAttribute attr = code.findAttribute(Attributes.STACK_MAP_TABLE) + StackMapTableAttribute attr = code.findAttribute(Attributes.stackMapTable()) .orElse(null); if (attr == null) { map = null; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/TypeAnnotationWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/TypeAnnotationWriter.java index a0236955cfca5..d5e19bc4241c2 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/TypeAnnotationWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/TypeAnnotationWriter.java @@ -76,10 +76,10 @@ public void reset(CodeAttribute attr) { pcMap = new HashMap<>(); codeAttribute = attr; check(NoteKind.VISIBLE, - m.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS) + m.findAttribute(Attributes.runtimeVisibleTypeAnnotations()) .map(a -> a.annotations())); check(NoteKind.INVISIBLE, - m.findAttribute(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) + m.findAttribute(Attributes.runtimeInvisibleTypeAnnotations()) .map(a -> a.annotations())); } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java index 422845150f041..c0ac835f4b605 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java @@ -597,7 +597,7 @@ private void scan(MethodTypeDesc mtd) { void scanAttributes(AttributedElement attrs) { try { - var sa = attrs.findAttribute(Attributes.SIGNATURE).orElse(null); + var sa = attrs.findAttribute(Attributes.signature()).orElse(null); if (sa != null) { switch (attrs) { case ClassModel _ -> scan(sa.asClassSignature()); @@ -606,14 +606,14 @@ void scanAttributes(AttributedElement attrs) { } } - var rvaa = attrs.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + var rvaa = attrs.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (rvaa != null) { for (var anno : rvaa.annotations()) { scan(anno.classSymbol()); } } - var rvpaa = attrs.findAttribute(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS).orElse(null); + var rvpaa = attrs.findAttribute(Attributes.runtimeVisibleParameterAnnotations()).orElse(null); if (rvpaa != null) { for (var parameter : rvpaa.parameterAnnotations()) { for (var anno : parameter) { @@ -622,7 +622,7 @@ void scanAttributes(AttributedElement attrs) { } } - var exceptions = attrs.findAttribute(Attributes.EXCEPTIONS).orElse(null); + var exceptions = attrs.findAttribute(Attributes.exceptions()).orElse(null); if (exceptions != null) { for (var e : exceptions.exceptions()) { addClass(e); diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java index dbcf77d3e3928..f53b8acbb8b2e 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java @@ -345,7 +345,7 @@ Value invokeMethod(ThreadReference thread, Method method, /** * Returns a List containing a {@link ThreadReference} for - * each thread currently waiting for this object's monitor. + * each platform thread currently waiting for this object's monitor. * See {@link ThreadReference#currentContendedMonitor} for * information about when a thread is considered to be waiting * for a monitor. @@ -355,7 +355,8 @@ Value invokeMethod(ThreadReference thread, Method method, * operation is supported. * * @return a List of {@link ThreadReference} objects. The list - * has zero length if no threads are waiting for the monitor. + * has zero length if no threads are waiting for the monitor, + * or only virtual threads are waiting for the monitor. * @throws java.lang.UnsupportedOperationException if the * target VM does not support this operation. * @throws IncompatibleThreadStateException if any @@ -366,7 +367,7 @@ List waitingThreads() throws IncompatibleThreadStateException; /** - * Returns an {@link ThreadReference} for the thread, if any, + * Returns a {@link ThreadReference} for the platform thread, if any, * which currently owns this object's monitor. * See {@link ThreadReference#ownedMonitors} for a definition * of ownership. @@ -375,8 +376,9 @@ List waitingThreads() * {@link VirtualMachine#canGetMonitorInfo} to determine if the * operation is supported. * - * @return the {@link ThreadReference} which currently owns the - * monitor, or null if it is unowned. + * @return the {@link ThreadReference} of the platform thread which + * currently owns the monitor, or null if the monitor is owned + * by a virtual thread or not owned. * * @throws java.lang.UnsupportedOperationException if the * target VM does not support this operation. @@ -386,8 +388,9 @@ List waitingThreads() ThreadReference owningThread() throws IncompatibleThreadStateException; /** - * Returns the number times this object's monitor has been - * entered by the current owning thread. + * Returns the number of times this object's monitor has been entered by + * the current owning thread if the owning thread is platform thread; + * Returns 0 if not owned by a platform thread. * See {@link ThreadReference#ownedMonitors} for a definition * of ownership. *

    diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java index 68901aebc8461..e481a699d1bbf 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java @@ -191,6 +191,46 @@ public void close() throws IOException { } return reader; } + /** + * {@inheritDoc} + */ + @Override + public JdkConsole println(Object obj) { + writer().println(obj); + writer().flush(); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public JdkConsole print(Object obj) { + writer().print(obj); + writer().flush(); + return this; + } + + /** + * {@inheritDoc} + * + * @throws IOError {@inheritDoc} + */ + @Override + public String readln(String prompt) { + try { + return sendAndReceive(() -> { + remoteInput.write(Task.READ_LINE.ordinal()); + char[] chars = (prompt == null ? "null" : prompt).toCharArray(); + sendChars(chars, 0, chars.length); + char[] line = readChars(); + return new String(line); + }); + } catch (IOException ex) { + throw new IOError(ex); + } + } + /** * {@inheritDoc} */ diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index ffd5eaac1898b..a8cdad8b26810 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -67,6 +67,7 @@ compiler/c2/Test8004741.java 8235801 generic-all compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all +compiler/codecache/CheckLargePages.java 8332654 linux-x64 compiler/vectorapi/reshape/TestVectorReinterpret.java 8320897 aix-ppc64,linux-ppc64le compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x64 diff --git a/test/hotspot/jtreg/compiler/c2/cr7200264/TestIntVect.java b/test/hotspot/jtreg/compiler/c2/cr7200264/TestIntVect.java index d39c195b55fda..17556896f2606 100644 --- a/test/hotspot/jtreg/compiler/c2/cr7200264/TestIntVect.java +++ b/test/hotspot/jtreg/compiler/c2/cr7200264/TestIntVect.java @@ -481,6 +481,9 @@ void test_suba(int[] a0, int[] a1, int[] a2) { @Test @IR(counts = { IRNode.SUB_VI, "> 0", IRNode.LSHIFT_VI, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.SUB_VI, "> 0", IRNode.LSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_mulc(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]*VALUE); @@ -490,6 +493,9 @@ void test_mulc(int[] a0, int[] a1) { @Test @IR(counts = { IRNode.SUB_VI, "> 0", IRNode.LSHIFT_VI, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.SUB_VI, "> 0", IRNode.LSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_mulc_n(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]*(-VALUE)); @@ -522,6 +528,14 @@ void test_mula(int[] a0, int[] a1, int[] a2) { IRNode.SUB_VI, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + @IR(counts = { IRNode.ADD_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.RSHIFT_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.SUB_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) // Not vectorized: On aarch64, vectorization for this example results in // MulVL nodes, which asimd does not support. @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", @@ -542,6 +556,14 @@ void test_divc(int[] a0, int[] a1) { IRNode.SUB_VI, IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + @IR(counts = { IRNode.ADD_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.RSHIFT_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0", + IRNode.SUB_VI, + IRNode.VECTOR_SIZE + "min(max_int, max_long)", "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) // Not vectorized: On aarch64, vectorization for this example results in // MulVL nodes, which asimd does not support. @IR(counts = { IRNode.LOAD_VECTOR_I, "= 0", @@ -662,6 +684,9 @@ void test_xora(int[] a0, int[] a1, int[] a2) { @Test @IR(counts = { IRNode.LSHIFT_VI, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.LSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_sllc(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]< 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.LSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_sllc_n(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]<<(-VALUE)); @@ -683,6 +711,11 @@ void test_sllc_n(int[] a0, int[] a1) { IRNode.LOAD_VECTOR_I, "> 0", IRNode.STORE_VECTOR, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.LSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_sllc_o(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]< 0", IRNode.STORE_VECTOR, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.LSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_sllc_on(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]<<(-SHIFT)); @@ -704,6 +742,9 @@ void test_sllc_on(int[] a0, int[] a1) { @Test @IR(counts = { IRNode.LSHIFT_VI, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.LSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_sllv(int[] a0, int[] a1, int b) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]< 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.URSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srlc(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>>VALUE); @@ -722,6 +766,9 @@ void test_srlc(int[] a0, int[] a1) { @Test @IR(counts = { IRNode.URSHIFT_VI, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.URSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srlc_n(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>>(-VALUE)); @@ -734,6 +781,11 @@ void test_srlc_n(int[] a0, int[] a1) { IRNode.LOAD_VECTOR_I, "> 0", IRNode.STORE_VECTOR, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.URSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srlc_o(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>>SHIFT); @@ -746,6 +798,11 @@ void test_srlc_o(int[] a0, int[] a1) { IRNode.LOAD_VECTOR_I, "> 0", IRNode.STORE_VECTOR, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.URSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srlc_on(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>>(-SHIFT)); @@ -755,6 +812,9 @@ void test_srlc_on(int[] a0, int[] a1) { @Test @IR(counts = { IRNode.URSHIFT_VI, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.URSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srlv(int[] a0, int[] a1, int b) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>>b); @@ -764,6 +824,9 @@ void test_srlv(int[] a0, int[] a1, int b) { @Test @IR(counts = { IRNode.RSHIFT_VI, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.RSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srac(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>VALUE); @@ -773,6 +836,9 @@ void test_srac(int[] a0, int[] a1) { @Test @IR(counts = { IRNode.RSHIFT_VI, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.RSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srac_n(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>(-VALUE)); @@ -785,6 +851,11 @@ void test_srac_n(int[] a0, int[] a1) { IRNode.LOAD_VECTOR_I, "> 0", IRNode.STORE_VECTOR, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.RSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srac_o(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>SHIFT); @@ -797,6 +868,11 @@ void test_srac_o(int[] a0, int[] a1) { IRNode.LOAD_VECTOR_I, "> 0", IRNode.STORE_VECTOR, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.RSHIFT_VI, "= 0", + IRNode.LOAD_VECTOR_I, "> 0", + IRNode.STORE_VECTOR, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srac_on(int[] a0, int[] a1) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>(-SHIFT)); @@ -806,6 +882,9 @@ void test_srac_on(int[] a0, int[] a1) { @Test @IR(counts = { IRNode.RSHIFT_VI, "> 0" }, applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = { IRNode.RSHIFT_VI, "> 0" }, + applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}) void test_srav(int[] a0, int[] a1, int b) { for (int i = 0; i < a0.length; i+=1) { a0[i] = (int)(a1[i]>>b); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeURShiftSubword.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeURShiftSubword.java index ebe3fe63ccfda..f477a08f7174a 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeURShiftSubword.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizeURShiftSubword.java @@ -34,7 +34,8 @@ * @bug 8283307 * @key randomness * @summary Auto-vectorization enhancement for unsigned shift right on signed subword types - * @requires ((os.arch=="amd64" | os.arch=="x86_64") & (vm.opt.UseSSE == "null" | vm.opt.UseSSE > 3)) | os.arch=="aarch64" + * @requires ((os.arch=="amd64" | os.arch=="x86_64") & (vm.opt.UseSSE == "null" | vm.opt.UseSSE > 3)) | os.arch=="aarch64" | + * (os.arch == "riscv64" & vm.cpu.features ~= ".*v,.*") * @library /test/lib / * @run driver compiler.c2.irTests.TestVectorizeURShiftSubword */ diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index ae077b3b3f44c..00973fd78c29d 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -678,7 +678,7 @@ public void getOopMapAtTest() throws Exception { Map methodMap = buildMethodMap(type); ClassModel cf = readClassfile(c); for (MethodModel cm : cf.methods()) { - cm.findAttribute(Attributes.CODE).ifPresent(codeAttr -> { + cm.findAttribute(Attributes.code()).ifPresent(codeAttr -> { String key = cm.methodName().stringValue() + ":" + cm.methodType().stringValue(); HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod) Objects.requireNonNull(methodMap.get(key)); boolean isMethodWithManyArgs = c == getClass() && m.getName().equals("methodWithManyArgs"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 11f324a91e1a1..1fb68439afbb2 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -755,6 +755,11 @@ public class IRNode { beforeMatchingNameRegex(LOAD_VECTOR_GATHER, "LoadVectorGather"); } + public static final String LOAD_VECTOR_MASKED = PREFIX + "LOAD_VECTOR_MASKED" + POSTFIX; + static { + beforeMatchingNameRegex(LOAD_VECTOR_MASKED, "LoadVectorMasked"); + } + public static final String LOAD_VECTOR_GATHER_MASKED = PREFIX + "LOAD_VECTOR_GATHER_MASKED" + POSTFIX; static { beforeMatchingNameRegex(LOAD_VECTOR_GATHER_MASKED, "LoadVectorGatherMasked"); @@ -1479,6 +1484,11 @@ public class IRNode { beforeMatchingNameRegex(STORE_VECTOR_SCATTER, "StoreVectorScatter"); } + public static final String STORE_VECTOR_MASKED = PREFIX + "STORE_VECTOR_MASKED" + POSTFIX; + static { + beforeMatchingNameRegex(STORE_VECTOR_MASKED, "StoreVectorMasked"); + } + public static final String STORE_VECTOR_SCATTER_MASKED = PREFIX + "STORE_VECTOR_SCATTER_MASKED" + POSTFIX; static { beforeMatchingNameRegex(STORE_VECTOR_SCATTER_MASKED, "StoreVectorScatterMasked"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java index 5269707256037..82d4a398ab698 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java @@ -104,6 +104,7 @@ public class IREncodingPrinter { "asimd", "sve", // Riscv64 + "v", "zvbb" )); diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java index e27feb36e868c..7526d1809520d 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java @@ -30,6 +30,7 @@ * @requires vm.compiler2.enabled * @key randomness * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=MemLimit,*.*,0 * -XX:LoopUnrollLimit=250 * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* * compiler.loopopts.superword.TestAlignVectorFuzzer @@ -44,6 +45,7 @@ * @requires vm.compiler2.enabled * @key randomness * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=MemLimit,*.*,0 * -XX:+AlignVector -XX:+VerifyAlignVector * -XX:LoopUnrollLimit=250 * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* @@ -60,6 +62,7 @@ * @requires vm.bits == 64 * @key randomness * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=MemLimit,*.*,0 * -XX:+AlignVector -XX:+VerifyAlignVector * -XX:LoopUnrollLimit=250 * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* @@ -76,6 +79,7 @@ * @requires vm.compiler2.enabled * @key randomness * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions + * -XX:CompileCommand=MemLimit,*.*,0 * -XX:+AlignVector -XX:+VerifyAlignVector * -XX:LoopUnrollLimit=250 * -XX:CompileCommand=printcompilation,compiler.loopopts.superword.TestAlignVectorFuzzer::* diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java index c65da58b28597..4521d43804b86 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8310886 8325252 + * @bug 8310886 8325252 8320622 * @summary Test MulAddS2I vectorization. * @library /test/lib / * @run driver compiler.loopopts.superword.TestMulAddS2I @@ -68,12 +68,8 @@ public class TestMulAddS2I { public static void main(String[] args) { - if (Platform.isX64() || Platform.isX86()) { - TestFramework.runWithFlags("-XX:+UseUnalignedLoadStores"); - TestFramework.runWithFlags("-XX:-UseUnalignedLoadStores"); - } else { - TestFramework.run(); - } + TestFramework.runWithFlags("-XX:+AlignVector"); + TestFramework.runWithFlags("-XX:-AlignVector"); } @Run(test = {"testa", "testb", "testc", "testd", "teste", "testf", "testg", "testh"}) diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java deleted file mode 100644 index 7f22db08a36da..0000000000000 --- a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright (c) 2024, 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 8324517 - * @summary C2: out of bound array load because of dependency on removed range check CastIIs - * - * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation - * -XX:CompileCommand=dontinline,TestArrayAccessAboveRCAfterRCCastIIEliminated::notInlined - * TestArrayAccessAboveRCAfterRCCastIIEliminated - * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation - * -XX:CompileCommand=dontinline,TestArrayAccessAboveRCAfterRCCastIIEliminated::notInlined - * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM TestArrayAccessAboveRCAfterRCCastIIEliminated - * @run main/othervm TestArrayAccessAboveRCAfterRCCastIIEliminated - * @run main/othervm -XX:CompileCommand=dontinline,TestArrayAccessAboveRCAfterRCCastIIEliminated::notInlined - * TestArrayAccessAboveRCAfterRCCastIIEliminated - * - */ - -public class TestArrayAccessAboveRCAfterRCCastIIEliminated { - private static int intField; - private static long longField; - private static volatile int volatileField; - - public static void main(String[] args) { - int[] array = new int[100]; - for (int i = 0; i < 20_000; i++) { - test1(9, 10, 1, true); - test1(9, 10, 1, false); - test2(9, 10, 1, true); - test2(9, 10, 1, false); - test3(9, 10, 1, true); - test3(9, 10, 1, false); - test4(9, 10, 1, true); - test4(9, 10, 1, false); - test5(9, 10, 1, true); - test5(9, 10, 1, false); - test6(9, 10, 1, true); - test6(9, 10, 1, false); - test7(9, 10, 1, true); - test7(9, 10, 1, false); - test8(9, 10, 1, true); - test8(9, 10, 1, false); - test9(9, 10, 1, true); - test9(9, 10, 1, false); - test10(9, 10, 1, true); - test10(9, 10, 1, false); - test11(9, 10, 1, true); - test11(9, 10, 1, false); - test12(9, 10, 1, true); - test12(9, 10, 1, false); - test13(9, 10, 1, true); - test13(9, 10, 1, false); - } - try { - test1(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test2(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test3(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test4(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test5(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test6(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test7(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test8(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test9(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test10(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test11(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test12(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test13(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - } - - private static void test1(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = array[otherArray.length]; - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = array[otherArray.length]; - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test2(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 / (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 / (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test3(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L / (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L / (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test4(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 % (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 % (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test5(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L % (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L % (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test6(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 % (otherArray.length + 1) + 1 / (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 % (otherArray.length + 1) + 1 / (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test7(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L % (otherArray.length + 1) + 1L / (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L % (otherArray.length + 1) + 1L / (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - private static void test8(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.divideUnsigned(1, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.divideUnsigned(1, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test9(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.divideUnsigned(1L, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.divideUnsigned(1L, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test10(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.remainderUnsigned(1, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.remainderUnsigned(1, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test11(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.remainderUnsigned(1L, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.remainderUnsigned(1L, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test12(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.divideUnsigned(1, (otherArray.length + 1)) + - Integer.remainderUnsigned(1, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.divideUnsigned(1, (otherArray.length + 1)) + - Integer.remainderUnsigned(1, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test13(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.remainderUnsigned(1L, (otherArray.length + 1)) + - Long.divideUnsigned(1L, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.remainderUnsigned(1L, (otherArray.length + 1)) + - Long.divideUnsigned(1L, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void notInlined(int[] array) { - - } -} diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java new file mode 100644 index 0000000000000..88d1bbde1d499 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java @@ -0,0 +1,1404 @@ +/* + * Copyright (c) 2024, 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.vectorapi; + +import compiler.lib.ir_framework.*; + +import jdk.test.lib.Asserts; +import jdk.incubator.vector.*; +import java.util.Arrays; +import java.nio.ByteOrder; + +/** + * @test + * @bug 8325520 + * @library /test/lib / + * @summary Don't allow folding of Load/Store vectors when using incompatible indices or masks + * @modules jdk.incubator.vector + * + * @run driver compiler.vectorapi.VectorGatherMaskFoldingTest + */ + +public class VectorGatherMaskFoldingTest { + // Species + private static final VectorSpecies L_SPECIES = LongVector.SPECIES_MAX; + private static final VectorSpecies I_SPECIES = IntVector.SPECIES_MAX; + private static final VectorSpecies F_SPECIES = FloatVector.SPECIES_MAX; + private static final VectorSpecies D_SPECIES = DoubleVector.SPECIES_MAX; + // Vectors + private static final LongVector longVector; + private static final LongVector longVector2; + private static final IntVector intVector; + private static final IntVector intVector2; + private static final DoubleVector doubleVector; + private static final DoubleVector doubleVector2; + private static final FloatVector floatVector; + private static final FloatVector floatVector2; + // Arrays + private static final long[] longArray = new long[L_SPECIES.length()]; + private static final long[] longArray2 = new long[L_SPECIES.length()]; + private static final int[] intArray = new int[I_SPECIES.length()]; + private static final int[] intArray2 = new int[I_SPECIES.length()]; + private static final double[] doubleArray = new double[D_SPECIES.length()]; + private static final double[] doubleArray2 = new double[D_SPECIES.length()]; + private static final float[] floatArray = new float[F_SPECIES.length()]; + private static final float[] floatArray2 = new float[F_SPECIES.length()]; + // Indices + private static final int[] longIndices = new int[L_SPECIES.length()]; + private static final int[] longIndices2 = new int[L_SPECIES.length()]; + private static final int[] duplicateLongIndices = new int[L_SPECIES.length()]; + private static final int[] intIndices = new int[I_SPECIES.length()]; + private static final int[] intIndices2 = new int[I_SPECIES.length()]; + private static final int[] duplicateIntIndices = new int[I_SPECIES.length()]; + private static final int[] doubleIndices = new int[D_SPECIES.length()]; + private static final int[] doubleIndices2 = new int[D_SPECIES.length()]; + private static final int[] duplicateDoubleIndices = new int[D_SPECIES.length()]; + private static final int[] floatIndices = new int[F_SPECIES.length()]; + private static final int[] floatIndices2 = new int[F_SPECIES.length()]; + private static final int[] duplicateFloatIndices = new int[F_SPECIES.length()]; + // Masks + private static final boolean[] longMask = new boolean[L_SPECIES.length()]; + private static final boolean[] longMask2 = new boolean[L_SPECIES.length()]; + private static final boolean[] intMask = new boolean[I_SPECIES.length()]; + private static final boolean[] intMask2 = new boolean[I_SPECIES.length()]; + private static final boolean[] doubleMask = new boolean[D_SPECIES.length()]; + private static final boolean[] doubleMask2 = new boolean[D_SPECIES.length()]; + private static final boolean[] floatMask = new boolean[F_SPECIES.length()]; + private static final boolean[] floatMask2 = new boolean[F_SPECIES.length()]; + private static final VectorMask longVectorMask; + private static final VectorMask longVectorMask2; + private static final VectorMask intVectorMask; + private static final VectorMask intVectorMask2; + private static final VectorMask doubleVectorMask; + private static final VectorMask doubleVectorMask2; + private static final VectorMask floatVectorMask; + private static final VectorMask floatVectorMask2; + + // Filling vectors/indices/masks + static { + for (int i = 0; i < L_SPECIES.length(); i++) { + longArray[i] = i + 1; + longArray2[i] = L_SPECIES.length() - i + 1; + longMask[i] = i % 2 == 0; + longMask2[i] = i >= L_SPECIES.length() / 2; + longIndices[i] = (i + L_SPECIES.length() / 2) % L_SPECIES.length(); + longIndices2[i] = (L_SPECIES.length() - i) % L_SPECIES.length(); + duplicateLongIndices[i] = longIndices[i] / 2; + } + longVector = LongVector.fromArray(L_SPECIES, longArray, 0); + longVector2 = LongVector.fromArray(L_SPECIES, longArray2, 0); + longVectorMask = VectorMask.fromArray(L_SPECIES, longMask, 0); + longVectorMask2 = VectorMask.fromArray(L_SPECIES, longMask2, 0); + for (int i = 0; i < I_SPECIES.length(); i++) { + intArray[i] = i + 1; + intArray2[i] = I_SPECIES.length() - i + 1; + intMask[i] = i % 2 == 0; + intMask2[i] = i >= I_SPECIES.length() / 2; + intIndices[i] = (i + I_SPECIES.length() / 2) % I_SPECIES.length(); + intIndices2[i] = (I_SPECIES.length() - i) % I_SPECIES.length(); + duplicateIntIndices[i] = intIndices[i] / 2; + } + intVector = IntVector.fromArray(I_SPECIES, intArray, 0); + intVector2 = IntVector.fromArray(I_SPECIES, intArray2, 0); + intVectorMask = VectorMask.fromArray(I_SPECIES, intMask, 0); + intVectorMask2 = VectorMask.fromArray(I_SPECIES, intMask2, 0); + for (int i = 0; i < D_SPECIES.length(); i++) { + doubleArray[i] = (double) i + 1.0; + doubleArray2[i] = (double) (D_SPECIES.length() - i) + 1.0; + doubleMask[i] = i % 2 == 0; + doubleMask2[i] = i >= D_SPECIES.length() / 2; + doubleIndices[i] = (i + D_SPECIES.length() / 2) % D_SPECIES.length(); + doubleIndices2[i] = (D_SPECIES.length() - i) % D_SPECIES.length(); + duplicateDoubleIndices[i] = doubleIndices[i] / 2; + } + doubleVector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + doubleVector2 = DoubleVector.fromArray(D_SPECIES, doubleArray2, 0); + doubleVectorMask = VectorMask.fromArray(D_SPECIES, doubleMask, 0); + doubleVectorMask2 = VectorMask.fromArray(D_SPECIES, doubleMask2, 0); + for (int i = 0; i < F_SPECIES.length(); i++) { + floatArray[i] = i + 1.0f; + floatArray2[i] = F_SPECIES.length() - i + 1.0f; + floatMask[i] = i % 2 == 0; + floatMask2[i] = i >= F_SPECIES.length() / 2; + floatIndices[i] = (i + F_SPECIES.length() / 2) % F_SPECIES.length(); + floatIndices2[i] = (F_SPECIES.length() - i) % F_SPECIES.length(); + duplicateFloatIndices[i] = floatIndices[i] / 2; + } + floatVector = FloatVector.fromArray(F_SPECIES, floatArray, 0); + floatVector2 = FloatVector.fromArray(F_SPECIES, floatArray2, 0); + floatVectorMask = VectorMask.fromArray(F_SPECIES, floatMask, 0); + floatVectorMask2 = VectorMask.fromArray(F_SPECIES, floatMask2, 0); + } + + // LOAD TESTS + + // LongVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherNotEqualArray() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray2, 0, longIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherNotEqualIndices() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneLongVectorLoadGather() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneLongVectorLoadMasked() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherEquals() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadMaskedEquals() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadMaskedNotEqualMask() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherMaskedEquals() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherMaskedNotEqualMask() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherMaskedNotEqualIndices() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices2, 0, longVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherNotEqualArray() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray2, 0, intIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherNotEqualIndices() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneIntVectorLoadGather() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneIntVectorLoadMasked() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherEquals() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadMaskedEquals() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadMaskedNotEqualMask() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherMaskedEquals() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherMaskedNotEqualMask() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherMaskedNotEqualIndices() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices2, 0, intVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherNotEqualArray() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray2, 0, doubleIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherNotEqualIndices() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_D, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadGather() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_D, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadMasked() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherEquals() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadMaskedEquals() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadMaskedNotEqualMask() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherMaskedEquals() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherMaskedNotEqualMask() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherMaskedNotEqualIndices() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices2, 0, doubleVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherNotEqualArray() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray2, 0, floatIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherNotEqualIndices() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_F, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneFloatVectorLoadGather() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_F, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneFloatVectorLoadMasked() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherEquals() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadMaskedEquals() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadMaskedNotEqualMask() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherMaskedEquals() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherMaskedNotEqualMask() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherMaskedNotEqualIndices() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices2, 0, floatVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // STORE TESTS + + // LongVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterNotEqualVector() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0); + longVector2.intoArray(res2, 0, longIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterNotEqualIndices() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0); + longVector.intoArray(res2, 0, longIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreScatter() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0); + longVector.intoArray(res2, 0, longIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreMasked() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0); + longVector.intoArray(res2, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterEquals() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0); + longVector.intoArray(res2, 0, longIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreMaskedEquals() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longVectorMask); + longVector.intoArray(res2, 0, longVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreMaskedNotEqualMask() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longVectorMask); + longVector.intoArray(res2, 0, longVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterMaskedEquals() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0, longVectorMask); + longVector.intoArray(res2, 0, longIndices, 0, longVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterMaskedNotEqualMask() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0, longVectorMask); + longVector.intoArray(res2, 0, longIndices, 0, longVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterMaskedNotEqualIndices() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0, longVectorMask); + longVector.intoArray(res2, 0, longIndices2, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterNotEqualVector() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0); + intVector2.intoArray(res2, 0, intIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterNotEqualIndices() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0); + intVector.intoArray(res2, 0, intIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreScatter() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0); + intVector.intoArray(res2, 0, intIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreMasked() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0); + intVector.intoArray(res2, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterEquals() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0); + intVector.intoArray(res2, 0, intIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreMaskedEquals() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intVectorMask); + intVector.intoArray(res2, 0, intVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreMaskedNotEqualMask() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intVectorMask); + intVector.intoArray(res2, 0, intVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterMaskedEquals() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0, intVectorMask); + intVector.intoArray(res2, 0, intIndices, 0, intVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterMaskedNotEqualMask() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0, intVectorMask); + intVector.intoArray(res2, 0, intIndices, 0, intVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterMaskedNotEqualIndices() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0, intVectorMask); + intVector.intoArray(res2, 0, intIndices2, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterNotEqualVector() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0); + doubleVector2.intoArray(res2, 0, doubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterNotEqualIndices() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0); + doubleVector.intoArray(res2, 0, doubleIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreScatter() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0); + doubleVector.intoArray(res2, 0, doubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreMasked() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0); + doubleVector.intoArray(res2, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterEquals() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0); + doubleVector.intoArray(res2, 0, doubleIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreMaskedEquals() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreMaskedNotEqualMask() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterMaskedEquals() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleIndices, 0, doubleVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterMaskedNotEqualMask() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleIndices, 0, doubleVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterMaskedNotEqualIndices() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleIndices2, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterNotEqualVector() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0); + floatVector2.intoArray(res2, 0, floatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterNotEqualIndices() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0); + floatVector.intoArray(res2, 0, floatIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreScatter() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0); + floatVector.intoArray(res2, 0, floatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreMasked() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0); + floatVector.intoArray(res2, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterEquals() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0); + floatVector.intoArray(res2, 0, floatIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreMaskedEquals() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreMaskedNotEqualMask() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterMaskedEquals() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatIndices, 0, floatVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterMaskedNotEqualMask() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatIndices, 0, floatVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterMaskedNotEqualIndices() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatIndices2, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // STORE - LOAD tests + + // LongVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreLoadGather() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0, longIndices, 0); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreScatterLoad() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0, longIndices, 0); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreLoadMasked() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0, longVectorMask); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreMaskedLoad() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0, longVectorMask); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorLoadGatherStoreScatterDuplicateIndicesVector() { + long[] res = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, duplicateLongIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, res, 0, duplicateLongIndices, 0); + Asserts.assertNotEquals(res2, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorStoreLoadMaskedVector() { + long[] res = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, res, 0, longVectorMask); + Asserts.assertNotEquals(res2, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadLongVectorDifferentSpeciesVector() { + long[] res = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0); + LongVector res2 = LongVector.fromArray(LongVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, longVector); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreLoadGather() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0, intIndices, 0); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreScatterLoad() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0, intIndices, 0); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreLoadMasked() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0, intVectorMask); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreMaskedLoad() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0, intVectorMask); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorLoadGatherStoreScatterDuplicateIndicesVector() { + int[] res = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, duplicateIntIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, res, 0, duplicateIntIndices, 0); + Asserts.assertNotEquals(res2, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorStoreLoadMaskedVector() { + int[] res = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, res, 0, intVectorMask); + Asserts.assertNotEquals(res2, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadIntVectorDifferentSpeciesVector() { + int[] res = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0); + IntVector res2 = IntVector.fromArray(IntVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, intVector); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreLoadGather() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0, doubleIndices, 0); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreScatterLoad() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0, doubleIndices, 0); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreLoadMasked() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0, doubleVectorMask); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreMaskedLoad() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0, doubleVectorMask); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorLoadGatherStoreScatterDuplicateIndicesVector() { + double[] res = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, duplicateDoubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, res, 0, duplicateDoubleIndices, 0); + Asserts.assertNotEquals(res2, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorStoreLoadMaskedVector() { + double[] res = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, res, 0, doubleVectorMask); + Asserts.assertNotEquals(res2, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadDoubleVectorDifferentSpeciesVector() { + double[] res = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0); + DoubleVector res2 = DoubleVector.fromArray(DoubleVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, doubleVector); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreLoadGather() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0, floatIndices, 0); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreScatterLoad() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0, floatIndices, 0); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreLoadMasked() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0, floatVectorMask); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreMaskedLoad() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0, floatVectorMask); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorLoadGatherStoreScatterDuplicateIndicesVector() { + float[] res = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, duplicateFloatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, res, 0, duplicateFloatIndices, 0); + Asserts.assertNotEquals(res2, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorStoreLoadMaskedVector() { + float[] res = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, res, 0, floatVectorMask); + Asserts.assertNotEquals(res2, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadFloatVectorDifferentSpeciesVector() { + float[] res = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0); + FloatVector res2 = FloatVector.fromArray(FloatVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, floatVector); + } + + + // LOAD - STORE tests + + // LongVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadGatherStore() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadStoreScatter() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0); + vector.intoArray(res, 0, longIndices, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadMaskedStore() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadStoreMasked() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0); + vector.intoArray(res, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorStoreScatterLoadGatherDuplicateIndicesVector() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, duplicateLongIndices, 0); + vector.intoArray(res, 0, duplicateLongIndices, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorLoadMaskedStoreVector() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + vector.intoArray(res, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadGatherStore() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadStoreScatter() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0); + vector.intoArray(res, 0, intIndices, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadMaskedStore() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadStoreMasked() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0); + vector.intoArray(res, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorStoreScatterLoadGatherDuplicateIndicesVector() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, duplicateIntIndices, 0); + vector.intoArray(res, 0, duplicateIntIndices, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorLoadMaskedStoreVector() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + vector.intoArray(res, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadGatherStore() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadStoreScatter() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + vector.intoArray(res, 0, doubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadMaskedStore() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadStoreMasked() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + vector.intoArray(res, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorStoreScatterLoadGatherDuplicateIndicesVector() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, duplicateDoubleIndices, 0); + vector.intoArray(res, 0, duplicateDoubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorLoadMaskedStoreVector() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + vector.intoArray(res, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadGatherStore() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadStoreScatter() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0); + vector.intoArray(res, 0, floatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadMaskedStore() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadStoreMasked() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0); + vector.intoArray(res, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorStoreScatterLoadGatherDuplicateIndicesVector() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, duplicateFloatIndices, 0); + vector.intoArray(res, 0, duplicateFloatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorLoadMaskedStoreVector() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + vector.intoArray(res, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector", "-XX:+IncrementalInlineForceCleanup") + .start(); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java index 74262142247fe..b723b349c2dae 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java @@ -35,7 +35,7 @@ * -XX:+WhiteBoxAPI * compiler.vectorization.runner.ArrayShiftOpTest * - * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64") + * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64") | (os.simpleArch == "riscv64") * @requires vm.compiler2.enabled */ @@ -99,6 +99,9 @@ public long[] longCombinedRotateShift() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.RSHIFT_VI, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VI, ">0"}) public int[] intShiftLargeDistConstant() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -110,6 +113,9 @@ public int[] intShiftLargeDistConstant() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.RSHIFT_VI, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VI, ">0"}) public int[] intShiftLargeDistInvariant() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -121,6 +127,9 @@ public int[] intShiftLargeDistInvariant() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.RSHIFT_VS, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VS, ">0"}) public short[] shortShiftLargeDistConstant() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -132,6 +141,9 @@ public short[] shortShiftLargeDistConstant() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.RSHIFT_VS, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VS, ">0"}) public short[] shortShiftLargeDistInvariant() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -143,6 +155,9 @@ public short[] shortShiftLargeDistInvariant() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.LSHIFT_VL, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.LSHIFT_VL, ">0"}) public long[] longShiftLargeDistConstant() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -154,6 +169,9 @@ public long[] longShiftLargeDistConstant() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.URSHIFT_VL, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.URSHIFT_VL, ">0"}) public long[] longShiftLargeDistInvariant() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -187,6 +205,9 @@ public short[] loopIndexShiftDistance() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.RSHIFT_VS, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VS, ">0"}) public short[] vectorUnsignedShiftRight() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicByteOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicByteOpTest.java index e0b5da1b71650..f080e29d1c358 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicByteOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicByteOpTest.java @@ -191,6 +191,9 @@ public byte[] vectorXor() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse4.1", "true"}, counts = {IRNode.LSHIFT_VB, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.LSHIFT_VB, ">0"}) public byte[] vectorShiftLeft() { byte[] res = new byte[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -202,6 +205,9 @@ public byte[] vectorShiftLeft() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse4.1", "true"}, counts = {IRNode.RSHIFT_VB, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VB, ">0"}) public byte[] vectorSignedShiftRight() { byte[] res = new byte[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -213,6 +219,9 @@ public byte[] vectorSignedShiftRight() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse4.1", "true"}, counts = {IRNode.RSHIFT_VB, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VB, ">0"}) public byte[] vectorUnsignedShiftRight() { byte[] res = new byte[SIZE]; for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicCharOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicCharOpTest.java index 6131e58d15624..9fa53609ea27e 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicCharOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicCharOpTest.java @@ -193,6 +193,9 @@ public char[] vectorXor() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.LSHIFT_VC, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.LSHIFT_VC, ">0"}) public char[] vectorShiftLeft() { char[] res = new char[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -204,6 +207,9 @@ public char[] vectorShiftLeft() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.URSHIFT_VC, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.URSHIFT_VC, ">0"}) public char[] vectorSignedShiftRight() { char[] res = new char[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -215,6 +221,9 @@ public char[] vectorSignedShiftRight() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.URSHIFT_VC, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.URSHIFT_VC, ">0"}) public char[] vectorUnsignedShiftRight() { char[] res = new char[SIZE]; for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicIntOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicIntOpTest.java index e848a15ffbc12..5774e3b63b2f0 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicIntOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicIntOpTest.java @@ -200,6 +200,9 @@ public int[] vectorXor() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.LSHIFT_VI, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.LSHIFT_VI, ">0"}) public int[] vectorShiftLeft() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -211,6 +214,9 @@ public int[] vectorShiftLeft() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.RSHIFT_VI, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VI, ">0"}) public int[] vectorSignedShiftRight() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -222,6 +228,9 @@ public int[] vectorSignedShiftRight() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.URSHIFT_VI, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.URSHIFT_VI, ">0"}) public int[] vectorUnsignedShiftRight() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicLongOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicLongOpTest.java index 80ebd7b64d0d1..c6ecac096f93a 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicLongOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicLongOpTest.java @@ -36,7 +36,7 @@ * -XX:+WhiteBoxAPI * compiler.vectorization.runner.BasicLongOpTest * - * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64") + * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64") | (os.simpleArch == "riscv64") * @requires vm.compiler2.enabled */ @@ -192,6 +192,9 @@ public long[] vectorXor() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.LSHIFT_VL, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.LSHIFT_VL, ">0"}) public long[] vectorShiftLeft() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -203,6 +206,9 @@ public long[] vectorShiftLeft() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.RSHIFT_VL, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VL, ">0"}) public long[] vectorSignedShiftRight() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -214,6 +220,9 @@ public long[] vectorSignedShiftRight() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.URSHIFT_VL, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.URSHIFT_VL, ">0"}) public long[] vectorUnsignedShiftRight() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicShortOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicShortOpTest.java index 363daf3a115ff..bf5516ddaf8a0 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicShortOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicShortOpTest.java @@ -191,6 +191,9 @@ public short[] vectorXor() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.LSHIFT_VS, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.LSHIFT_VS, ">0"}) public short[] vectorShiftLeft() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -202,6 +205,9 @@ public short[] vectorShiftLeft() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.RSHIFT_VS, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VS, ">0"}) public short[] vectorSignedShiftRight() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -238,6 +244,9 @@ public short[] vectorMax() { @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, counts = {IRNode.RSHIFT_VS, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"v", "true"}, + counts = {IRNode.RSHIFT_VS, ">0"}) public short[] vectorUnsignedShiftRight() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/gc/testlibrary/Helpers.java b/test/hotspot/jtreg/gc/testlibrary/Helpers.java index 03d67e44455da..a0c28ff25f7bf 100644 --- a/test/hotspot/jtreg/gc/testlibrary/Helpers.java +++ b/test/hotspot/jtreg/gc/testlibrary/Helpers.java @@ -88,7 +88,7 @@ public static int detectByteArrayAllocationOverhead() { * @param className class name * @param root root directory - where .java and .class files will be put * @param source class source - * @throws IOException if cannot write file to specified directory + * @throws Exception if cannot write file to specified directory */ public static void compileClass(String className, Path root, String source) throws Exception { Path sourceFile = root.resolve(className + ".java"); diff --git a/test/hotspot/jtreg/runtime/NMT/PeakMallocTest.java b/test/hotspot/jtreg/runtime/NMT/PeakMallocTest.java new file mode 100644 index 0000000000000..50757df61b19b --- /dev/null +++ b/test/hotspot/jtreg/runtime/NMT/PeakMallocTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8332122 + * @summary Test to verify correctness of peak malloc tracking + * @key randomness + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=summary -Xms32m -Xmx32m -Xint PeakMallocTest + * + */ + +// Note we run the test with -Xint to keep compilers from running and reduce malloc noise. + +import jdk.test.lib.process.OutputAnalyzer; + +import jdk.test.whitebox.WhiteBox; + +public class PeakMallocTest { + + private static WhiteBox wb = WhiteBox.getWhiteBox(); + private static final double FUDGE_FACTOR = 0.2; + + public static void main(String[] args) throws Exception { + + // Measure early malloc total and peak + OutputAnalyzer output = NMTTestUtils.startJcmdVMNativeMemory("scale=1"); + long earlyTotal = getMallocTotal(output); + long earlyPeak = getMallocPeak(output); + System.out.println("Early malloc total: " + earlyTotal); + System.out.println("Early malloc peak: " + earlyPeak); + + // Allocate a large amount of memory and then free + long allocSize = Math.max(8 * earlyPeak, 250 * 1024 * 1024); // MAX(earlyPeak * 8, 250MB) + long addr = wb.NMTMalloc(allocSize); + System.out.println("Allocation size: " + allocSize); + wb.NMTFree(addr); + + // Measure again + output = NMTTestUtils.startJcmdVMNativeMemory("scale=1"); + long currTotal = getMallocTotal(output); + long currPeak = getMallocPeak(output); + System.out.println("Current malloc total: " + currTotal); + System.out.println("Current malloc peak: " + currPeak); + + // Verify total global malloc is similar with a fudge factor + double mallocLowerBound = earlyTotal * (1 - FUDGE_FACTOR); + double mallocUpperBound = earlyTotal * (1 + FUDGE_FACTOR); + if (currTotal < mallocLowerBound || currTotal > mallocUpperBound) { + throw new Exception("Global malloc measurement is incorrect. " + + "Expected range: [" + mallocLowerBound + " - " + mallocUpperBound + "]. " + + "Actual malloc total: " + currTotal); + } + + // Verify global malloc peak reflects large allocation with a fudge factor + long peakDiff = currPeak - earlyPeak; + double peakLowerBound = allocSize * (1 - FUDGE_FACTOR); + double peakUpperBound = allocSize * (1 + FUDGE_FACTOR); + if (peakDiff < peakLowerBound || peakDiff > peakUpperBound) { + throw new Exception("Global malloc peak measurement is incorrect. " + + "Expected peak diff range: [" + peakLowerBound + " - " + peakUpperBound + "]. " + + "Actual peak diff: " + peakDiff); + } + } + + private static long getMallocPeak(OutputAnalyzer output) { + // First match should correspond to global malloc peak + String global = output.firstMatch("peak=\\d*"); + return Long.parseLong(global.substring(global.indexOf("=") + 1)); + } + + private static long getMallocTotal(OutputAnalyzer output) { + // First match should correspond to global malloc total + String global = output.firstMatch("malloc: \\d*"); + return Long.parseLong(global.substring(global.indexOf(" ") + 1)); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java new file mode 100644 index 0000000000000..50696c8c1fcc3 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023, 2024, 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 id=static + * @summary Run JavacBenchApp with the classic static archive workflow + * @requires vm.cds + * @library /test/lib + * @run driver JavacBench STATIC + */ + +/* + * @test id=dynamic + * @summary Run JavacBenchApp with the classic dynamic archive workflow + * @requires vm.cds + * @library /test/lib + * @run driver JavacBench DYNAMIC + */ + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class JavacBench { + static String mainClass = JavacBenchApp.class.getName(); + static String appJar; + + public static void main(String args[]) throws Exception { + appJar = ClassFileInstaller.writeJar("JavacBenchApp.jar", + "JavacBenchApp", + "JavacBenchApp$ClassFile", + "JavacBenchApp$FileManager", + "JavacBenchApp$SourceFile"); + JavacBenchTester tester = new JavacBenchTester(); + tester.run(args); + } + + static class JavacBenchTester extends CDSAppTester { + public JavacBenchTester() { + super("JavacBench"); + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, + "90", + }; + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBenchApp.java b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBenchApp.java new file mode 100644 index 0000000000000..a32069883af15 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBenchApp.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import java.lang.invoke.MethodHandles; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +/** + * This program tries to compile a large number of classes that exercise a fair amount of + * features in javac. + */ +public class JavacBenchApp { + static class ClassFile extends SimpleJavaFileObject { + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + protected ClassFile(String name) { + super(URI.create("memo:///" + name.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS); + } + @Override + public ByteArrayOutputStream openOutputStream() { + return this.baos; + } + byte[] toByteArray() { + return baos.toByteArray(); + } + } + + static class FileManager extends ForwardingJavaFileManager { + private Map classesMap = new HashMap(); + protected FileManager(JavaFileManager fileManager) { + super(fileManager); + } + @Override + public ClassFile getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) { + ClassFile classFile = new ClassFile(name); + classesMap.put(name, classFile); + return classFile; + } + public Map getCompiledClasses() { + Map result = new HashMap<>(); + for (Map.Entry entry : classesMap.entrySet()) { + result.put(entry.getKey(), entry.getValue().toByteArray()); + } + return result; + } + } + + static class SourceFile extends SimpleJavaFileObject { + private CharSequence sourceCode; + public SourceFile(String name, CharSequence sourceCode) { + super(URI.create("memo:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.sourceCode = sourceCode; + } + @Override + public CharSequence getCharContent(boolean ignore) { + return this.sourceCode; + } + } + + public Map compile() { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + DiagnosticCollector ds = new DiagnosticCollector<>(); + Collection sourceFiles = sources; + + try (FileManager fileManager = new FileManager(compiler.getStandardFileManager(ds, null, null))) { + JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, sourceFiles); + if (task.call()) { + return fileManager.getCompiledClasses(); + } else { + for (Diagnostic d : ds.getDiagnostics()) { + System.out.format("Line: %d, %s in %s", d.getLineNumber(), d.getMessage(null), d.getSource().getName()); + } + throw new InternalError("compilation failure"); + } + } catch (IOException e) { + throw new InternalError(e); + } + } + + List sources; + + static final String imports = """ + import java.lang.*; + import java.util.*; + """; + + static final String testClassBody = """ + // Some comments + static long x; + static final long y; + static { + y = System.currentTimeMillis(); + } + /* More comments */ + @Deprecated + String func() { return "String " + this + y; } + public static void main(String args[]) { + try { + x = Long.parseLong(args[0]); + } catch (Throwable t) { + t.printStackTrace(); + } + doit(() -> { + System.out.println("Hello Lambda"); + Thread.dumpStack(); + }); + } + static List list = List.of("1", "2"); + class InnerClass1 { + static final long yy = y; + } + static void doit(Runnable r) { + for (var x : list) { + r.run(); + } + } + static String patternMatch(String arg, Object o) { + if (o instanceof String s) { + return "1234"; + } + final String b = "B"; + return switch (arg) { + case "A" -> "a"; + case b -> "b"; + default -> "c"; + }; + } + public sealed class SealedInnerClass {} + public final class Foo extends SealedInnerClass {} + enum Expression { + ADDITION, + SUBTRACTION, + MULTIPLICATION, + DIVISION + } + public record Point(int x, int y) { + public Point(int x) { + this(x, 0); + } + } + """; + + String sanitySource = """ + public class Sanity implements java.util.concurrent.Callable { + public String call() { + return "this is a test"; + } + } + """; + + void setup(int count) { + sources = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + String source = imports + "public class Test" + i + " {" + testClassBody + "}"; + sources.add(new SourceFile("Test" + i, source)); + } + + sources.add(new SourceFile("Sanity", sanitySource)); + } + + @SuppressWarnings("unchecked") + static void validate(byte[] sanityClassFile) throws Throwable { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Class cls = lookup.defineClass(sanityClassFile); + Callable obj = (Callable)cls.getDeclaredConstructor().newInstance(); + String s = obj.call(); + if (!s.equals("this is a test")) { + throw new RuntimeException("Expected \"this is a test\", but got \"" + s + "\""); + } + } + + public static void main(String args[]) throws Throwable { + long started = System.currentTimeMillis(); + JavacBenchApp bench = new JavacBenchApp(); + + int count = 0; + if (args.length > 0) { + count = Integer.parseInt(args[0]); + if (count >= 0) { + bench.setup(count); + Map allClasses = bench.compile(); + validate(allClasses.get("Sanity")); + } + } + if (System.getProperty("JavacBenchApp.silent") == null) { + // Set this property when running with "perf stat", etc + long elapsed = System.currentTimeMillis() - started; + System.out.println("Generated source code for " + bench.sources.size() + " classes and compiled them in " + elapsed + " ms"); + } + } +} + diff --git a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java index bc9a0c5cabcc0..0d136cadef717 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java +++ b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java @@ -114,6 +114,13 @@ static void joinThreads(Thread[] threads) { throw new Error("Unexpected " + e); } } + static Thread expOwnerThread() { + return Thread.currentThread().isVirtual() ? null : Thread.currentThread(); + } + + static int expEntryCount() { + return Thread.currentThread().isVirtual() ? 0 : 1; + } /* Scenario #0: * - owning: 0 @@ -127,14 +134,18 @@ static void test0(boolean isVirtual) { setTestedMonitor(lockCheck); Thread[] wThreads = startWaitingThreads(isVirtual); + final int expWaitingCount = isVirtual ? 0 : NUMBER_OF_WAITING_THREADS; + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 0 // count of threads waiting to enter: 0 // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS check(lockCheck, null, 0, // no owner thread 0, // count of threads waiting to enter: 0 - NUMBER_OF_WAITING_THREADS); + expWaitingCount); synchronized (lockCheck) { lockCheck.notifyAll(); @@ -158,20 +169,30 @@ static void test1(boolean isVirtual) { Thread[] eThreads = null; synchronized (lockCheck) { + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values for the virtual thread case. + int expEnteringCount = isVirtual ? 0 : NUMBER_OF_ENTERING_THREADS; + + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: 0 // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: 0 - check(lockCheck, Thread.currentThread(), 1, 0, 0); + check(lockCheck, expOwnerThread(), expEntryCount(), 0, 0); eThreads = startEnteringThreads(isVirtual); + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: 0 - check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERING_THREADS, + check(lockCheck, expOwnerThread(), expEntryCount(), + expEnteringCount, 0 /* count of threads waiting to be notified: 0 */); } @@ -195,15 +216,23 @@ static void test2(boolean isVirtual) throws Error { Thread[] eThreads = null; synchronized (lockCheck) { + // Virtual threads are not supported by the GetObjectMonitorUsage. + // Correct the expected values for the virtual thread case. + int expEnteringCount = isVirtual ? 0 : NUMBER_OF_ENTERING_THREADS; + int expWaitingCount = isVirtual ? 0 : NUMBER_OF_WAITING_THREADS; + eThreads = startEnteringThreads(isVirtual); + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERING_THREADS, - NUMBER_OF_WAITING_THREADS); + check(lockCheck, expOwnerThread(), expEntryCount(), + expEnteringCount, + expWaitingCount); lockCheck.notifyAll(); } @@ -234,35 +263,51 @@ static void test3(boolean isVirtual) throws Error { Thread[] eThreads = null; synchronized (lockCheck) { + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values for the virtual thread case. + int expEnteringCount = isVirtual ? 0 : NUMBER_OF_ENTERING_THREADS; + int expWaitingCount = isVirtual ? 0 : NUMBER_OF_WAITING_THREADS; + + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: 0 // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - check(lockCheck, Thread.currentThread(), 1, + check(lockCheck, expOwnerThread(), expEntryCount(), 0, // number of threads waiting to enter or re-enter - NUMBER_OF_WAITING_THREADS); + expWaitingCount); eThreads = startEnteringThreads(isVirtual); + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERING_THREADS, - NUMBER_OF_WAITING_THREADS); + check(lockCheck, expOwnerThread(), expEntryCount(), + expEnteringCount, + expWaitingCount); for (int i = 0; i < NUMBER_OF_WAITING_THREADS; i++) { + expEnteringCount = isVirtual ? 0 : NUMBER_OF_ENTERING_THREADS + i + 1; + expWaitingCount = isVirtual ? 0 : NUMBER_OF_WAITING_THREADS - i - 1; lockCheck.notify(); // notify waiting threads one by one // now the notified WaitingTask has to be blocked on the lockCheck re-enter + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS // count of threads waiting to re-enter: i + 1 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - i - 1 - check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERING_THREADS + i + 1, - NUMBER_OF_WAITING_THREADS - i - 1); + check(lockCheck, expOwnerThread(), expEntryCount(), + expEnteringCount, + expWaitingCount); } } joinThreads(wThreads); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/entryCount/entrycount002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/entryCount/entrycount002.java index 7736eae1d2b42..e5e8f4e8d80f2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/entryCount/entrycount002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/entryCount/entrycount002.java @@ -197,8 +197,11 @@ private void execTest() { display("Checking entryCount for iteration : " + i); try { + // The lockRef.entryCount() is expected to return 0 if the owner thread is virtual. + int expEntryCount = mainThread.isVirtual() ? 0 : i; int entryCount = lockRef.entryCount(); - if (entryCount != i) { + + if (entryCount != expEntryCount) { exitCode = Consts.TEST_FAILED; complain("entry count method returned unexpected value : " + entryCount + "\n\t expected one : " + i); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/owningThread/owningthread002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/owningThread/owningthread002.java index 89d1b7033105b..83e0bbb8c0518 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/owningThread/owningthread002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/owningThread/owningthread002.java @@ -200,6 +200,15 @@ private void execTest() { try { ThreadReference thread = lockRef.owningThread(); + // The lockRef.owningThread() is expected to return null if tested threads are virtual. + if (eventThread.isVirtual()) { + if (thread == null) { + display("expected null is returned` by owningThread method on virtual thread: " + eventThread.name()); + } else { + complain("owningThread returned ThreadReference of virtual thread instead of null: " + thread.name()); + } + continue; + } if (thread.name().indexOf(owningthread002a.threadNamePrefix) < 0) { exitCode = Consts.TEST_FAILED; complain("owningThread returned ThreadReference with unexpected name: " + thread.name()); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads002.java index 356f78876aae6..74bc41a34eb6d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads002.java @@ -122,6 +122,9 @@ private static void execTest() { if (thread.name().indexOf(waitingthreads002a.threadNamePrefix) >= 0 && thread.status() == ThreadReference.THREAD_STATUS_MONITOR ) { waitingCount++; + // Virtual threads are not present in result returned by objRef.waitingThreads(). + if (!thread.isVirtual()) { + } } } } @@ -159,7 +162,9 @@ private static void execTest() { objRef = (ObjectReference) debuggeeClass.getValue(debuggeeClass.fieldByName(fieldName)); try { List waitingThreads = objRef.waitingThreads(); - if (waitingThreads.size() != waitingthreads002a.threadCount) { + final boolean vthreadMode = "Virtual".equals(System.getProperty("test.thread.factory")); + final int expWaitingCount = vthreadMode ? 0 : waitingthreads002a.threadCount; + if (waitingThreads.size() != expWaitingCount) { exitStatus = Consts.TEST_FAILED; complain("waitingThreads method returned list with unexpected size for " + fieldName + "\n\t expected value : " + waitingthreads002a.threadCount + "; got one : " + waitingThreads.size()); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java index 1ae3bf79e1c30..c3c3cb31ebd27 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java @@ -61,8 +61,16 @@ public static int run(String argv[], PrintStream out) { syncObject[i] = new Object(); runn[i] = new objmonusage001a(mainThread, i, syncObject[i]); } + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values if the test is executed with + // JTREG_TEST_THREAD_FACTORY=Virtual. + Thread expOwner = mainThread.isVirtual() ? null : mainThread; + int expEntryCount = mainThread.isVirtual() ? 0 : 1; for (int i = 0; i < NUMBER_OF_THREADS; i++) { + Thread expNotifyWaiter = runn[i].isVirtual() ? null : runn[i]; + int expNotifyWaitingCount = runn[i].isVirtual() ? 0 : 1; + synchronized (syncObject[i]) { runn[i].start(); try { @@ -92,8 +100,8 @@ public static int run(String argv[], PrintStream out) { // This is a stable verification point because the worker thread is in wait() // and is not notified and the main thread is doing the verification. // - check(NUMBER_OF_THREADS + i, syncObject[i], mainThread, 1, - null, 0, runn[i], 1); + check(NUMBER_OF_THREADS + i, syncObject[i], expOwner, expEntryCount, + null, 0, expNotifyWaiter, expNotifyWaitingCount); } // Check #3: @@ -117,7 +125,7 @@ public static int run(String argv[], PrintStream out) { // and is not notified and the main thread is doing the verification. // check((NUMBER_OF_THREADS * 2) + i, syncObject[i], null, 0, - null, 0, runn[i], 1); + null, 0, expNotifyWaiter, expNotifyWaitingCount); } for (int i = 0; i < NUMBER_OF_THREADS; i++) { @@ -147,6 +155,14 @@ public objmonusage001a(Thread mt, int i, Object s) { } public void run() { + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values if the test is executed with + // JTREG_TEST_THREAD_FACTORY=Virtual. + Thread expOwner = this.isVirtual() ? null : this; + Thread expNotifyWaiter = mainThread.isVirtual() ? null : mainThread; + int expEntryCount = this.isVirtual() ? 0 : 1; + int expNotifyWaitingCount = mainThread.isVirtual() ? 0 : 1; + synchronized (syncObject) { // Check #1: // - owner == this_thread: @@ -166,8 +182,8 @@ public void run() { // This is a stable verification point because the main thread is in wait() // and is not notified and this worker thread is doing the verification. // - objmonusage001.check(index, syncObject, this, 1, - null, 0, mainThread, 1); + objmonusage001.check(index, syncObject, expOwner, expEntryCount, + null, 0, expNotifyWaiter, expNotifyWaitingCount); syncObject.notify(); try { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java index 37addef82d6f4..8d79a6011f581 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -60,11 +60,23 @@ public static int run(String args[], PrintStream out) { Thread currThread = Thread.currentThread(); ContendThread thr[] = new ContendThread[NUMBER_OF_THREADS]; synchronized (lockCheck) { + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values if the test is executed with + // JTREG_TEST_THREAD_FACTORY=Virtual. + Thread expOwner = currThread.isVirtual() ? null : currThread; + int expEntryCount = currThread.isVirtual() ? 0 : 2; + synchronized (lockCheck) { - check(lockCheck, currThread, 2, 0); + check(lockCheck, expOwner, expEntryCount, 0); } + expEntryCount = currThread.isVirtual() ? 0 : 1; + int expWaiterCount = 0; + for (int i = 0; i < NUMBER_OF_THREADS; i++) { thr[i] = new ContendThread(); + if (!thr[i].isVirtual()) { + expWaiterCount++; + } synchronized (lockStart) { thr[i].start(); try { @@ -74,7 +86,7 @@ public static int run(String args[], PrintStream out) { throw new Error("Unexpected " + e); } } - check(lockCheck, currThread, 1, i + 1); + check(lockCheck, expOwner, expEntryCount, expWaiterCount); } } diff --git a/test/jdk/com/sun/security/ec/ECOperationsFuzzTest.java b/test/jdk/com/sun/security/ec/ECOperationsFuzzTest.java new file mode 100644 index 0000000000000..31d83815ed894 --- /dev/null +++ b/test/jdk/com/sun/security/ec/ECOperationsFuzzTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2024, Intel Corporation. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Random; +import java.math.BigInteger; +import java.lang.reflect.Field; +import java.security.spec.ECParameterSpec; +import sun.security.ec.ECOperations; +import sun.security.util.ECUtil; +import sun.security.util.NamedCurve; +import sun.security.util.CurveDB; +import sun.security.ec.point.*; +import java.security.spec.ECPoint; +import sun.security.util.KnownOIDs; +import sun.security.util.math.IntegerMontgomeryFieldModuloP; +import sun.security.util.math.intpoly.*; + +/* + * @test + * @key randomness + * @modules java.base/sun.security.ec java.base/sun.security.ec.point + * java.base/sun.security.util java.base/sun.security.util.math + * java.base/sun.security.util.math.intpoly + * @run main/othervm/timeout=1200 --add-opens + * java.base/sun.security.ec=ALL-UNNAMED -XX:+UnlockDiagnosticVMOptions + * -XX:-UseIntPolyIntrinsics ECOperationsFuzzTest + * @summary Unit test ECOperationsFuzzTest. + */ + +/* + * @test + * @key randomness + * @modules java.base/sun.security.ec java.base/sun.security.ec.point + * java.base/sun.security.util java.base/sun.security.util.math + * java.base/sun.security.util.math.intpoly + * @run main/othervm/timeout=1200 --add-opens + * java.base/sun.security.ec=ALL-UNNAMED -XX:+UnlockDiagnosticVMOptions + * -XX:+UseIntPolyIntrinsics ECOperationsFuzzTest + * @summary Unit test ECOperationsFuzzTest. + */ + +// This test case is NOT entirely deterministic, it uses a random seed for +// pseudo-random number generator. If a failure occurs, hardcode the seed to +// make the test case deterministic +public class ECOperationsFuzzTest { + public static void main(String[] args) throws Exception { + // Note: it might be useful to increase this number during development + final int repeat = 10000; + test(repeat); + System.out.println("Fuzz Success"); + } + + private static void check(MutablePoint reference, MutablePoint testValue, + long seed, int iter) { + AffinePoint affineRef = reference.asAffine(); + AffinePoint affine = testValue.asAffine(); + if (!affineRef.equals(affine)) { + throw new RuntimeException( + "Found error with seed " + seed + "at iteration " + iter); + } + } + + public static void test(int repeat) throws Exception { + Random rnd = new Random(); + long seed = rnd.nextLong(); + rnd.setSeed(seed); + + int keySize = 256; + ECParameterSpec params = ECUtil.getECParameterSpec(keySize); + NamedCurve curve = CurveDB.lookup(KnownOIDs.secp256r1.value()); + ECPoint generator = curve.getGenerator(); + BigInteger b = curve.getCurve().getB(); + if (params == null || generator == null) { + throw new RuntimeException( + "No EC parameters available for key size " + keySize + " bits"); + } + + ECOperations ops = ECOperations.forParameters(params).get(); + ECOperations opsReference = new ECOperations( + IntegerPolynomialP256.ONE.getElement(b), P256OrderField.ONE); + + boolean instanceTest1 = ops + .getField() instanceof IntegerMontgomeryFieldModuloP; + boolean instanceTest2 = opsReference + .getField() instanceof IntegerMontgomeryFieldModuloP; + if (instanceTest1 == false || instanceTest2 == true) { + throw new RuntimeException("Bad Initialization: [" + + instanceTest1 + "," + instanceTest2 + "]"); + } + + byte[] multiple = new byte[keySize / 8]; + rnd.nextBytes(multiple); + multiple[keySize/8 - 1] &= 0x7f; // from opsReference.seedToScalar(multiple); + + MutablePoint referencePoint = opsReference.multiply(generator, multiple); + MutablePoint point = ops.multiply(generator, multiple); + check(referencePoint, point, seed, -1); + + AffinePoint refAffineGenerator = AffinePoint.fromECPoint(generator, + referencePoint.getField()); + AffinePoint montAffineGenerator = AffinePoint.fromECPoint(generator, + point.getField()); + + MutablePoint refProjGenerator = new ProjectivePoint.Mutable( + refAffineGenerator.getX(false).mutable(), + refAffineGenerator.getY(false).mutable(), + referencePoint.getField().get1().mutable()); + + MutablePoint projGenerator = new ProjectivePoint.Mutable( + montAffineGenerator.getX(false).mutable(), + montAffineGenerator.getY(false).mutable(), + point.getField().get1().mutable()); + + for (int i = 0; i < repeat; i++) { + rnd.nextBytes(multiple); + multiple[keySize/8 - 1] &= 0x7f; // opsReference.seedToScalar(multiple); + + MutablePoint nextReferencePoint = opsReference + .multiply(referencePoint.asAffine(), multiple); + MutablePoint nextPoint = ops.multiply(point.asAffine().toECPoint(), + multiple); + check(nextReferencePoint, nextPoint, seed, i); + + if (rnd.nextBoolean()) { + opsReference.setSum(nextReferencePoint, referencePoint); + ops.setSum(nextPoint, point); + check(nextReferencePoint, nextPoint, seed, i); + } + + if (rnd.nextBoolean()) { + opsReference.setSum(nextReferencePoint, refProjGenerator); + ops.setSum(nextPoint, projGenerator); + check(nextReferencePoint, nextPoint, seed, i); + } + + if (rnd.nextInt(100) < 10) { // 10% Reset point to generator, test + // generator multiplier + referencePoint = opsReference.multiply(generator, multiple); + point = ops.multiply(generator, multiple); + check(referencePoint, point, seed, i); + } else { + referencePoint = nextReferencePoint; + point = nextPoint; + } + } + } + +} + +// make test TEST="test/jdk/com/sun/security/ec/ECOperationsFuzzTest.java" \ No newline at end of file diff --git a/test/jdk/com/sun/security/ec/ECOperationsKATTest.java b/test/jdk/com/sun/security/ec/ECOperationsKATTest.java new file mode 100644 index 0000000000000..3c98b5f63cdbf --- /dev/null +++ b/test/jdk/com/sun/security/ec/ECOperationsKATTest.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2024, Intel Corporation. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Random; +import java.util.List; +import java.util.LinkedList; +import java.math.BigInteger; +import java.lang.reflect.Field; +import java.security.spec.ECParameterSpec; +import sun.security.ec.ECOperations; +import sun.security.util.ECUtil; +import sun.security.util.NamedCurve; +import sun.security.util.CurveDB; +import sun.security.ec.point.*; +import java.security.spec.ECPoint; +import sun.security.util.KnownOIDs; +import sun.security.util.math.IntegerMontgomeryFieldModuloP; +import sun.security.util.math.intpoly.*; + +/* + * @test + * @modules java.base/sun.security.ec java.base/sun.security.ec.point + * java.base/sun.security.util java.base/sun.security.util.math + * java.base/sun.security.util.math.intpoly + * @run main/othervm --add-opens java.base/sun.security.ec=ALL-UNNAMED + * ECOperationsKATTest + * @summary Unit test ECOperationsKATTest. + */ + +/* + * @test + * @modules java.base/sun.security.ec java.base/sun.security.ec.point + * java.base/sun.security.util java.base/sun.security.util.math + * java.base/sun.security.util.math.intpoly + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xcomp + * -XX:-TieredCompilation --add-opens java.base/sun.security.ec=ALL-UNNAMED + * -XX:+UnlockDiagnosticVMOptions ECOperationsKATTest + * @summary Unit test ECOperationsKATTest. + */ + + public class ECOperationsKATTest { + final private static java.util.HexFormat hex = java.util.HexFormat.of(); + + public static void main(String args[]) throws Exception { + int testsPassed = 0; + int testNumber = 0; + + for (TestData test : testList) { + System.out.println("*** Test " + ++testNumber + ": " + test.testName); + if (runSingleTest(test)) { + testsPassed++; + } + } + System.out.println(); + + if (testsPassed != testNumber) { + throw new RuntimeException( + "One or more tests failed. Check output for details"); + } + } + + private static boolean check(MutablePoint testValue, ECPoint reference) { + AffinePoint affine = testValue.asAffine(); + BigInteger x = affine.getX().asBigInteger(); + BigInteger y = affine.getY().asBigInteger(); + BigInteger refX = reference.getAffineX(); + BigInteger refY = reference.getAffineY(); + + if (!refX.equals(x) || !refY.equals(y)) { + System.out.println("ERROR - Output Mismatch!"); + System.out.println("Expected: X: " + refX.toString(16) + " Y: " + + refY.toString(16)); + System.out.println( + "Result: X: " + x.toString(16) + " Y: " + y.toString(16)); + return false; + } + return true; + } + + private static class TestData { + public TestData(String name, String keyStr, String xStr1, String yStr1, + String xStr2, String yStr2) { + testName = name; + // multiplier = (new BigInteger(keyStr, 16)).toByteArray(); + multiplier = hex.parseHex(keyStr); + sun.security.util.ArrayUtil.reverse(multiplier); + reference1 = new ECPoint(new BigInteger(xStr1, 16), + new BigInteger(yStr1, 16)); + reference2 = new ECPoint(new BigInteger(xStr2, 16), + new BigInteger(yStr2, 16)); + } + + String testName; + byte[] multiplier; + ECPoint reference1; // For generator multiplier test + ECPoint reference2; // For non-generator multiplier test + } + + public static final List testList = new LinkedList() {{ + // (x1,y1) = mult*generator + // (x2,y2) = mult*mult*generator + add(new TestData("Test Vector #1", + "0000000000000000000000000000000000000000000000000000000000000012", // mult + "1057E0AB5780F470DEFC9378D1C7C87437BB4C6F9EA55C63D936266DBD781FDA", // x1 + "F6F1645A15CBE5DC9FA9B7DFD96EE5A7DCC11B5C5EF4F1F78D83B3393C6A45A2", // y1 + "4954047A366A91E3FD94E574DB6F2B04F3A8465883DBC55A816EA563BF54A324", // x2 + "B5A54786FD9EA48C9FC38A0557B0C4D54F285908A7291B630D06BEE970F530D3") // y2 + ); + add(new TestData("Test Vector #2", + "1200000000000000000000000000000000000000000000000000000000000000", // mult + "DF684E6D0D57AF8B89DA11E8F7436C3D360F531D62BDCE42C5A8B72D73D5C717", // x + "9D3576BD03C09B8F416EE9C27D70AD4A425119271ACF549312CA48758F4E1FEC", // y + "57C8257EEAABF5446DCFACB99DEE104367B6C9950C76797C372EB177D5FA23B3", // x + "1CD3E8A34521C1C8E574EB4B99343CAA57E00725D8618F0231C7C79AA6837725") // y + ); + add(new TestData("Test Vector #3", + "0000000000000000000000000000000120000000000000000000000000000012", // mult + "A69DFD47B24485E5F523BDA5FBACF03F5A7C3D22E0C2BC6705594B7B051A06D0", // x + "ECF19629416BE5C9AF1E30988F3AA8B803809CF4D12944EB49C5E9892723798A", // y + "1E28559F5B681C308632EE11A007B9891B3FD592C982C4926153795794295E58", // x + "3C373046C27BB34609A43C91DF6D4B9AB9EB08F3B69A8F8FAE944211D8297F30") // y + ); + add(new TestData("Test Vector #4", + "0000000000000000000000000000000000000000000000000000000000000001", // mult + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", // x + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", // y + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", // x + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5") // y + ); + add(new TestData("Test Vector #5", + "EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", // mult + "66B71D0BD47344197CCFB0C9578EAF0ADB609E05BB4E8F87D56BD34F24EE7C47", // x + "14A0ECB7F708C02B2BAE238D2C4607BB9D04FCE64E10A428C911D6FA25B2F0FD", // y + "D25AAFD0FCC5B5E95C84C0702C138BC4D7FEB4E5F9C2DFB4301E313507EFDF44", // x + "F3F04EBC7D308511B0392BB7171CF92688D6484A95A8100EDFC933613A359133") // y + ); + add(new TestData("Test Vector #6", + "1111111111111111111111111111111111111111111111111111111111111111", // mult + "0217E617F0B6443928278F96999E69A23A4F2C152BDF6D6CDF66E5B80282D4ED", // x + "194A7DEBCB97712D2DDA3CA85AA8765A56F45FC758599652F2897C65306E5794", // y + "A83A07D6AE918359DEBCC385DA1E416EB83417435079CA8DB06005E107C309A0", // x + "5AACDF816850C33EB3E54F3D0DD759B97B5E7065B2060016F73735E4A6AADE23") // y + ); + }}; + + private static boolean runSingleTest(TestData testData) { + int keySize = 256; + ECParameterSpec params = ECUtil.getECParameterSpec(keySize); + NamedCurve curve = CurveDB.lookup(KnownOIDs.secp256r1.value()); + ECPoint generator = curve.getGenerator(); + BigInteger b = curve.getCurve().getB(); + if (params == null || generator == null) { + throw new RuntimeException( + "No EC parameters available for key size " + keySize + " bits"); + } + + ECOperations ops = ECOperations.forParameters(params).get(); + ECOperations opsReference = new ECOperations( + IntegerPolynomialP256.ONE.getElement(b), P256OrderField.ONE); + + boolean instanceTest1 = ops + .getField() instanceof IntegerMontgomeryFieldModuloP; + boolean instanceTest2 = opsReference + .getField() instanceof IntegerMontgomeryFieldModuloP; + if (instanceTest1 == false || instanceTest2 == true) { + throw new RuntimeException("Bad Initialization: [" + instanceTest1 + "," + + instanceTest2 + "]"); + } + + MutablePoint nextPoint = ops.multiply(generator, testData.multiplier); + MutablePoint nextReferencePoint = opsReference.multiply(generator, + testData.multiplier); + if (!check(nextReferencePoint, testData.reference1) + || !check(nextPoint, testData.reference1)) { + return false; + } + + nextPoint = ops.multiply(nextPoint.asAffine(), testData.multiplier); + nextReferencePoint = opsReference.multiply(nextReferencePoint.asAffine(), + testData.multiplier); + if (!check(nextReferencePoint, testData.reference2) + || !check(nextPoint, testData.reference2)) { + return false; + } + + return true; + } +} + +//make test TEST="test/jdk/com/sun/security/ec/ECOperationsKATTest.java" + +/* + * KAT generator using OpenSSL for reference vectors + * g++ ecpoint.cpp -g -lcrypto -Wno-deprecated-declarations && ./a.out + * (Some OpenSSL EC operations are marked internal i.e. deprecated) + * + +#include +#include + +void check(int rc, const char* locator) { + if (rc != 1) { + printf("Failed at %s\n", locator); + exit(55); + } +} + +int main(){ + BN_CTX* ctx = BN_CTX_new(); + BIGNUM* k = BN_CTX_get(ctx); + BIGNUM* x1 = BN_CTX_get(ctx); + BIGNUM* y1 = BN_CTX_get(ctx); + BIGNUM* x2 = BN_CTX_get(ctx); + BIGNUM* y2 = BN_CTX_get(ctx); + EC_GROUP *ec_group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + EC_POINT* pubkey = EC_POINT_new(ec_group); + EC_POINT* pubkey2 = EC_POINT_new(ec_group); + int rc; + + rc = BN_hex2bn(&k, "1111111111111111111111111111111111111111111111111111111111111111"); //check(rc, "set raw key"); + rc = EC_POINT_mul(ec_group, pubkey, k, NULL, NULL, ctx); check(rc, "mult public key"); + rc = EC_POINT_get_affine_coordinates(ec_group, pubkey, x1, y1, ctx); check(rc, "get affine coordinates"); + rc = EC_POINT_mul(ec_group, pubkey2, NULL, pubkey, k, ctx); check(rc, "mult public key"); + rc = EC_POINT_get_affine_coordinates(ec_group, pubkey2, x2, y2, ctx); check(rc, "get affine coordinates"); + printf("k: %s\n", BN_bn2hex(k)); + printf("x: %s\ny: %s\n", BN_bn2hex(x1), BN_bn2hex(y1)); + printf("x: %s\ny: %s\n", BN_bn2hex(x2), BN_bn2hex(y2)); + + BN_CTX_free(ctx); + return 0; +} + */ \ No newline at end of file diff --git a/test/jdk/com/sun/security/util/math/intpoly/IntegerPolynomialTest.java b/test/jdk/com/sun/security/util/math/intpoly/IntegerPolynomialTest.java new file mode 100644 index 0000000000000..237c0408c580c --- /dev/null +++ b/test/jdk/com/sun/security/util/math/intpoly/IntegerPolynomialTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2024, Intel Corporation. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Random; +import java.math.BigInteger; +import java.util.Arrays; +import sun.security.util.math.*; +import sun.security.util.math.intpoly.*; + +/* + * @test + * @key randomness + * @modules java.base/sun.security.util java.base/sun.security.util.math + * java.base/sun.security.util.math.intpoly + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseIntPolyIntrinsics + * IntegerPolynomialTest + * @summary Unit test + * IntegerPolynomial.MutableIntegerModuloP.conditionalAssign(). + */ + +/* + * @test + * @key randomness + * @modules java.base/sun.security.util java.base/sun.security.util.math + * java.base/sun.security.util.math.intpoly + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xcomp + * -XX:-TieredCompilation -XX:+UseIntPolyIntrinsics IntegerPolynomialTest + * @summary Unit test + * IntegerPolynomial.MutableIntegerModuloP.conditionalAssign(). + */ + +// This test case is NOT entirely deterministic, it uses a random seed for +// pseudo-random number generator. If a failure occurs, hardcode the seed to +// make the test case deterministic +public class IntegerPolynomialTest { + public static void main(String[] args) throws Exception { + Random rnd = new Random(); + long seed = rnd.nextLong(); + rnd.setSeed(seed); + + IntegerPolynomial testFields[] = new IntegerPolynomial[] { + IntegerPolynomial1305.ONE, IntegerPolynomial25519.ONE, + IntegerPolynomial448.ONE, IntegerPolynomialP256.ONE, + MontgomeryIntegerPolynomialP256.ONE, IntegerPolynomialP384.ONE, + IntegerPolynomialP521.ONE, + new IntegerPolynomialModBinP.Curve25519OrderField(), + new IntegerPolynomialModBinP.Curve448OrderField(), + P256OrderField.ONE, P384OrderField.ONE, P521OrderField.ONE, + Curve25519OrderField.ONE, Curve448OrderField.ONE }; + + for (IntegerPolynomial field : testFields) { + ImmutableIntegerModuloP aRef = field + .getElement(new BigInteger(32 * 64, rnd)); + MutableIntegerModuloP a = aRef.mutable(); + ImmutableIntegerModuloP bRef = field + .getElement(new BigInteger(32 * 64, rnd)); + MutableIntegerModuloP b = bRef.mutable(); + + a.conditionalSet(b, 0); // Don't assign + if (Arrays.equals(a.getLimbs(), b.getLimbs())) { + throw new RuntimeException( + "[SEED " + seed + "]: Incorrect assign for " + field); + } + a.conditionalSet(b, 1); // Assign + if (!Arrays.equals(a.getLimbs(), b.getLimbs())) { + throw new RuntimeException( + "[SEED " + seed + "]: Incorrect assign for " + field); + } + } + System.out.println("Test Success"); + } +} + +//make test TEST="test/jdk/com/sun/security/util/math/intpoly/IntegerPolynomialTest.java" \ No newline at end of file diff --git a/test/jdk/com/sun/security/util/math/intpoly/MontgomeryPolynomialFuzzTest.java b/test/jdk/com/sun/security/util/math/intpoly/MontgomeryPolynomialFuzzTest.java new file mode 100644 index 0000000000000..da5aa33d8310d --- /dev/null +++ b/test/jdk/com/sun/security/util/math/intpoly/MontgomeryPolynomialFuzzTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2024, Intel Corporation. All rights reserved. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Random; +import sun.security.util.math.IntegerMontgomeryFieldModuloP; +import sun.security.util.math.ImmutableIntegerModuloP; +import java.math.BigInteger; +import sun.security.util.math.intpoly.*; + +/* + * @test + * @key randomness + * @modules java.base/sun.security.util java.base/sun.security.util.math + * java.base/sun.security.util.math.intpoly + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseIntPolyIntrinsics + * MontgomeryPolynomialFuzzTest + * @summary Unit test MontgomeryPolynomialFuzzTest. + */ + +/* + * @test + * @key randomness + * @modules java.base/sun.security.util java.base/sun.security.util.math + * java.base/sun.security.util.math.intpoly + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UseIntPolyIntrinsics + * MontgomeryPolynomialFuzzTest + * @summary Unit test MontgomeryPolynomialFuzzTest. + */ + +// This test case is NOT entirely deterministic, it uses a random seed for pseudo-random number generator +// If a failure occurs, hardcode the seed to make the test case deterministic +public class MontgomeryPolynomialFuzzTest { + public static void main(String[] args) throws Exception { + // Note: it might be useful to increase this number during development + final int repeat = 1000000; + for (int i = 0; i < repeat; i++) { + run(); + } + System.out.println("Fuzz Success"); + } + + private static void check(BigInteger reference, + ImmutableIntegerModuloP testValue, long seed) { + if (!reference.equals(testValue.asBigInteger())) { + throw new RuntimeException("SEED: " + seed); + } + } + + public static void run() throws Exception { + Random rnd = new Random(); + long seed = rnd.nextLong(); + rnd.setSeed(seed); + + IntegerMontgomeryFieldModuloP montField = MontgomeryIntegerPolynomialP256.ONE; + BigInteger P = MontgomeryIntegerPolynomialP256.ONE.MODULUS; + BigInteger r = BigInteger.ONE.shiftLeft(260).mod(P); + BigInteger rInv = r.modInverse(P); + BigInteger aRef = (new BigInteger(P.bitLength(), rnd)).mod(P); + + // Test conversion to montgomery domain + ImmutableIntegerModuloP a = montField.getElement(aRef); + aRef = aRef.multiply(r).mod(P); + check(aRef, a, seed); + + if (rnd.nextBoolean()) { + aRef = aRef.multiply(aRef).multiply(rInv).mod(P); + a = a.multiply(a); + check(aRef, a, seed); + } + + if (rnd.nextBoolean()) { + aRef = aRef.add(aRef).mod(P); + a = a.add(a); + check(aRef, a, seed); + } + } +} + +//make test TEST="test/jdk/com/sun/security/util/math/intpoly/MontgomeryPolynomialFuzzTest.java" \ No newline at end of file diff --git a/test/jdk/java/io/IO/IO.java b/test/jdk/java/io/IO/IO.java new file mode 100644 index 0000000000000..9b35fe1ab8104 --- /dev/null +++ b/test/jdk/java/io/IO/IO.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.stream.Stream; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jtreg.SkippedException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; + +/* + * @test + * @bug 8305457 + * @summary java.io.IO tests + * @library /test/lib + * @run junit IO + */ +public class IO { + + @Nested + @EnabledOnOs({OS.LINUX, OS.MAC}) + public class OSSpecificTests { + + private static Path expect; + + @BeforeAll + public static void prepareTTY() { + expect = Paths.get("/usr/bin/expect"); // os-specific path + if (!Files.exists(expect) || !Files.isExecutable(expect)) { + throw new SkippedException("'" + expect + "' not found"); + } + } + + /* + * Unlike printTest, which tests a _default_ console that is normally + * jdk.internal.org.jline.JdkConsoleProviderImpl, this test tests + * jdk.internal.io.JdkConsoleImpl. Those console implementations operate + * in different conditions and, thus, are tested separately. + * + * To test jdk.internal.io.JdkConsoleImpl one needs to ensure that both + * conditions are met: + * + * - a non-existent console provider is requested + * - isatty is true + * + * To achieve isatty, the test currently uses the EXPECT(1) Unix command, + * which does not work for Windows. Later, a library like pty4j or JPty + * might be used instead of EXPECT, to cover both Unix and Windows. + */ + @ParameterizedTest + @ValueSource(strings = {"println", "print"}) + public void outputTestInteractive(String mode) throws Exception { + var testSrc = System.getProperty("test.src", "."); + OutputAnalyzer output = ProcessTools.executeProcess( + expect.toString(), + Path.of(testSrc, "output.exp").toAbsolutePath().toString(), + System.getProperty("test.jdk") + "/bin/java", + "--enable-preview", + "-Djdk.console=gibberish", + Path.of(testSrc, "Output.java").toAbsolutePath().toString(), + mode); + assertEquals(0, output.getExitValue()); + assertTrue(output.getStderr().isEmpty()); + output.reportDiagnosticSummary(); + String out = output.getStdout(); + // The first half of the output is produced by Console, the second + // half is produced by IO: those halves must match. + // Executing Console and IO in the same VM (as opposed to + // consecutive VM runs, which are cleaner) to be able to compare string + // representation of objects. + assertFalse(out.isBlank()); + assertEquals(out.substring(0, out.length() / 2), + out.substring(out.length() / 2)); + } + + /* + * This tests simulates terminal interaction (isatty), to check that the + * prompt is output. + * + * To simulate a terminal, the test currently uses the EXPECT(1) Unix + * command, which does not work for Windows. Later, a library like pty4j + * or JPty might be used instead of EXPECT, to cover both Unix and Windows. + */ + @ParameterizedTest + @MethodSource("args") + public void inputTestInteractive(String console, String prompt) throws Exception { + var testSrc = System.getProperty("test.src", "."); + var command = new ArrayList(); + command.add(expect.toString()); + command.add(Path.of(testSrc, "input.exp").toAbsolutePath().toString()); + command.add(System.getProperty("test.jdk") + "/bin/java"); + command.add("--enable-preview"); + if (console != null) + command.add("-Djdk.console=" + console); + command.add(Path.of(testSrc, "Input.java").toAbsolutePath().toString()); + command.add(prompt == null ? "0" : "1"); + command.add(String.valueOf(prompt)); + OutputAnalyzer output = ProcessTools.executeProcess(command.toArray(new String[]{})); + output.reportDiagnosticSummary(); + assertEquals(0, output.getExitValue()); + } + + public static Stream args() { + // cross product: consoles x prompts + return Stream.of(null, "gibberish").flatMap(console -> Stream.of(null, "?", "%s") + .map(prompt -> new String[]{console, prompt}).map(Arguments::of)); + } + } + + @ParameterizedTest + @ValueSource(strings = {"println", "print"}) + public void printTest(String mode) throws Exception { + var file = Path.of(System.getProperty("test.src", "."), "Output.java") + .toAbsolutePath().toString(); + var pb = ProcessTools.createTestJavaProcessBuilder("--enable-preview", file, mode); + OutputAnalyzer output = ProcessTools.executeProcess(pb); + assertEquals(0, output.getExitValue()); + assertTrue(output.getStderr().isEmpty()); + output.reportDiagnosticSummary(); + String out = output.getStdout(); + // The first half of the output is produced by Console, the second + // half is produced by IO: those halves must match. + // Executing Console and IO in the same VM (as opposed to + // consecutive VM runs, which are cleaner) to be able to compare string + // representation of objects. + assertFalse(out.isBlank()); + assertEquals(out.substring(0, out.length() / 2), + out.substring(out.length() / 2)); + } + + + @ParameterizedTest + @ValueSource(strings = {"println", "print", "input"}) + public void nullConsole(String method) throws Exception { + var file = Path.of(System.getProperty("test.src", "."), "Methods.java") + .toAbsolutePath().toString(); + var pb = ProcessTools.createTestJavaProcessBuilder("-Djdk.console=gibberish", + "--enable-preview", file, method); + OutputAnalyzer output = ProcessTools.executeProcess(pb); + output.reportDiagnosticSummary(); + assertEquals(1, output.getExitValue()); + output.shouldContain("Exception in thread \"main\" java.io.IOError"); + } +} diff --git a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.cpp b/test/jdk/java/io/IO/Input.java similarity index 69% rename from src/hotspot/share/gc/g1/g1HeapRegionPrinter.cpp rename to test/jdk/java/io/IO/Input.java index 1c87b800601f9..1bc03c8bb8a54 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.cpp +++ b/test/jdk/java/io/IO/Input.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -19,20 +19,18 @@ * 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" +import java.io.IOException; + +import static java.io.IO.readln; -#include "gc/g1/g1HeapRegionPrinter.hpp" -#include "gc/g1/g1HeapRegionSet.hpp" +public class Input { -void G1HeapRegionPrinter::mark_reclaim(FreeRegionList* cleanup_list) { - if (is_active()) { - FreeRegionListIterator iter(cleanup_list); - while (iter.more_available()) { - HeapRegion* hr = iter.get_next(); - mark_reclaim(hr); + public static void main(String[] args) throws IOException { + if (args[0].equals("0")) + System.out.print(readln(null)); + else + System.out.print(readln(args[1])); } - } } diff --git a/test/jdk/java/io/IO/Methods.java b/test/jdk/java/io/IO/Methods.java new file mode 100644 index 0000000000000..c1700241b32d3 --- /dev/null +++ b/test/jdk/java/io/IO/Methods.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import static java.io.IO.*; + +public class Methods { + + public static void main(String[] args) { + switch (args[0]) { + case "println" -> println("hello"); + case "print" -> print("hello"); + case "input" -> readln("hello"); + default -> throw new IllegalArgumentException(args[0]); + } + } +} diff --git a/test/jdk/java/io/IO/Output.java b/test/jdk/java/io/IO/Output.java new file mode 100644 index 0000000000000..38d37fa9f41bc --- /dev/null +++ b/test/jdk/java/io/IO/Output.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import static java.io.IO.*; +import java.util.function.Consumer; + +public class Output { + + private static final Object[] OBJECTS = { + null, + false, + (byte) 1, + (short) 2, + 'a', + 3, + 4L, + 5f, + 6d, + new Object(), + "%s", // to test that print(ln) does not interpret its argument as a format string + new char[]{'a'}, + }; + + public static void main(String[] args) { + switch (args[0]) { + case "print" -> { + printObjects(obj -> System.console().format("%s", obj).flush()); + printObjects(obj -> print(obj)); + } + case "println" -> { + printObjects(obj -> System.console().format("%s%n", obj).flush()); + printObjects(obj -> println(obj)); + } + default -> throw new IllegalArgumentException(); + } + } + + private static void printObjects(Consumer printer) { + for (var obj : OBJECTS) { + printer.accept(obj); + } + } +} diff --git a/test/jdk/java/io/IO/input.exp b/test/jdk/java/io/IO/input.exp new file mode 100644 index 0000000000000..ba86b57b131ba --- /dev/null +++ b/test/jdk/java/io/IO/input.exp @@ -0,0 +1,36 @@ +# +# Copyright (c) 2024, 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. +# + +set prompt [lindex $argv $argc-1] +set stty_init "rows 24 cols 80" + +spawn {*}$argv +expect { + -exact "$prompt" { + send "hello\r" + } + timeout { + puts "timeout"; exit 1 + } +} +expect eof diff --git a/test/jdk/java/io/IO/output.exp b/test/jdk/java/io/IO/output.exp new file mode 100644 index 0000000000000..9044912cfaf55 --- /dev/null +++ b/test/jdk/java/io/IO/output.exp @@ -0,0 +1,32 @@ +# +# Copyright (c) 2024, 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. +# + +################################################################################ +# This script does not expect/verify anything and is only used to simulate tty # +################################################################################ + +# Use `noecho` below, otherwise, expect will output the expanded "spawn ..." +# command, which will interfere with asserting output from the java test + +spawn -noecho {*}$argv +expect eof diff --git a/test/jdk/java/io/Serializable/serialProxy/SerialProxyClassNotFound.java b/test/jdk/java/io/Serializable/serialProxy/SerialProxyClassNotFound.java new file mode 100644 index 0000000000000..f441c82c3f97d --- /dev/null +++ b/test/jdk/java/io/Serializable/serialProxy/SerialProxyClassNotFound.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.util.SerializationUtils; +import jdk.test.lib.hexdump.HexPrinter; +import jdk.test.lib.hexdump.ObjectStreamPrinter; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.util.Map; +import java.util.stream.Stream; + +/* + * @test + * @bug 8331224 + * @summary Test missing class throws CNFE before creating record or setting class fields + * @library /test/lib + * @run junit SerialProxyClassNotFound + */ + +/** + * Verify the correct exception (CNFE) is thrown when the class is not found during + * deserialization. Field values for objects should result in CNFE *before* creating the + * record or initializing the fields of a class. + * The issue is exposed by the use of serialization proxy classes; the proxies + * typically have types that are different from the original object type and + * result in ClassCastException. + */ +public class SerialProxyClassNotFound implements Serializable { + + private static Stream Cases() { + return Stream.of( + Arguments.of(new Record1(Map.of("aaa", new XX()))), // Map uses serial proxy + Arguments.of(new Class2(Map.of("bbb", new XX()))), // Map uses serial proxy + Arguments.of(new Record4(new Class3(new XX()))), // Class3 uses serial proxy + Arguments.of(new Class5(new Class3(new XX()))), // Class3 uses serial proxy + Arguments.of(new Class6(new Class3(new XX()))) // Class3 uses serial proxy + ); + } + @ParameterizedTest + @MethodSource("Cases") + void checkForCNFE(Object obj) throws ClassNotFoundException, IOException { + // A record with field containing a Map with an entry for a class that is not found + byte[] bytes = SerializationUtils.serialize(obj); + + // Scan bytes looking for "$XX"; replace all occurrences + boolean replaced = false; + for (int off = 0; off < bytes.length - 3; off++) { + if (bytes[off] == '$' && bytes[off + 1] == 'X' && bytes[off + 2] == 'X') { + // Modify bytes to change name of class to SerialProxyClassNotFound$YY + bytes[off + 1] = 'Y'; + bytes[off + 2] = 'Y'; + replaced = true; + } + } + if (!replaced) { + // Not found, Debug dump the bytes to locate the index of the XX class name + HexPrinter.simple() + .formatter(ObjectStreamPrinter.formatter()) + .dest(System.err) + .format(bytes); + fail("'$XX' of `SerialProxyClassNotFound$XX` not found in serialized bytes "); + } + + try { + Object o = SerializationUtils.deserialize(bytes); + System.out.println("Deserialized obj: " + o); + HexPrinter.simple() + .formatter(ObjectStreamPrinter.formatter()) + .dest(System.err) + .format(bytes); + fail("deserialize should have thrown ClassNotFoundException"); + } catch (ClassNotFoundException cnfe) { + assertEquals(cnfe.getMessage(), + "SerialProxyClassNotFound$YY", + "CNFE message incorrect"); + } catch (IOException ioe) { + HexPrinter.simple() + .formatter(ObjectStreamPrinter.formatter()) + .dest(System.err) + .format(bytes); + throw ioe; + } + } + + // A class with a readily identifiable name + static class XX implements Serializable { } + + // A record holding a Map holding a reference to a readily identifiable (but deleted) class + record Record1(Map arg) implements Serializable {}; + + // Class holding a Map holding a reference to a (deleted) class + static class Class2 implements Serializable { + Map arg; + Class2(Map arg) { + this.arg = arg; + } + public String toString() { + return "Class2[arg=" + arg + "]"; + } + } + + // Class3 a holder of a reference to a class that will be "deleted" + static class Class3 implements Serializable { + XX arg; + Class3(XX arg) { + this.arg = arg; + } + private Object writeReplace() { + return new Class3Proxy(arg); + } + public String toString() { + return "Class3[arg=" + arg + "]"; + } + } + + // Serial proxy for Class3 + record Class3Proxy(XX arg) implements Serializable { + private Object readResolve() { + return new Class3(arg); + } + } + + // Record holding a Class3 + record Record4(Class3 arg) implements Serializable {} + + // Holder class without custom readObject + // Causes !hasSpecialReadMethod path through OIS.readSerialData + static class Class5 implements Serializable { + Class3 arg; + Class5(Class3 arg) { + this.arg = arg; + } + public String toString() { + return "Class5[arg=" + arg + "]"; + } + } + + // Holder class with custom readObject + // Causes hasSpecialReadMethod path taken through OIS.readSerialData + static class Class6 implements Serializable { + Class3 arg; + Class6(Class3 arg) { + this.arg = arg; + } + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + } + public String toString() { + return "Class6[arg=" + arg + "]"; + } + } + +} diff --git a/test/jdk/java/lang/StackWalker/TestBCI.java b/test/jdk/java/lang/StackWalker/TestBCI.java index 3cba0505e9c9b..4d5e6a6eaf473 100644 --- a/test/jdk/java/lang/StackWalker/TestBCI.java +++ b/test/jdk/java/lang/StackWalker/TestBCI.java @@ -134,7 +134,7 @@ static class MethodInfo { this.name = m.methodName().stringValue(); this.desc = m.methodTypeSymbol(); m.code().orElseThrow(() -> new IllegalArgumentException("Missing Code in " + m)) - .findAttribute(Attributes.LINE_NUMBER_TABLE) + .findAttribute(Attributes.lineNumberTable()) .orElseThrow(() -> new IllegalArgumentException("Missing LineNumberTable in " + m)) .lineNumbers().forEach(entry -> bciToLineNumbers.computeIfAbsent(entry.startPc(), _ -> new TreeSet<>()) diff --git a/test/jdk/java/lang/invoke/lambda/LambdaAsm.java b/test/jdk/java/lang/invoke/lambda/LambdaAsm.java index ebca93d639aa9..8369ea2bcd39b 100644 --- a/test/jdk/java/lang/invoke/lambda/LambdaAsm.java +++ b/test/jdk/java/lang/invoke/lambda/LambdaAsm.java @@ -125,7 +125,7 @@ static int checkMethod(ClassModel cf, String mthd) throws Exception { for (var m : cf.methods()) { String mname = m.methodName().stringValue(); if (mname.equals(mthd)) { - for (var a : m.findAttributes(Attributes.CODE)) { + for (var a : m.findAttributes(Attributes.code())) { count++; checkMethod(cf.thisClass().asInternalName(), mname, cf.constantPool(), a); diff --git a/test/jdk/java/net/InetAddress/OfLiteralTest.java b/test/jdk/java/net/InetAddress/OfLiteralTest.java index 90148a786af65..090523a9ee9f2 100644 --- a/test/jdk/java/net/InetAddress/OfLiteralTest.java +++ b/test/jdk/java/net/InetAddress/OfLiteralTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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,8 +22,8 @@ */ /* @test - * @bug 8272215 - * @summary Test for ofLiteral API in InetAddress classes + * @bug 8272215 8315767 + * @summary Test for ofLiteral, ofPosixLiteral APIs in InetAddress classes * @run junit/othervm -Djdk.net.hosts.file=nonExistingHostsFile.txt * OfLiteralTest * @run junit/othervm -Djdk.net.hosts.file=nonExistingHostsFile.txt @@ -67,11 +67,15 @@ public void validLiteral(InetAddressClass inetAddressClass, InetAddress ofLiteralResult = switch (inetAddressClass) { case INET_ADDRESS -> InetAddress.ofLiteral(addressLiteral); case INET4_ADDRESS -> Inet4Address.ofLiteral(addressLiteral); + case INET4_ADDRESS_POSIX -> Inet4Address.ofPosixLiteral(addressLiteral); case INET6_ADDRESS -> Inet6Address.ofLiteral(addressLiteral); }; - InetAddress getByNameResult = InetAddress.getByName(addressLiteral); Assert.assertArrayEquals(expectedAddressBytes, ofLiteralResult.getAddress()); - Assert.assertEquals(getByNameResult, ofLiteralResult); + // POSIX literals are not compatible with InetAddress.getByName() + if (inetAddressClass != InetAddressClass.INET4_ADDRESS_POSIX) { + InetAddress getByNameResult = InetAddress.getByName(addressLiteral); + Assert.assertEquals(getByNameResult, ofLiteralResult); + } } private static Stream validLiteralArguments() throws Exception { @@ -101,6 +105,33 @@ private static Stream validLiteralArguments() throws Exception { byte[] ipv6Ipv4MappedAddressExpBytes = new byte[]{ (byte) 129, (byte) 144, 52, 38}; + // 87.0.0.1 address bytes + byte[] ipv4_87_0_0_1 = new byte[]{87, 0, 0, 1}; + + // 127.0.0.1 address bytes + byte[] ipv4_127_0_0_1 = new byte[]{127, 0, 0, 1}; + + // 17.99.141.27 address bytes + byte[] ipv4_17_99_141_27 = new byte[]{17, 99, (byte)141, 27}; + + // 127.8.0.1 address bytes + byte[] ipv4_127_8_0_1 = new byte[]{127, 8, 0, 1}; + + // 0.0.0.42 address bytes + byte[] ipv4_0_0_0_42 = new byte[]{0, 0, 0, 42}; + + // 0.0.0.34 address bytes + byte[] ipv4_0_0_0_34 = new byte[]{0, 0, 0, 34}; + + // 127.0.1.2 address bytes + byte[] ipv4_127_0_1_2 = new byte[]{127, 0, 1, 2}; + + // 127.1.2.3 address bytes + byte[] ipv4_127_1_2_3 = new byte[]{127, 1, 2, 3}; + + // 255.255.255.255 address bytes + byte[] ipv4_255_255_255_255 = new byte[]{(byte)255, (byte)255, (byte)255, (byte)255}; + Stream validLiterals = Stream.of( // IPv6 address literals are parsable by Inet6Address.ofLiteral // and InetAddress.ofLiteral methods @@ -170,7 +201,87 @@ private static Stream validLiteralArguments() throws Exception { // with leading 0 that is discarded and address // parsed as decimal Arguments.of(InetAddressClass.INET_ADDRESS, - "03735928559", ipv4ExpBytes) + "03735928559", ipv4ExpBytes), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0127.0.0.1", ipv4_87_0_0_1), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0177.0.0.1", ipv4_127_0_0_1), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0s treated as octal segment prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0177.0000.0000.0001", ipv4_127_0_0_1), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "127.010.0.1", ipv4_127_8_0_1), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0377.0377.0377.0377", ipv4_255_255_255_255), + // form:'x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0s treated as octal segment prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0177.0.0402", ipv4_127_0_1_2), + // form:'x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0x treated as hexadecimal segment prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0x7F.0.0x102", ipv4_127_0_1_2), + // form:'x.x' method:InetAddress.ofPosixLiteral - + // with leading 0s treated as octal segment prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0177.0201003", ipv4_127_1_2_3), + // form:'x.x' method:InetAddress.ofPosixLiteral - + // with leading 0x treated as hexadecimal prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0x7F.0x10203", ipv4_127_1_2_3), + // form:'x.x' method:InetAddress.ofPosixLiteral - + // without prefixes treated as decimal + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "127.66051", ipv4_127_1_2_3), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "017700000001", ipv4_127_0_0_1), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "02130706433", ipv4_17_99_141_27), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "037777777777", ipv4_255_255_255_255), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0x treated as hex prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0x1020304", oneToFourAddressExpBytes), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0x treated as hex prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0xFFFFFFFF", ipv4_255_255_255_255), + // form:'x' method:InetAddress.ofPosixLiteral - + // without leading 0 treated as decimal + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "2130706433", ipv4_127_0_0_1), + // form:'x' method:InetAddress.ofPosixLiteral - + // without leading 0 treated as decimal + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "42", ipv4_0_0_0_42), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0100401404", oneToFourAddressExpBytes), + // form:'x' method:InetAddress.ofPosixLiteral - + // without prefixes treated as decimal + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "16909060", oneToFourAddressExpBytes), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "042", ipv4_0_0_0_34) ); // Generate addresses for loopback and wildcard address test cases @@ -251,7 +362,18 @@ private static Stream invalidLiteralArguments() { Arguments.of(InetAddressClass.INET_ADDRESS, "0x1.2.3.4"), Arguments.of(InetAddressClass.INET4_ADDRESS, "1.2.0x3.4"), Arguments.of(InetAddressClass.INET_ADDRESS, "0xFFFFFFFF"), - Arguments.of(InetAddressClass.INET4_ADDRESS, "0xFFFFFFFF") + Arguments.of(InetAddressClass.INET4_ADDRESS, "0xFFFFFFFF"), + + // invalid IPv4 literals in POSIX/BSD form + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "0x100.1.2.3"), // 0x100 is too large + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "1.2.3.0x100"), + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "127.08.9.1"), // 8, 9 are invalid octals + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "127.8.09.1"), + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "048"), + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, ""), // empty + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "0x1FFFFFFFF"), // 2^33 - 1 is too large + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "0x100000000"), // 2^32 is too large + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "040000000000") ); // Construct arguments for a test case with IPv6-scoped address with scope-id // specified as a string with non-existing network interface name @@ -297,6 +419,7 @@ private static Executable constructExecutable(InetAddressClass inetAddressClass, return switch (inetAddressClass) { case INET_ADDRESS -> () -> InetAddress.ofLiteral(input); case INET4_ADDRESS -> () -> Inet4Address.ofLiteral(input); + case INET4_ADDRESS_POSIX -> () -> Inet4Address.ofPosixLiteral(input); case INET6_ADDRESS -> () -> Inet6Address.ofLiteral(input); }; } @@ -304,6 +427,7 @@ private static Executable constructExecutable(InetAddressClass inetAddressClass, enum InetAddressClass { INET_ADDRESS, INET4_ADDRESS, + INET4_ADDRESS_POSIX, INET6_ADDRESS } } diff --git a/test/jdk/java/util/Random/RandomTestCoverage.java b/test/jdk/java/util/Random/RandomTestCoverage.java index be12d18819834..a0e906fbbe2a1 100644 --- a/test/jdk/java/util/Random/RandomTestCoverage.java +++ b/test/jdk/java/util/Random/RandomTestCoverage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 @@ -87,7 +87,7 @@ static void coverRandomGenerator(RandomGenerator rng) { DoubleStream doubleStream4 = rng.doubles(5, 0.5, 1.0); } - static void checkPredicates(RandomGeneratorFactory factory) { + static void checkPredicates(RandomGeneratorFactory factory) { RandomGenerator rng = factory.create(); if (rng instanceof ArbitrarilyJumpableGenerator != factory.isArbitrarilyJumpable()) { throw new RuntimeException("isArbitrarilyJumpable failing"); @@ -156,7 +156,7 @@ static void coverOf(String name) { coverFactory(RandomGeneratorFactory.of(name)); } - static void coverFactory(RandomGeneratorFactory factory) { + static void coverFactory(RandomGeneratorFactory factory) { String name = factory.name(); String group = factory.group(); int stateBits = factory.stateBits(); @@ -171,8 +171,34 @@ static void coverFactory(RandomGeneratorFactory factory) { boolean isSplittable = factory.isSplittable(); coverRandomGenerator(factory.create()); - coverRandomGenerator(factory.create(12345L)); - coverRandomGenerator(factory.create(new byte[] {1, 2, 3, 4, 5, 6, 7, 8})); + // test create(long) + switch (factory.name()) { + // SecureRandom doesn't have long constructors so we expect + // UnsupportedOperationException + case "SecureRandom" -> { + try { + factory.create(12345L); + throw new AssertionError("RandomGeneratorFactory.create(long) was expected" + + "to throw UnsupportedOperationException for " + factory.name() + " but didn't"); + } catch (UnsupportedOperationException ignored) { + } + } + default -> coverRandomGenerator(factory.create(12345L)); + } + // test create(byte[]) + switch (factory.name()) { + // these don't have byte[] constructors so we expect UnsupportedOperationException + case "Random", + "SplittableRandom" -> { + try { + factory.create(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); + throw new AssertionError("RandomGeneratorFactory.create(byte[]) was expected" + + "to throw UnsupportedOperationException for " + factory.name() + " but didn't"); + } catch (UnsupportedOperationException ignored) { + } + } + default -> coverRandomGenerator(factory.create(new byte[] {1, 2, 3, 4, 5, 6, 7, 8})); + } } static void coverDefaults() { @@ -188,32 +214,35 @@ public static void main(String[] args) throws Throwable { coverOf(factory.name()); }); RandomGeneratorFactory.all() - .filter(f -> f.isStreamable()) + .filter(RandomGeneratorFactory::isStreamable) .forEach(factory -> { coverStreamable((StreamableGenerator)factory.create()); }); RandomGeneratorFactory.all() - .filter(f -> f.isSplittable()) + .filter(RandomGeneratorFactory::isSplittable) .forEach(factory -> { coverSplittable((SplittableGenerator)factory.create()); }); RandomGeneratorFactory.all() - .filter(f -> f.isJumpable()) + .filter(RandomGeneratorFactory::isJumpable) .forEach(factory -> { coverJumpable((JumpableGenerator)factory.create()); }); RandomGeneratorFactory.all() - .filter(f -> f.isLeapable()) + .filter(RandomGeneratorFactory::isLeapable) .forEach(factory -> { coverLeapable((LeapableGenerator)factory.create()); }); RandomGeneratorFactory.all() - .filter(f -> f.isArbitrarilyJumpable()) + .filter(RandomGeneratorFactory::isArbitrarilyJumpable) .forEach(factory -> { coverArbitrarilyJumpable((ArbitrarilyJumpableGenerator)factory.create()); }); + RandomGeneratorFactory.all() + .forEach(RandomTestCoverage::checkPredicates); coverRandomGenerator(new SecureRandom()); coverRandomGenerator(ThreadLocalRandom.current()); + coverDefaults(); } } diff --git a/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java b/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java new file mode 100644 index 0000000000000..80779c9ce1d07 --- /dev/null +++ b/test/jdk/javax/swing/JMenuBar/RightLeftOrientation.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2007, 2024, 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 4211731 4214512 + * @summary + * This test checks if menu bars lay out correctly when their + * ComponentOrientation property is set to RIGHT_TO_LEFT. This test is + * manual. The tester is asked to compare left-to-right and + * right-to-left menu bars and judge whether they are mirror images of each + * other. + * @library /test/jdk/java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RightLeftOrientation + */ + +import java.awt.ComponentOrientation; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.ButtonGroup; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class RightLeftOrientation { + + static JFrame ltrFrame; + static JFrame rtlFrame; + + private static final String INSTRUCTIONS = """ + This test checks menu bars for correct Right-To-Left Component Orientation. + + You should see two frames, each containing a menu bar. + + One frame will be labelled "Left To Right" and will contain + a menu bar with menus starting on its left side. + The other frame will be labelled "Right To Left" and will + contain a menu bar with menus starting on its right side. + + The test will also contain radio buttons that can be used to set + the look and feel of the menu bars. + For each look and feel, you should compare the two menu + bars and make sure they are mirror images of each other. """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("RTL test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(30) + .testUI(RightLeftOrientation::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("RightLeftOrientation"); + JPanel panel = new JPanel(); + + ButtonGroup group = new ButtonGroup(); + JRadioButton rb; + ActionListener plafChanger = new PlafChanger(); + + UIManager.LookAndFeelInfo[] lafInfos = UIManager.getInstalledLookAndFeels(); + for (int i = 0; i < lafInfos.length; i++) { + rb = new JRadioButton(lafInfos[i].getName()); + rb.setActionCommand(lafInfos[i].getClassName()); + rb.addActionListener(plafChanger); + group.add(rb); + panel.add(rb); + if (i == 0) { + rb.setSelected(true); + } + } + + frame.add(panel); + + ltrFrame = new JFrame("Left To Right"); + ltrFrame.setJMenuBar(createMenuBar(ComponentOrientation.LEFT_TO_RIGHT)); + ltrFrame.setSize(400, 100); + ltrFrame.setLocation(new Point(10, 10)); + ltrFrame.setVisible(true); + + rtlFrame = new JFrame("Right To Left"); + rtlFrame.setJMenuBar(createMenuBar(ComponentOrientation.RIGHT_TO_LEFT)); + rtlFrame.setSize(400, 100); + rtlFrame.setLocation(new Point(10, 120)); + rtlFrame.setVisible(true); + frame.pack(); + return frame; + } + + static class PlafChanger implements ActionListener { + public void actionPerformed(ActionEvent e) { + String lnfName = e.getActionCommand(); + + try { + UIManager.setLookAndFeel(lnfName); + SwingUtilities.updateComponentTreeUI(ltrFrame); + SwingUtilities.updateComponentTreeUI(rtlFrame); + } + catch (Exception exc) { + System.err.println("Could not load LookAndFeel: " + lnfName); + } + + } + } + + + static JMenuBar createMenuBar(ComponentOrientation o) { + JMenuBar menuBar = new JMenuBar(); + menuBar.setComponentOrientation(o); + + JMenu menu = new JMenu("One"); + menu.setComponentOrientation(o); + menuBar.add(menu); + + menu = new JMenu("Two"); + menu.setComponentOrientation(o); + menuBar.add(menu); + + menu = new JMenu("Three"); + menu.setComponentOrientation(o); + menuBar.add(menu); + + return menuBar; + } + +} diff --git a/test/jdk/javax/swing/JToolBar/RightLeftOrientation.java b/test/jdk/javax/swing/JToolBar/RightLeftOrientation.java new file mode 100644 index 0000000000000..8822a86f79a77 --- /dev/null +++ b/test/jdk/javax/swing/JToolBar/RightLeftOrientation.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2007, 2024, 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 4214514 + * @summary + * This test checks if tool bars lay out correctly when their + * ComponentOrientation property is set to RIGHT_TO_LEFT. This test is + * manual. The tester is asked to compare left-to-right and + * right-to-left tool bars and judge whether they are mirror images of each + * other. + * @library /test/jdk/java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RightLeftOrientation + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class RightLeftOrientation { + + static JFrame ltrFrame; + static JFrame rtlFrame; + + private static final String INSTRUCTIONS = """ + This test checks tool bars for correct Right-To-Left Component Orientation. + + You should see two frames, each containing a tool bar. + + One frame will be labelled "Left To Right" and will contain + a tool bar with buttons starting on its left side. + The other frame will be labelled "Right To Left" and will + contain a tool bar with buttons starting on its right side. + + The test will also contain radio buttons that can be used to set + the look and feel of the tool bars. + For each look and feel, you should compare the two tool bars and + make sure they are mirror images of each other. + You should also drag the tool bars to each corner of the frame + to make sure the docking behavior is consistent between the two frames."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("RTL test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(RightLeftOrientation::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("RightLeftOrientation"); + JPanel panel = new JPanel(); + + ButtonGroup group = new ButtonGroup(); + JRadioButton rb; + ActionListener plafChanger = new PlafChanger(); + + UIManager.LookAndFeelInfo[] lafInfos = UIManager.getInstalledLookAndFeels(); + for (int i = 0; i < lafInfos.length; i++) { + rb = new JRadioButton(lafInfos[i].getName()); + rb.setActionCommand(lafInfos[i].getClassName()); + rb.addActionListener(plafChanger); + group.add(rb); + panel.add(rb); + if (i == 0) { + rb.setSelected(true); + } + } + + frame.add(panel); + + ltrFrame = new JFrame("Left To Right"); + Container contentPane = ltrFrame.getContentPane(); + contentPane.setLayout(new BorderLayout()); + panel = new JPanel(); + panel.setBackground(Color.white); + contentPane.add("Center",panel); + contentPane.add("North", + createToolBar(ComponentOrientation.LEFT_TO_RIGHT)); + ltrFrame.setSize(400, 140); + ltrFrame.setLocation(new Point(10, 10)); + ltrFrame.setVisible(true); + + rtlFrame = new JFrame("Right To Left"); + contentPane = rtlFrame.getContentPane(); + contentPane.setLayout(new BorderLayout()); + panel = new JPanel(); + panel.setBackground(Color.white); + contentPane.add("Center",panel); + contentPane.add("North", + createToolBar(ComponentOrientation.RIGHT_TO_LEFT)); + rtlFrame.setSize(400, 140); + rtlFrame.setLocation(new Point(420, 10)); + rtlFrame.setVisible(true); + + frame.pack(); + return frame; + } + + static class PlafChanger implements ActionListener { + public void actionPerformed(ActionEvent e) { + String lnfName = e.getActionCommand(); + + try { + UIManager.setLookAndFeel(lnfName); + SwingUtilities.updateComponentTreeUI(ltrFrame); + SwingUtilities.updateComponentTreeUI(rtlFrame); + } + catch (Exception exc) { + System.err.println("Could not load LookAndFeel: " + lnfName); + } + + } + } + + + static JToolBar createToolBar(ComponentOrientation o) { + JToolBar toolBar = new JToolBar(); + toolBar.setComponentOrientation(o); + + JButton button = new JButton("One"); + button.setComponentOrientation(o); + toolBar.add(button); + + button = new JButton("Two"); + button.setComponentOrientation(o); + toolBar.add(button); + + button = new JButton("Three"); + button.setComponentOrientation(o); + toolBar.add(button); + + return toolBar; + } + +} diff --git a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java b/test/jdk/jdk/classfile/AdvancedTransformationsTest.java index 9b4609fe8bc48..2ef7dca11ae0b 100644 --- a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java +++ b/test/jdk/jdk/classfile/AdvancedTransformationsTest.java @@ -120,9 +120,9 @@ void testRemapClass() throws Exception { ClassDesc.ofDescriptor(RawBytecodeHelper.class.descriptorString()), ClassDesc.of("remapped.RemappedBytecode"))) .orElse(ClassHierarchyResolver.defaultResolver()) )).verify(remapped)); - remapped.fields().forEach(f -> f.findAttribute(Attributes.SIGNATURE).ifPresent(sa -> + remapped.fields().forEach(f -> f.findAttribute(Attributes.signature()).ifPresent(sa -> verifySignature(f.fieldTypeSymbol(), sa.asTypeSignature()))); - remapped.methods().forEach(m -> m.findAttribute(Attributes.SIGNATURE).ifPresent(sa -> { + remapped.methods().forEach(m -> m.findAttribute(Attributes.signature()).ifPresent(sa -> { var md = m.methodTypeSymbol(); var ms = sa.asMethodSignature(); verifySignature(md.returnType(), ms.result()); @@ -173,7 +173,7 @@ void testRemapModule() throws Exception { cc.parse( cc.buildModule( ModuleAttribute.of(ModuleDesc.of("MyModule"), mab -> - mab.uses(foo).provides(foo, foo)))))).findAttribute(Attributes.MODULE).get(); + mab.uses(foo).provides(foo, foo)))))).findAttribute(Attributes.module()).get(); assertEquals(ma.uses().get(0).asSymbol(), bar); var provides = ma.provides().get(0); assertEquals(provides.provides().asSymbol(), bar); diff --git a/test/jdk/jdk/classfile/AnnotationModelTest.java b/test/jdk/jdk/classfile/AnnotationModelTest.java index ed647784219fc..25d02b8172f08 100644 --- a/test/jdk/jdk/classfile/AnnotationModelTest.java +++ b/test/jdk/jdk/classfile/AnnotationModelTest.java @@ -54,7 +54,7 @@ class AnnotationModelTest { @Test void readAnnos() { var model = ClassFile.of().parse(fileBytes); - var annotations = model.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get().annotations(); + var annotations = model.findAttribute(Attributes.runtimeVisibleAnnotations()).get().annotations(); assertEquals(annotations.size(), 3); } diff --git a/test/jdk/jdk/classfile/AttributesTest.java b/test/jdk/jdk/classfile/AttributesTest.java new file mode 100644 index 0000000000000..0d156dd586027 --- /dev/null +++ b/test/jdk/jdk/classfile/AttributesTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024, 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 8331291 + * @summary Testing Attributes API. + * @run junit AttributesTest + */ +import java.lang.classfile.AttributeMapper; +import java.lang.classfile.Attributes; +import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.reflect.Field; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +import jdk.internal.classfile.impl.BoundAttribute; +import jdk.internal.classfile.impl.TemporaryConstantPool; + +class AttributesTest { + + @Test + void testAttributesMapping() throws Exception { + var cp = TemporaryConstantPool.INSTANCE; + for (Field f : Attributes.class.getDeclaredFields()) { + if (f.getName().startsWith("NAME_") && f.getType() == String.class) { + Utf8Entry attrName = cp.utf8Entry((String)f.get(null)); + AttributeMapper mapper = BoundAttribute.standardAttribute(attrName); + assertNotNull(mapper, attrName.stringValue() + " 0x" + Integer.toHexString(attrName.hashCode())); + assertEquals(attrName.stringValue(), mapper.name()); + } + } + } +} diff --git a/test/jdk/jdk/classfile/BoundAttributeTest.java b/test/jdk/jdk/classfile/BoundAttributeTest.java index 8a25146bab951..103bcffa8987a 100644 --- a/test/jdk/jdk/classfile/BoundAttributeTest.java +++ b/test/jdk/jdk/classfile/BoundAttributeTest.java @@ -61,7 +61,7 @@ void testReadMethodParametersAttributeWithoutParameterName() { }); ClassModel model = cc.parse(raw); MethodParametersAttribute methodParametersAttribute = model.methods().get(0) - .findAttribute(Attributes.METHOD_PARAMETERS) + .findAttribute(Attributes.methodParameters()) .orElseThrow(() -> new AssertionFailedError("Attribute not present")); // MethodParametersAttribute#parameters() materializes the parameters List parameters = assertDoesNotThrow(methodParametersAttribute::parameters); diff --git a/test/jdk/jdk/classfile/CorpusTest.java b/test/jdk/jdk/classfile/CorpusTest.java index b13657e207213..21e275a837d84 100644 --- a/test/jdk/jdk/classfile/CorpusTest.java +++ b/test/jdk/jdk/classfile/CorpusTest.java @@ -83,7 +83,7 @@ static void splitTableAttributes(String sourceClassFile, String targetClassFile) var dcob = (DirectCodeBuilder)cob; var curPc = dcob.curPc(); switch (coe) { - case LineNumber ln -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.LINE_NUMBER_TABLE) { + case LineNumber ln -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.lineNumberTable()) { @Override public void writeBody(BufWriter b) { b.writeU2(1); @@ -91,14 +91,14 @@ public void writeBody(BufWriter b) { b.writeU2(ln.line()); } }); - case LocalVariable lv -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.LOCAL_VARIABLE_TABLE) { + case LocalVariable lv -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) { @Override public void writeBody(BufWriter b) { b.writeU2(1); lv.writeTo(b); } }); - case LocalVariableType lvt -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.LOCAL_VARIABLE_TYPE_TABLE) { + case LocalVariableType lvt -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) { @Override public void writeBody(BufWriter b) { b.writeU2(1); diff --git a/test/jdk/jdk/classfile/FilterDeadLabelsTest.java b/test/jdk/jdk/classfile/FilterDeadLabelsTest.java index be527d7bc1139..810f02d5f19fb 100644 --- a/test/jdk/jdk/classfile/FilterDeadLabelsTest.java +++ b/test/jdk/jdk/classfile/FilterDeadLabelsTest.java @@ -66,9 +66,9 @@ void testFilterDeadLabels() { }))).methods().get(0).code().get(); assertTrue(code.exceptionHandlers().isEmpty()); - code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).ifPresent(a -> assertTrue(a.localVariables().isEmpty())); - code.findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE).ifPresent(a -> assertTrue(a.localVariableTypes().isEmpty())); - code.findAttribute(Attributes.CHARACTER_RANGE_TABLE).ifPresent(a -> assertTrue(a.characterRangeTable().isEmpty())); + code.findAttribute(Attributes.localVariableTable()).ifPresent(a -> assertTrue(a.localVariables().isEmpty())); + code.findAttribute(Attributes.localVariableTypeTable()).ifPresent(a -> assertTrue(a.localVariableTypes().isEmpty())); + code.findAttribute(Attributes.characterRangeTable()).ifPresent(a -> assertTrue(a.characterRangeTable().isEmpty())); } @ParameterizedTest diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index a94a56ce33ff3..40ae8a5fb1f67 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -127,7 +127,7 @@ void testInvalidLookupSwitch() { assertThrows(IllegalArgumentException.class, () -> ClassFile.of().parse(ClassFile.of().build(ClassDesc.of("LookupSwitchClass"), cb -> cb.withMethod( "lookupSwitchMethod", MethodTypeDesc.of(ConstantDescs.CD_void), 0, mb -> - ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.CODE) { + ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override public void writeBody(BufWriter b) { b.writeU2(-1);//max stack @@ -152,7 +152,7 @@ void testInvalidTableSwitch() { assertThrows(IllegalArgumentException.class, () -> ClassFile.of().parse(ClassFile.of().build(ClassDesc.of("TableSwitchClass"), cb -> cb.withMethod( "tableSwitchMethod", MethodTypeDesc.of(ConstantDescs.CD_void), 0, mb -> - ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.CODE) { + ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override public void writeBody(BufWriter b) { b.writeU2(-1);//max stack diff --git a/test/jdk/jdk/classfile/LowJCovAttributeTest.java b/test/jdk/jdk/classfile/LowJCovAttributeTest.java index 9bc1e29155ea3..858b9c90416d1 100644 --- a/test/jdk/jdk/classfile/LowJCovAttributeTest.java +++ b/test/jdk/jdk/classfile/LowJCovAttributeTest.java @@ -94,8 +94,8 @@ private void testRead0() { } } for (MethodModel m : classLow.methods()) { - m.findAttribute(Attributes.CODE).ifPresent(code -> - ((CodeModel) code).findAttribute(Attributes.CHARACTER_RANGE_TABLE).ifPresent(attr -> { + m.findAttribute(Attributes.code()).ifPresent(code -> + ((CodeModel) code).findAttribute(Attributes.characterRangeTable()).ifPresent(attr -> { for (CharacterRangeInfo cr : attr.characterRangeTable()) { printf(" %d-%d -> %d/%d-%d/%d (%x)%n", cr.startPc(), cr.endPc(), cr.characterRangeStart() >> 10, cr.characterRangeStart() & 0x3FF, @@ -156,7 +156,7 @@ private void println() { // } // writeAndCompareAttributes(classLow, cp); // for (MethodLow m : classLow.methodsLow()) { -// m.findAttribute(Attributes.CODE).ifPresent(code -> +// m.findAttribute(Attributes.code()).ifPresent(code -> // writeAndCompareAttributes(code, cp)); // } // } diff --git a/test/jdk/jdk/classfile/LvtTest.java b/test/jdk/jdk/classfile/LvtTest.java index 35ec8dfcfa358..7c60d75823af4 100644 --- a/test/jdk/jdk/classfile/LvtTest.java +++ b/test/jdk/jdk/classfile/LvtTest.java @@ -174,7 +174,7 @@ void testCreateLoadLVT() throws Exception { var c = cc.parse(bytes); var main = c.methods().get(1); - var lvt = main.code().get().findAttribute(Attributes.LOCAL_VARIABLE_TABLE).get(); + var lvt = main.code().get().findAttribute(Attributes.localVariableTable()).get(); var lvs = lvt.localVariables(); assertEquals(lvs.size(), 3); @@ -278,7 +278,7 @@ void testCreateLoadLVTT() throws Exception { }); var c = cc.parse(bytes); var main = c.methods().get(1); - var lvtt = main.code().get().findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE).get(); + var lvtt = main.code().get().findAttribute(Attributes.localVariableTypeTable()).get(); var lvts = lvtt.localVariableTypes(); /* From javap: diff --git a/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java b/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java index 825394bff0af7..0ac9de70472ca 100644 --- a/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java +++ b/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java @@ -120,7 +120,7 @@ void copy(String name, byte[] bytes) throws Exception { cb.with(e); }); //TODO: work-around to compiler bug generating multiple constant pool entries within records - if (cm.findAttribute(Attributes.RECORD).isPresent()) { + if (cm.findAttribute(Attributes.record()).isPresent()) { System.err.printf("MassAdaptCopyPrimitiveMatchCodeTest: Ignored because it is a record%n - %s%n", name); return; } diff --git a/test/jdk/jdk/classfile/ModuleBuilderTest.java b/test/jdk/jdk/classfile/ModuleBuilderTest.java index 68dd16ab03af4..38e2dfef35a79 100644 --- a/test/jdk/jdk/classfile/ModuleBuilderTest.java +++ b/test/jdk/jdk/classfile/ModuleBuilderTest.java @@ -89,7 +89,7 @@ public ModuleBuilderTest() { .with(ModuleMainClassAttribute.of(ClassDesc.of("overwritten.main.Class")))); moduleModel = cc.parse(modInfo); attr = ((ModuleAttribute) moduleModel.attributes().stream() - .filter(a -> a.attributeMapper() == Attributes.MODULE) + .filter(a -> a.attributeMapper() == Attributes.module()) .findFirst() .orElseThrow()); } @@ -103,7 +103,7 @@ void testCreateModuleInfo() { // Verify var cm = cc.parse(modBytes); - var attr =cm.findAttribute(Attributes.MODULE).get(); + var attr =cm.findAttribute(Attributes.module()).get(); assertEquals(attr.moduleName().name().stringValue(), modName.name()); assertEquals(attr.moduleFlagsMask(), 0); assertEquals(attr.moduleVersion().get().stringValue(), modVsn); @@ -181,13 +181,13 @@ void testVerifyProvides() { @Test void verifyPackages() { - ModulePackagesAttribute a = moduleModel.findAttribute(Attributes.MODULE_PACKAGES).orElseThrow(); + ModulePackagesAttribute a = moduleModel.findAttribute(Attributes.modulePackages()).orElseThrow(); assertEquals(a.packages().stream().map(pe -> pe.asSymbol().name()).toList(), List.of("foo.bar.baz", "quux")); } @Test void verifyMainclass() { - ModuleMainClassAttribute a = moduleModel.findAttribute(Attributes.MODULE_MAIN_CLASS).orElseThrow(); + ModuleMainClassAttribute a = moduleModel.findAttribute(Attributes.moduleMainClass()).orElseThrow(); assertEquals(a.mainClass().asInternalName(), "overwritten/main/Class"); } diff --git a/test/jdk/jdk/classfile/SignaturesTest.java b/test/jdk/jdk/classfile/SignaturesTest.java index f4da2405dcd9f..4bba69735da3d 100644 --- a/test/jdk/jdk/classfile/SignaturesTest.java +++ b/test/jdk/jdk/classfile/SignaturesTest.java @@ -133,7 +133,7 @@ void testParseAndPrintSignatures() throws Exception { .filter(p -> Files.isRegularFile(p) && p.toString().endsWith(".class")).forEach(path -> { try { var cm = ClassFile.of().parse(path); - cm.findAttribute(Attributes.SIGNATURE).ifPresent(csig -> { + cm.findAttribute(Attributes.signature()).ifPresent(csig -> { assertEquals( ClassSignature.parseFrom(csig.signature().stringValue()).signatureString(), csig.signature().stringValue(), @@ -141,7 +141,7 @@ void testParseAndPrintSignatures() throws Exception { csc.incrementAndGet(); }); for (var m : cm.methods()) { - m.findAttribute(Attributes.SIGNATURE).ifPresent(msig -> { + m.findAttribute(Attributes.signature()).ifPresent(msig -> { assertEquals( MethodSignature.parseFrom(msig.signature().stringValue()).signatureString(), msig.signature().stringValue(), @@ -150,7 +150,7 @@ void testParseAndPrintSignatures() throws Exception { }); } for (var f : cm.fields()) { - f.findAttribute(Attributes.SIGNATURE).ifPresent(fsig -> { + f.findAttribute(Attributes.signature()).ifPresent(fsig -> { assertEquals( Signature.parseFrom(fsig.signature().stringValue()).signatureString(), fsig.signature().stringValue(), @@ -158,8 +158,8 @@ void testParseAndPrintSignatures() throws Exception { fsc.incrementAndGet(); }); } - cm.findAttribute(Attributes.RECORD).ifPresent(reca - -> reca.components().forEach(rc -> rc.findAttribute(Attributes.SIGNATURE).ifPresent(rsig -> { + cm.findAttribute(Attributes.record()).ifPresent(reca + -> reca.components().forEach(rc -> rc.findAttribute(Attributes.signature()).ifPresent(rsig -> { assertEquals( Signature.parseFrom(rsig.signature().stringValue()).signatureString(), rsig.signature().stringValue(), @@ -182,7 +182,7 @@ static class Observer extends ArrayList.Inner>{} @Test void testClassSignatureClassDesc() throws IOException { var observerCf = ClassFile.of().parse(Path.of(System.getProperty("test.classes"), "SignaturesTest$Observer.class")); - var sig = observerCf.findAttribute(Attributes.SIGNATURE).orElseThrow().asClassSignature(); + var sig = observerCf.findAttribute(Attributes.signature()).orElseThrow().asClassSignature(); var arrayListSig = sig.superclassSignature(); // ArrayList var arrayListTypeArg = (TypeArg.Bounded) arrayListSig.typeArgs().getFirst(); // Outer.Inner assertEquals(TypeArg.Bounded.WildcardIndicator.NONE, arrayListTypeArg.wildcardIndicator()); diff --git a/test/jdk/jdk/classfile/TestRecordComponent.java b/test/jdk/jdk/classfile/TestRecordComponent.java index a4d173e2c679d..95d56ffae8d08 100644 --- a/test/jdk/jdk/classfile/TestRecordComponent.java +++ b/test/jdk/jdk/classfile/TestRecordComponent.java @@ -93,7 +93,7 @@ void testChagne() throws Exception { cb.with(ce); }; ClassModel newModel = cc.parse(cc.transform(cm, xform)); - RecordAttribute ra = newModel.findAttribute(Attributes.RECORD).orElseThrow(); + RecordAttribute ra = newModel.findAttribute(Attributes.record()).orElseThrow(); assertEquals(ra.components().size(), 2, "Should have two components"); assertEquals(ra.components().get(0).name().stringValue(), "fooXYZ"); assertEquals(ra.components().get(1).name().stringValue(), "barXYZ"); @@ -110,7 +110,7 @@ void testOptions() throws Exception { count.addAndGet(rm.components().size()); }}); assertEquals(count.get(), 2); - assertEquals(cm.findAttribute(Attributes.RECORD).orElseThrow().components().size(), 2); + assertEquals(cm.findAttribute(Attributes.record()).orElseThrow().components().size(), 2); count.set(0); } diff --git a/test/jdk/jdk/classfile/examples/AnnotationsExamples.java b/test/jdk/jdk/classfile/examples/AnnotationsExamples.java index d9c397489654d..846645d93a941 100644 --- a/test/jdk/jdk/classfile/examples/AnnotationsExamples.java +++ b/test/jdk/jdk/classfile/examples/AnnotationsExamples.java @@ -54,8 +54,9 @@ public byte[] addAnno(ClassModel m) { * Find classes with annotations of a certain type */ public void findAnnotation(ClassModel m) { - if (m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).isPresent()) { - RuntimeVisibleAnnotationsAttribute a = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get(); + var rvaa = m.findAttribute(Attributes.runtimeVisibleAnnotations()); + if (rvaa.isPresent()) { + RuntimeVisibleAnnotationsAttribute a = rvaa.get(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/FunctionalInterface;")) System.out.println(m.thisClass().asInternalName()); @@ -68,9 +69,9 @@ public void findAnnotation(ClassModel m) { */ public void swapAnnotation(ClassModel m) { ClassModel m2 = m; - - if (m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).isPresent()) { - RuntimeVisibleAnnotationsAttribute a = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get(); + var rvaa = m.findAttribute(Attributes.runtimeVisibleAnnotations()); + if (rvaa.isPresent()) { + RuntimeVisibleAnnotationsAttribute a = rvaa.get(); var cc = ClassFile.of(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/annotation/Documented;")) { @@ -78,9 +79,9 @@ public void swapAnnotation(ClassModel m) { } } } - - if (m2.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).isPresent()) { - RuntimeVisibleAnnotationsAttribute a = m2.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get(); + rvaa = m2.findAttribute(Attributes.runtimeVisibleAnnotations()); + if (rvaa.isPresent()) { + RuntimeVisibleAnnotationsAttribute a = rvaa.get(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/annotation/Documented;")) throw new RuntimeException(); @@ -112,9 +113,9 @@ public void swapAnnotation(ClassModel m) { */ public void addAnnotation(ClassModel m) { ClassModel m2 = m; - - if (m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).isPresent()) { - RuntimeVisibleAnnotationsAttribute a = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get(); + var rvaa = m.findAttribute(Attributes.runtimeVisibleAnnotations()); + if (rvaa.isPresent()) { + RuntimeVisibleAnnotationsAttribute a = rvaa.get(); var cc = ClassFile.of(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/FunctionalInterface;")) { @@ -135,7 +136,7 @@ public void addAnnotation(ClassModel m) { } } - int size = m2.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElseThrow().annotations().size(); + int size = m2.findAttribute(Attributes.runtimeVisibleAnnotations()).orElseThrow().annotations().size(); if (size !=2) { StringBuilder sb = new StringBuilder(); ClassPrinter.toJson(m2, ClassPrinter.Verbosity.TRACE_ALL, sb::append); diff --git a/test/jdk/jdk/classfile/examples/ModuleExamples.java b/test/jdk/jdk/classfile/examples/ModuleExamples.java index 69e71aaeb5ce6..d4f4ff9a6958f 100644 --- a/test/jdk/jdk/classfile/examples/ModuleExamples.java +++ b/test/jdk/jdk/classfile/examples/ModuleExamples.java @@ -54,14 +54,14 @@ public void examineModule() throws IOException { ClassModel cm = ClassFile.of().parse(JRT.getPath("modules/java.base/module-info.class")); System.out.println("Is JVMS $4.7 compatible module-info: " + cm.isModuleInfo()); - ModuleAttribute ma = cm.findAttribute(Attributes.MODULE).orElseThrow(); + ModuleAttribute ma = cm.findAttribute(Attributes.module()).orElseThrow(); System.out.println("Module name: " + ma.moduleName().name().stringValue()); System.out.println("Exports: " + ma.exports()); - ModuleMainClassAttribute mmca = cm.findAttribute(Attributes.MODULE_MAIN_CLASS).orElse(null); + ModuleMainClassAttribute mmca = cm.findAttribute(Attributes.moduleMainClass()).orElse(null); System.out.println("Does the module have a MainClassAttribute?: " + (mmca != null)); - ModulePackagesAttribute mmp = cm.findAttribute(Attributes.MODULE_PACKAGES).orElseThrow(); + ModulePackagesAttribute mmp = cm.findAttribute(Attributes.modulePackages()).orElseThrow(); System.out.println("Packages?: " + mmp.packages()); } diff --git a/test/jdk/jdk/classfile/helpers/ClassRecord.java b/test/jdk/jdk/classfile/helpers/ClassRecord.java index b348a51f23ef3..a62ef1723677f 100644 --- a/test/jdk/jdk/classfile/helpers/ClassRecord.java +++ b/test/jdk/jdk/classfile/helpers/ClassRecord.java @@ -243,75 +243,75 @@ public static AttributesRecord ofStreamingElements(Supplier (Attribute) e) .collect(toMap(Attribute::attributeName, e -> e)); return new AttributesRecord( - mapAttr(attrs, ANNOTATION_DEFAULT, a -> ElementValueRecord.ofElementValue(a.defaultValue())), + mapAttr(attrs, annotationDefault(), a -> ElementValueRecord.ofElementValue(a.defaultValue())), cp == null ? null : IntStream.range(0, cp.bootstrapMethodCount()).mapToObj(i -> BootstrapMethodRecord.ofBootstrapMethodEntry(cp.bootstrapMethodEntry(i))).collect(toSetOrNull()), - mapAttr(attrs, CODE, a -> CodeRecord.ofStreamingElements(a.maxStack(), a.maxLocals(), a.codeLength(), a::elementStream, a, new CodeNormalizerHelper(a.codeArray()), cf)), - mapAttr(attrs, COMPILATION_ID, a -> a.compilationId().stringValue()), - mapAttr(attrs, CONSTANT_VALUE, a -> ConstantPoolEntryRecord.ofCPEntry(a.constant())), - mapAttr(attrs, DEPRECATED, a -> DefinedValue.DEFINED), - mapAttr(attrs, ENCLOSING_METHOD, a -> EnclosingMethodRecord.ofEnclosingMethodAttribute(a)), - mapAttr(attrs, EXCEPTIONS, a -> new HashSet<>(a.exceptions().stream().map(e -> e.asInternalName()).toList())), - mapAttr(attrs, INNER_CLASSES, a -> a.classes().stream().collect(toMap(ic -> ic.innerClass().asInternalName(), ic -> InnerClassRecord.ofInnerClassInfo(ic)))), - mapAttr(attrs, METHOD_PARAMETERS, a -> a.parameters().stream().map(mp -> MethodParameterRecord.ofMethodParameter(mp)).toList()), - mapAttr(attrs, MODULE, a -> ModuleRecord.ofModuleAttribute(a)), - mapAttr(attrs, MODULE_HASHES, a -> ModuleHashesRecord.ofModuleHashesAttribute(a)), - mapAttr(attrs, MODULE_MAIN_CLASS, a -> a.mainClass().asInternalName()), - mapAttr(attrs, MODULE_PACKAGES, a -> a.packages().stream().map(p -> p.name().stringValue()).collect(toSet())), - mapAttr(attrs, MODULE_RESOLUTION, a -> a.resolutionFlags()), - mapAttr(attrs, MODULE_TARGET, a -> a.targetPlatform().stringValue()), - mapAttr(attrs, NEST_HOST, a -> a.nestHost().asInternalName()), - mapAttr(attrs, NEST_MEMBERS, a -> a.nestMembers().stream().map(m -> m.asInternalName()).collect(toSet())), - mapAttr(attrs, PERMITTED_SUBCLASSES, a -> new HashSet<>(a.permittedSubclasses().stream().map(e -> e.asInternalName()).toList())), - mapAttr(attrs, RECORD, a -> a.components().stream().map(rc -> RecordComponentRecord.ofRecordComponent(rc, cf)).toList()), + mapAttr(attrs, code(), a -> CodeRecord.ofStreamingElements(a.maxStack(), a.maxLocals(), a.codeLength(), a::elementStream, a, new CodeNormalizerHelper(a.codeArray()), cf)), + mapAttr(attrs, compilationId(), a -> a.compilationId().stringValue()), + mapAttr(attrs, constantValue(), a -> ConstantPoolEntryRecord.ofCPEntry(a.constant())), + mapAttr(attrs, Attributes.deprecated(), a -> DefinedValue.DEFINED), + mapAttr(attrs, enclosingMethod(), a -> EnclosingMethodRecord.ofEnclosingMethodAttribute(a)), + mapAttr(attrs, exceptions(), a -> new HashSet<>(a.exceptions().stream().map(e -> e.asInternalName()).toList())), + mapAttr(attrs, innerClasses(), a -> a.classes().stream().collect(toMap(ic -> ic.innerClass().asInternalName(), ic -> InnerClassRecord.ofInnerClassInfo(ic)))), + mapAttr(attrs, methodParameters(), a -> a.parameters().stream().map(mp -> MethodParameterRecord.ofMethodParameter(mp)).toList()), + mapAttr(attrs, module(), a -> ModuleRecord.ofModuleAttribute(a)), + mapAttr(attrs, moduleHashes(), a -> ModuleHashesRecord.ofModuleHashesAttribute(a)), + mapAttr(attrs, moduleMainClass(), a -> a.mainClass().asInternalName()), + mapAttr(attrs, modulePackages(), a -> a.packages().stream().map(p -> p.name().stringValue()).collect(toSet())), + mapAttr(attrs, moduleResolution(), a -> a.resolutionFlags()), + mapAttr(attrs, moduleTarget(), a -> a.targetPlatform().stringValue()), + mapAttr(attrs, nestHost(), a -> a.nestHost().asInternalName()), + mapAttr(attrs, nestMembers(), a -> a.nestMembers().stream().map(m -> m.asInternalName()).collect(toSet())), + mapAttr(attrs, permittedSubclasses(), a -> new HashSet<>(a.permittedSubclasses().stream().map(e -> e.asInternalName()).toList())), + mapAttr(attrs, record(), a -> a.components().stream().map(rc -> RecordComponentRecord.ofRecordComponent(rc, cf)).toList()), elements.get().filter(e -> e instanceof RuntimeVisibleAnnotationsAttribute).map(e -> (RuntimeVisibleAnnotationsAttribute) e).flatMap(a -> a.annotations().stream()) .map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), elements.get().filter(e -> e instanceof RuntimeInvisibleAnnotationsAttribute).map(e -> (RuntimeInvisibleAnnotationsAttribute) e).flatMap(a -> a.annotations().stream()) .map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), - mapAttr(attrs, RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), - mapAttr(attrs, RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), - mapAttr(attrs, RUNTIME_VISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), - mapAttr(attrs, RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), - mapAttr(attrs, SIGNATURE, a -> a.signature().stringValue()), - mapAttr(attrs, SOURCE_DEBUG_EXTENSION, a -> new String(a.contents(), StandardCharsets.UTF_8)), - mapAttr(attrs, SOURCE_FILE, a -> a.sourceFile().stringValue()), - mapAttr(attrs, SOURCE_ID, a -> a.sourceId().stringValue()), - mapAttr(attrs, SYNTHETIC, a -> DefinedValue.DEFINED) + mapAttr(attrs, runtimeVisibleParameterAnnotations(), a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), + mapAttr(attrs, runtimeInvisibleParameterAnnotations(), a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), + mapAttr(attrs, runtimeVisibleTypeAnnotations(), a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), + mapAttr(attrs, runtimeInvisibleTypeAnnotations(), a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), + mapAttr(attrs, signature(), a -> a.signature().stringValue()), + mapAttr(attrs, sourceDebugExtension(), a -> new String(a.contents(), StandardCharsets.UTF_8)), + mapAttr(attrs, sourceFile(), a -> a.sourceFile().stringValue()), + mapAttr(attrs, sourceId(), a -> a.sourceId().stringValue()), + mapAttr(attrs, synthetic(), a -> DefinedValue.DEFINED) ); } public static AttributesRecord ofAttributes(AttributeFinder af, CompatibilityFilter... cf) { return new AttributesRecord( - af.findAndMap(Attributes.ANNOTATION_DEFAULT, a -> ElementValueRecord.ofElementValue(a.defaultValue())), - af.findAndMap(Attributes.BOOTSTRAP_METHODS, a -> a.bootstrapMethods().stream().map(bm -> BootstrapMethodRecord.ofBootstrapMethodEntry(bm)).collect(toSet())), - af.findAndMap(Attributes.CODE, a -> CodeRecord.ofCodeAttribute(a, cf)), - af.findAndMap(Attributes.COMPILATION_ID, a -> a.compilationId().stringValue()), - af.findAndMap(Attributes.CONSTANT_VALUE, a -> ConstantPoolEntryRecord.ofCPEntry(a.constant())), - af.findAndMap(Attributes.DEPRECATED, a -> DefinedValue.DEFINED), - af.findAndMap(Attributes.ENCLOSING_METHOD, a -> EnclosingMethodRecord.ofEnclosingMethodAttribute(a)), - af.findAndMap(Attributes.EXCEPTIONS, a -> a.exceptions().stream().map(e -> e.asInternalName()).collect(toSet())), - af.findAndMap(Attributes.INNER_CLASSES, a -> a.classes().stream().collect(toMap(ic -> ic.innerClass().asInternalName(), ic -> InnerClassRecord.ofInnerClassInfo(ic)))), - af.findAndMap(Attributes.METHOD_PARAMETERS, a -> a.parameters().stream().map(mp -> MethodParameterRecord.ofMethodParameter(mp)).toList()), - af.findAndMap(Attributes.MODULE, a -> ModuleRecord.ofModuleAttribute(a)), - af.findAndMap(Attributes.MODULE_HASHES, a -> ModuleHashesRecord.ofModuleHashesAttribute(a)), - af.findAndMap(Attributes.MODULE_MAIN_CLASS, a -> a.mainClass().asInternalName()), - af.findAndMap(Attributes.MODULE_PACKAGES, a -> a.packages().stream().map(p -> p.name().stringValue()).collect(toSet())), - af.findAndMap(Attributes.MODULE_RESOLUTION, a -> a.resolutionFlags()), - af.findAndMap(Attributes.MODULE_TARGET, a -> a.targetPlatform().stringValue()), - af.findAndMap(Attributes.NEST_HOST, a -> a.nestHost().asInternalName()), - af.findAndMap(Attributes.NEST_MEMBERS, a -> a.nestMembers().stream().map(m -> m.asInternalName()).collect(toSet())), - af.findAndMap(Attributes.PERMITTED_SUBCLASSES, a -> a.permittedSubclasses().stream().map(e -> e.asInternalName()).collect(toSet())), - af.findAndMap(RECORD, a -> a.components().stream().map(rc -> RecordComponentRecord.ofRecordComponent(rc, cf)).toList()), - af.findAll(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).flatMap(a -> a.annotations().stream()).map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), - af.findAll(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).flatMap(a -> a.annotations().stream()).map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), - af.findAndMap(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), - af.findAndMap(Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), - af.findAndMap(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), - af.findAndMap(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), - af.findAndMap(Attributes.SIGNATURE, a -> a.signature().stringValue()), - af.findAndMap(Attributes.SOURCE_DEBUG_EXTENSION, a -> new String(a.contents(), StandardCharsets.UTF_8)), - af.findAndMap(Attributes.SOURCE_FILE, a -> a.sourceFile().stringValue()), - af.findAndMap(Attributes.SOURCE_ID, a -> a.sourceId().stringValue()), - af.findAndMap(Attributes.SYNTHETIC, a -> DefinedValue.DEFINED)); + af.findAndMap(annotationDefault(), a -> ElementValueRecord.ofElementValue(a.defaultValue())), + af.findAndMap(bootstrapMethods(), a -> a.bootstrapMethods().stream().map(bm -> BootstrapMethodRecord.ofBootstrapMethodEntry(bm)).collect(toSet())), + af.findAndMap(code(), a -> CodeRecord.ofCodeAttribute(a, cf)), + af.findAndMap(compilationId(), a -> a.compilationId().stringValue()), + af.findAndMap(constantValue(), a -> ConstantPoolEntryRecord.ofCPEntry(a.constant())), + af.findAndMap(Attributes.deprecated(), a -> DefinedValue.DEFINED), + af.findAndMap(enclosingMethod(), a -> EnclosingMethodRecord.ofEnclosingMethodAttribute(a)), + af.findAndMap(exceptions(), a -> a.exceptions().stream().map(e -> e.asInternalName()).collect(toSet())), + af.findAndMap(innerClasses(), a -> a.classes().stream().collect(toMap(ic -> ic.innerClass().asInternalName(), ic -> InnerClassRecord.ofInnerClassInfo(ic)))), + af.findAndMap(methodParameters(), a -> a.parameters().stream().map(mp -> MethodParameterRecord.ofMethodParameter(mp)).toList()), + af.findAndMap(module(), a -> ModuleRecord.ofModuleAttribute(a)), + af.findAndMap(moduleHashes(), a -> ModuleHashesRecord.ofModuleHashesAttribute(a)), + af.findAndMap(moduleMainClass(), a -> a.mainClass().asInternalName()), + af.findAndMap(modulePackages(), a -> a.packages().stream().map(p -> p.name().stringValue()).collect(toSet())), + af.findAndMap(moduleResolution(), a -> a.resolutionFlags()), + af.findAndMap(moduleTarget(), a -> a.targetPlatform().stringValue()), + af.findAndMap(nestHost(), a -> a.nestHost().asInternalName()), + af.findAndMap(nestMembers(), a -> a.nestMembers().stream().map(m -> m.asInternalName()).collect(toSet())), + af.findAndMap(permittedSubclasses(), a -> a.permittedSubclasses().stream().map(e -> e.asInternalName()).collect(toSet())), + af.findAndMap(record(), a -> a.components().stream().map(rc -> RecordComponentRecord.ofRecordComponent(rc, cf)).toList()), + af.findAll(runtimeVisibleAnnotations()).flatMap(a -> a.annotations().stream()).map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), + af.findAll(runtimeInvisibleAnnotations()).flatMap(a -> a.annotations().stream()).map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), + af.findAndMap(runtimeVisibleParameterAnnotations(), a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), + af.findAndMap(runtimeInvisibleParameterAnnotations(), a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), + af.findAndMap(runtimeVisibleTypeAnnotations(), a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), + af.findAndMap(runtimeInvisibleTypeAnnotations(), a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), + af.findAndMap(signature(), a -> a.signature().stringValue()), + af.findAndMap(sourceDebugExtension(), a -> new String(a.contents(), StandardCharsets.UTF_8)), + af.findAndMap(sourceFile(), a -> a.sourceFile().stringValue()), + af.findAndMap(sourceId(), a -> a.sourceId().stringValue()), + af.findAndMap(synthetic(), a -> DefinedValue.DEFINED)); } } @@ -353,12 +353,12 @@ static CodeAttributesRecord ofStreamingElements(Supplier a.characterRangeTable().stream()).map(cr -> CharacterRangeRecord.ofCharacterRange(cr, code)).collect(toSetOrNull()), - af.findAll(Attributes.LINE_NUMBER_TABLE).flatMap(a -> a.lineNumbers().stream()).map(ln -> new LineNumberRecord(ln.lineNumber(), code.targetIndex(ln.startPc()))).collect(toSetOrNull()), - af.findAll(Attributes.LOCAL_VARIABLE_TABLE).flatMap(a -> a.localVariables().stream()).map(lv -> LocalVariableRecord.ofLocalVariableInfo(lv, code)).collect(toSetOrNull()), - af.findAll(Attributes.LOCAL_VARIABLE_TYPE_TABLE).flatMap(a -> a.localVariableTypes().stream()).map(lv -> LocalVariableTypeRecord.ofLocalVariableTypeInfo(lv, code)).collect(toSetOrNull()), - af.findAndMap(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(ann -> TypeAnnotationRecord.ofTypeAnnotation(ann, lr, code)).collect(toSet())), - af.findAndMap(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(ann -> TypeAnnotationRecord.ofTypeAnnotation(ann, lr, code)).collect(toSet()))); + af.findAll(Attributes.characterRangeTable()).flatMap(a -> a.characterRangeTable().stream()).map(cr -> CharacterRangeRecord.ofCharacterRange(cr, code)).collect(toSetOrNull()), + af.findAll(Attributes.lineNumberTable()).flatMap(a -> a.lineNumbers().stream()).map(ln -> new LineNumberRecord(ln.lineNumber(), code.targetIndex(ln.startPc()))).collect(toSetOrNull()), + af.findAll(Attributes.localVariableTable()).flatMap(a -> a.localVariables().stream()).map(lv -> LocalVariableRecord.ofLocalVariableInfo(lv, code)).collect(toSetOrNull()), + af.findAll(Attributes.localVariableTypeTable()).flatMap(a -> a.localVariableTypes().stream()).map(lv -> LocalVariableTypeRecord.ofLocalVariableTypeInfo(lv, code)).collect(toSetOrNull()), + af.findAndMap(Attributes.runtimeVisibleTypeAnnotations(), a -> a.annotations().stream().map(ann -> TypeAnnotationRecord.ofTypeAnnotation(ann, lr, code)).collect(toSet())), + af.findAndMap(Attributes.runtimeInvisibleTypeAnnotations(), a -> a.annotations().stream().map(ann -> TypeAnnotationRecord.ofTypeAnnotation(ann, lr, code)).collect(toSet()))); } } diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java index 85fac4940665a..0c9b771c3ef62 100644 --- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java +++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java @@ -76,7 +76,7 @@ static byte[] transform(ClassModel clm) { // first pass transforms bound to unbound instructions cob3.transforming(new CodeRebuildingTransform(), cob4 -> { com.forEachElement(cob4::with); - com.findAttribute(Attributes.STACK_MAP_TABLE).ifPresent(cob4::with); + com.findAttribute(Attributes.stackMapTable()).ifPresent(cob4::with); })))); case AnnotationDefaultAttribute a -> mb.with(AnnotationDefaultAttribute.of(transformAnnotationValue(a.defaultValue()))); case DeprecatedAttribute a -> mb.with(DeprecatedAttribute.of()); diff --git a/test/jdk/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java b/test/jdk/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java index a313aab255267..2d5175dcf3fd0 100644 --- a/test/jdk/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java +++ b/test/jdk/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java @@ -164,7 +164,7 @@ public List run(Stream classes)throws IOException, InterruptedExce private static final String CALLER_SENSITIVE_ANNOTATION = "Ljdk/internal/reflect/CallerSensitive;"; private static boolean isCallerSensitive(MethodModel m) { - var attr = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + var attr = m.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (attr != null) { for (var ann : attr.annotations()) { if (ann.className().equalsString(CALLER_SENSITIVE_ANNOTATION)) { diff --git a/test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSMs.java b/test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSMs.java index 0a8a0ccfaea11..6dff95000f075 100644 --- a/test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSMs.java +++ b/test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSMs.java @@ -238,7 +238,7 @@ private static boolean csmWithCallerParameter(ClassModel cf, MethodModel csm, Me private static boolean isCallerSensitive(MethodModel m) throws IllegalArgumentException { - var attr = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + var attr = m.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (attr != null) { for (var ann : attr.annotations()) { if (ann.className().equalsString(CALLER_SENSITIVE_ANNOTATION)) { @@ -250,7 +250,7 @@ private static boolean isCallerSensitive(MethodModel m) } private static boolean isCallerSensitiveAdapter(MethodModel m) { - var attr = m.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + var attr = m.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (attr != null) { for (var ann : attr.annotations()) { diff --git a/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java b/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java index d3d8377183d3a..7480acb1d1d3a 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ * @requires vm.hasJFR * @library /test/lib /test/jdk * @summary Purpose of this test is to run leak profiler without command line tweaks or WhiteBox hacks until we succeed - * @run main/othervm jdk.jfr.event.oldobject.TestSanityDefault + * @run main/othervm -Xmx1G jdk.jfr.event.oldobject.TestSanityDefault */ public class TestSanityDefault { diff --git a/test/jdk/sun/security/krb5/auto/CaseSensitive.java b/test/jdk/sun/security/krb5/auto/CaseSensitive.java new file mode 100644 index 0000000000000..365d8c6c6f081 --- /dev/null +++ b/test/jdk/sun/security/krb5/auto/CaseSensitive.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024, 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 8331975 + * @summary ensure correct name comparison when a system property is set + * @library /test/lib + * @compile -XDignore.symbol.file CaseSensitive.java + * @run main jdk.test.lib.FileInstaller TestHosts TestHosts + * @run main/othervm -Djdk.net.hosts.file=TestHosts CaseSensitive no + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.security.krb5.name.case.sensitive=true CaseSensitive yes + */ + +import jdk.test.lib.Asserts; +import org.ietf.jgss.GSSException; +import sun.security.jgss.GSSUtil; + +public class CaseSensitive { + + public static void main(String[] args) throws Exception { + switch (args[0]) { + case "yes" -> testSensitive(); + case "no" -> testInsensitive(); + } + } + + static void testSensitive() throws Exception { + var kdc = new OneKDC(null).writeJAASConf(); + kdc.addPrincipal("hello", "password".toCharArray()); + kdc.writeKtab(OneKDC.KTAB); + + Context c = Context.fromJAAS("client"); + Context s = Context.fromJAAS("com.sun.security.jgss.krb5.accept"); + + // There is only "hello". Cannot talk to "HELLO" + c.startAsClient("HELLO", GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + try { + Context.handshake(c, s); + throw new RuntimeException("Should not succeed"); + } catch(GSSException ge) { + System.out.println(ge.getMessage()); + System.out.println("No HELLO in db. Expected"); + } + + // Add "HELLO". Can talk to "HELLO" now. + kdc.addPrincipal("HELLO", "different".toCharArray()); + kdc.writeKtab(OneKDC.KTAB); + + c.startAsClient("HELLO", GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + // Name could be partial without realm, so only compare the beginning + Asserts.assertTrue(c.x().getTargName().toString().startsWith("HELLO"), + c.x().getTargName().toString()); + Asserts.assertTrue(s.x().getTargName().toString().startsWith("HELLO"), + s.x().getTargName().toString()); + + // Can also talk to "hello", which has a different password. + c.startAsClient("hello", GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + Asserts.assertTrue(c.x().getTargName().toString().startsWith("hello"), + c.x().getTargName().toString()); + Asserts.assertTrue(s.x().getTargName().toString().startsWith("hello"), + s.x().getTargName().toString()); + } + + static void testInsensitive() throws Exception { + var kdc = new OneKDC(null).writeJAASConf(); + kdc.addPrincipal("hello", "password".toCharArray()); + kdc.writeKtab(OneKDC.KTAB); + + Context c = Context.fromJAAS("client"); + Context s = Context.fromJAAS("com.sun.security.jgss.krb5.accept"); + + // There is only "hello" but we can talk to "HELLO". + c.startAsClient("HELLO", GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + Asserts.assertTrue(c.x().getTargName().toString().startsWith("HELLO"), + c.x().getTargName().toString()); + Asserts.assertTrue(s.x().getTargName().toString().startsWith("HELLO"), + s.x().getTargName().toString()); + } +} diff --git a/test/jdk/sun/security/krb5/auto/KDC.java b/test/jdk/sun/security/krb5/auto/KDC.java index 6e4bfba61f4a8..bb744281eb9b4 100644 --- a/test/jdk/sun/security/krb5/auto/KDC.java +++ b/test/jdk/sun/security/krb5/auto/KDC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, 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 @@ -143,6 +143,9 @@ public class KDC { private static final String SUPPORTED_ETYPES = System.getProperty("kdc.supported.enctypes"); + private static final boolean NAME_CASE_SENSITIVE + = Boolean.getBoolean("jdk.security.krb5.name.case.sensitive"); + // The native KDC private final NativeKdc nativeKdc; @@ -154,27 +157,28 @@ public class KDC { // Principal db. principal -> pass. A case-insensitive TreeMap is used // so that even if the client provides a name with different case, the KDC // can still locate the principal and give back correct salt. - private TreeMap passwords = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap passwords = newTreeMap(); // Non default salts. Precisely, there should be different salts for // different etypes, pretend they are the same at the moment. - private TreeMap salts = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap salts = newTreeMap(); // Non default s2kparams for newer etypes. Precisely, there should be // different s2kparams for different etypes, pretend they are the same // at the moment. - private TreeMap s2kparamses = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap s2kparamses = newTreeMap(); // Alias for referrals. - private TreeMap aliasReferrals = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap aliasReferrals = newTreeMap(); // Alias for local resolution. - private TreeMap alias2Principals = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap alias2Principals = newTreeMap(); + + private static TreeMap newTreeMap() { + return NAME_CASE_SENSITIVE + ? new TreeMap<>() + : new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + } // Realm name private String realm; @@ -354,7 +358,7 @@ public void writeKtab(String tab, boolean append, String... names) } if (nativeKdc == null) { char[] pass = passwords.get(name); - int kvno = 0; + int kvno = -1; // always create new keys if (Character.isDigit(pass[pass.length - 1])) { kvno = pass[pass.length - 1] - '0'; } diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java index abad01099bcee..f7e677bbbd05d 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -34,9 +34,12 @@ */ import java.net.ServerSocket; +import java.net.BindException; public class ReuseAddr extends SSLSocketTemplate { + private static final int MAX_ATTEMPTS = 3; + @Override protected void doServerSide() throws Exception { super.doServerSide(); @@ -50,6 +53,21 @@ protected void doServerSide() throws Exception { } public static void main(String[] args) throws Exception { - new ReuseAddr().run(); + for (int i=1 ; i <= MAX_ATTEMPTS; i++) { + try { + new ReuseAddr().run(); + System.out.println("Test succeeded at attempt " + i); + break; + } catch (BindException x) { + System.out.println("attempt " + i + " failed: " + x); + if (i == MAX_ATTEMPTS) { + String msg = "Could not succeed after " + i + " attempts"; + System.err.println(msg); + throw new AssertionError("Failed to reuse address: " + msg, x); + } else { + System.out.println("Retrying..."); + } + } + } } } diff --git a/test/jdk/tools/jlink/plugins/StripJavaDebugAttributesPluginTest.java b/test/jdk/tools/jlink/plugins/StripJavaDebugAttributesPluginTest.java index 79a52f5728810..0bcb19e087caf 100644 --- a/test/jdk/tools/jlink/plugins/StripJavaDebugAttributesPluginTest.java +++ b/test/jdk/tools/jlink/plugins/StripJavaDebugAttributesPluginTest.java @@ -137,16 +137,16 @@ private > void checkDebugAttributes(byte[] strippedClassF ClassModel classFile = ClassFile.of().parse(strippedClassFile); for (MethodModel method : classFile.methods()) { String methodName = method.methodName().stringValue(); - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); - if (code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElse(null) != null) { + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); + if (code.findAttribute(Attributes.lineNumberTable()).orElse(null) != null) { throw new AssertionError("Debug attribute was not removed: " + "LINE_NUMBER_TABLE" + " from method " + classFile.thisClass().asInternalName() + "#" + methodName); } - if (code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElse(null) != null) { + if (code.findAttribute(Attributes.localVariableTable()).orElse(null) != null) { throw new AssertionError("Debug attribute was not removed: " + "LOCAL_VARIABLE_TABLE" + " from method " + classFile.thisClass().asInternalName() + "#" + methodName); } - if (code.findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE).orElse(null) != null) { + if (code.findAttribute(Attributes.localVariableTypeTable()).orElse(null) != null) { throw new AssertionError("Debug attribute was not removed: " + "LOCAL_VARIABLE_TYPE_TABLE" + " from method " + classFile.thisClass().asInternalName() + "#" + methodName); } diff --git a/test/langtools/tools/javac/4241573/T4241573.java b/test/langtools/tools/javac/4241573/T4241573.java index 93164bad57f2d..9989ff83454ab 100644 --- a/test/langtools/tools/javac/4241573/T4241573.java +++ b/test/langtools/tools/javac/4241573/T4241573.java @@ -109,7 +109,7 @@ void verifySourceFileAttribute(File f) { System.err.println("verify: " + f); try { ClassModel cf = ClassFile.of().parse(f.toPath()); - SourceFileAttribute sfa = cf.findAttribute(Attributes.SOURCE_FILE).orElseThrow(); + SourceFileAttribute sfa = cf.findAttribute(Attributes.sourceFile()).orElseThrow(); String found = sfa.sourceFile().stringValue(); String expect = f.getName().replaceAll("([$.].*)?\\.class", ".java"); if (!expect.equals(found)) { diff --git a/test/langtools/tools/javac/7003595/T7003595.java b/test/langtools/tools/javac/7003595/T7003595.java index 94fb0c4b09c6c..c5c12259c14ad 100644 --- a/test/langtools/tools/javac/7003595/T7003595.java +++ b/test/langtools/tools/javac/7003595/T7003595.java @@ -163,7 +163,7 @@ void verifyBytecode(JavaSource source) { throw new Error("Classfile not found: " + filename); } - InnerClassesAttribute innerClasses = cf.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute innerClasses = cf.findAttribute(Attributes.innerClasses()).orElse(null); ArrayList foundInnerSig = new ArrayList<>(); if (innerClasses != null) { diff --git a/test/langtools/tools/javac/8009170/RedundantByteCodeInArrayTest.java b/test/langtools/tools/javac/8009170/RedundantByteCodeInArrayTest.java index a9821e75ac0f2..8f2ed91039cfd 100644 --- a/test/langtools/tools/javac/8009170/RedundantByteCodeInArrayTest.java +++ b/test/langtools/tools/javac/8009170/RedundantByteCodeInArrayTest.java @@ -56,7 +56,7 @@ void checkClassFile(File file) //lets get all the methods in the class file. for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString("arrMethod")) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = method.findAttribute(Attributes.code()).orElse(null); assert code != null; if (code.maxLocals() > 4) throw new AssertionError("Too many locals for method arrMethod"); diff --git a/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java b/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java index 7769b1caf3226..fb78132e4f104 100644 --- a/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java +++ b/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java @@ -125,7 +125,7 @@ static void assertInnerFlags(ClassModel classFile, String name, int expected) { } private static int lookupInnerFlags(ClassModel classFile, String innerName) { - InnerClassesAttribute inners = classFile.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute inners = classFile.findAttribute(Attributes.innerClasses()).orElse(null); if (inners == null) { throw new AssertionError("InnerClasses attribute missing in class " + classFile.thisClass().asInternalName()); } diff --git a/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java b/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java new file mode 100644 index 0000000000000..1362864d8fe10 --- /dev/null +++ b/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2024, 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 8325324 + * @summary Verify behavior w.r.t. implicit imports + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @run main ImplicitImports +*/ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; + +import toolbox.TestRunner; +import toolbox.JavacTask; +import toolbox.JavaTask; +import toolbox.Task; +import toolbox.Task.OutputKind; +import toolbox.ToolBox; + +public class ImplicitImports extends TestRunner { + + private static final String SOURCE_VERSION = System.getProperty("java.specification.version"); + private ToolBox tb; + + public static void main(String... args) throws Exception { + new ImplicitImports().runTests(); + } + + ImplicitImports() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testImplicitJavaBaseImport(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeFile(src.resolve("Test.java"), + """ + public static void main(String... args) { + List l = new ArrayList<>(); + System.out.println(l.getClass().getName()); + } + """); + + Files.createDirectories(classes); + + {//with --release: + new JavacTask(tb) + .options("--enable-preview", "--release", SOURCE_VERSION) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + var out = new JavaTask(tb) + .classpath(classes.toString()) + .className("Test") + .vmOptions("--enable-preview") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + var expectedOut = List.of("java.util.ArrayList"); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } + + {//with --source: + new JavacTask(tb) + .options("--enable-preview", "--source", SOURCE_VERSION) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + var out = new JavaTask(tb) + .classpath(classes.toString()) + .className("Test") + .vmOptions("--enable-preview") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + var expectedOut = List.of("java.util.ArrayList"); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } + } + + @Test + public void testImplicitSimpleIOImport(Path base) throws Exception { + Path current = base.resolve("."); + + Path patchClasses = prepareIOPatch(current); + + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeFile(src.resolve("Test.java"), + """ + public static void main(String... args) { + println("Hello, World!"); + } + """); + + Files.createDirectories(classes); + + new JavacTask(tb) + .options("--enable-preview", "--release", SOURCE_VERSION, + "--patch-module", "java.base=" + patchClasses) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + var out = new JavaTask(tb) + .classpath(classes.toString()) + .className("Test") + .vmOptions("--enable-preview", + "--patch-module", "java.base=" + patchClasses) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + var expectedOut = List.of("Hello, World!"); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } + + @Test + public void testNoImplicitImportsForOrdinaryClasses(Path base) throws Exception { + Path current = base.resolve("."); + + Path patchClasses = prepareIOPatch(current); + + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeFile(src.resolve("Test.java"), + """ + public class Test { + public static void main(String... args) { + List l = new ArrayList<>(); + println("Hello, World!"); + } + } + """); + + Files.createDirectories(classes); + + var log = new JavacTask(tb) + .options("--enable-preview", "--release", SOURCE_VERSION, + "--patch-module", "java.base=" + patchClasses, + "-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + var expectedLog = List.of( + "Test.java:3:9: compiler.err.cant.resolve.location: kindname.class, List, , , (compiler.misc.location: kindname.class, Test, null)", + "Test.java:3:30: compiler.err.cant.resolve.location: kindname.class, ArrayList, , , (compiler.misc.location: kindname.class, Test, null)", + "Test.java:4:9: compiler.err.cant.resolve.location.args: kindname.method, println, , java.lang.String, (compiler.misc.location: kindname.class, Test, null)", + "3 errors" + ); + + if (!Objects.equals(expectedLog, log)) { + throw new AssertionError("Incorrect Output, expected: " + expectedLog + + ", actual: " + log); + + } + } + + private Path prepareIOPatch(Path base) throws IOException { + Path patchSrc = base.resolve("patch-src"); + Path patchClasses = base.resolve("patch-classes"); + tb.writeJavaFiles(patchSrc, + """ + package java.io; + public class IO { + public static void println(Object o) { + System.out.println(o); + } + } + """); + + Files.createDirectories(patchClasses); + + new JavacTask(tb) + .options("--patch-module", "java.base=" + patchSrc) + .outdir(patchClasses) + .files(tb.findJavaFiles(patchSrc)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + return patchClasses; + } + + @Test + public void testWithExplicitImport(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeFile(src.resolve("Test.java"), + """ + import java.lang.*; + public static void main(String... args) { + List l = new ArrayList<>(); + System.out.println(l.getClass().getName()); + } + """); + + Files.createDirectories(classes); + + new JavacTask(tb) + .options("--enable-preview", "--release", SOURCE_VERSION) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + var out = new JavaTask(tb) + .classpath(classes.toString()) + .className("Test") + .vmOptions("--enable-preview") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + var expectedOut = List.of("java.util.ArrayList"); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } +} diff --git a/test/langtools/tools/javac/MethodParameters/ClassFileVisitor.java b/test/langtools/tools/javac/MethodParameters/ClassFileVisitor.java index 610256064142a..3e2d151808f2f 100644 --- a/test/langtools/tools/javac/MethodParameters/ClassFileVisitor.java +++ b/test/langtools/tools/javac/MethodParameters/ClassFileVisitor.java @@ -95,7 +95,7 @@ void visitClass(final String cname, final File cfile, final StringBuilder sb) th isStatic = false; isAnon = false; - classFile.findAttribute(Attributes.INNER_CLASSES).ifPresent(this::visitInnerClasses); + classFile.findAttribute(Attributes.innerClasses()).ifPresent(this::visitInnerClasses); isAnon = isInner & isAnon; sb.append(isStatic ? "static " : "") diff --git a/test/langtools/tools/javac/MethodParameters/LegacyOutputTest/LegacyOutputTest.java b/test/langtools/tools/javac/MethodParameters/LegacyOutputTest/LegacyOutputTest.java index 3f613be7e82fe..dad79da509e67 100644 --- a/test/langtools/tools/javac/MethodParameters/LegacyOutputTest/LegacyOutputTest.java +++ b/test/langtools/tools/javac/MethodParameters/LegacyOutputTest/LegacyOutputTest.java @@ -86,7 +86,7 @@ List getParameterNames(String release) throws Exception { } ClassModel classFile = ClassFile.of().parse(Paths.get("Test.class")); MethodModel method = getMethod(classFile, "f"); - MethodParametersAttribute attribute = method.findAttribute(Attributes.METHOD_PARAMETERS).orElse(null); + MethodParametersAttribute attribute = method.findAttribute(Attributes.methodParameters()).orElse(null); if (attribute == null) { return null; } diff --git a/test/langtools/tools/javac/MethodParametersTest.java b/test/langtools/tools/javac/MethodParametersTest.java index 5c7a891cdb07a..8ce73671d1fd6 100644 --- a/test/langtools/tools/javac/MethodParametersTest.java +++ b/test/langtools/tools/javac/MethodParametersTest.java @@ -175,8 +175,8 @@ void modifyBaz(boolean flip) throws Exception { if (!baz.methods().get(0).methodName().equalsString("")) throw new Exception("Classfile Baz badly formed: method has name " + baz.methods().get(0).methodName().stringValue()); - MethodParametersAttribute mpattr = baz.methods().get(0).findAttribute(Attributes.METHOD_PARAMETERS).orElse(null); - CodeAttribute cattr = baz.methods().get(0).findAttribute(Attributes.CODE).orElse(null);; + MethodParametersAttribute mpattr = baz.methods().get(0).findAttribute(Attributes.methodParameters()).orElse(null); + CodeAttribute cattr = baz.methods().get(0).findAttribute(Attributes.code()).orElse(null);; if (null == mpattr) throw new Exception("Classfile Baz badly formed: no method parameters info"); if (null == cattr) diff --git a/test/langtools/tools/javac/RequiredParameterFlags/ImplicitParameters.java b/test/langtools/tools/javac/RequiredParameterFlags/ImplicitParameters.java index 64db03abdaeb9..0eb4d1b8a42ae 100644 --- a/test/langtools/tools/javac/RequiredParameterFlags/ImplicitParameters.java +++ b/test/langtools/tools/javac/RequiredParameterFlags/ImplicitParameters.java @@ -195,7 +195,7 @@ public void testCompactConstructor(ClassModel classFile) { } private void checkParameters(MethodModel method, int... parametersFlags) { - MethodParametersAttribute methodParameters = method.findAttribute(Attributes.METHOD_PARAMETERS).orElseThrow(); + MethodParametersAttribute methodParameters = method.findAttribute(Attributes.methodParameters()).orElseThrow(); Assert.checkNonNull(methodParameters, "MethodParameters attribute must be present"); List table = methodParameters.parameters(); Assert.check(table.size() == parametersFlags.length, () -> "Expected " + parametersFlags.length diff --git a/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java b/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java index 72576a7fcb8be..8ec49a17c4d3a 100644 --- a/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java +++ b/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java @@ -24,13 +24,12 @@ import jdk.test.lib.compiler.CompilerUtils; import toolbox.ToolBox; -import java.lang.classfile.Attributes; import java.lang.classfile.BootstrapMethodEntry; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassModel; import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeModel; import java.lang.classfile.MethodModel; -import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.constantpool.MethodHandleEntry; import java.lang.classfile.instruction.InvokeDynamicInstruction; import java.nio.file.Path; @@ -87,7 +86,7 @@ public static boolean hasStringConcatFactoryCall(Path file, String methodName) t for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString(methodName)) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeModel code = method.code().orElseThrow(); for (CodeElement i : code.elementList()) { if (i instanceof InvokeDynamicInstruction indy) { BootstrapMethodEntry bsmSpec = indy.invokedynamic().bootstrap(); diff --git a/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java b/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java index 60d54944168dc..174e9721f3fec 100644 --- a/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java +++ b/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java @@ -104,7 +104,7 @@ public static void readIndyTypes() throws Exception { for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString("main")) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement i : code.elementList()) { if (i instanceof InvokeDynamicInstruction) { InvokeDynamicInstruction indy = (InvokeDynamicInstruction) i; diff --git a/test/langtools/tools/javac/StringConcat/access/Test.java b/test/langtools/tools/javac/StringConcat/access/Test.java index 93ee3ec7c3f1f..c4aa54618ea70 100644 --- a/test/langtools/tools/javac/StringConcat/access/Test.java +++ b/test/langtools/tools/javac/StringConcat/access/Test.java @@ -182,7 +182,7 @@ public static void readIndyTypes() throws Exception { for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString("main")) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement i : code.elementList()) { if (i instanceof InvokeDynamicInstruction) { InvokeDynamicEntry indyInfo = ((InvokeDynamicInstruction) i).invokedynamic(); diff --git a/test/langtools/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java b/test/langtools/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java index 53adfe17d18ad..bb486b3238263 100644 --- a/test/langtools/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java +++ b/test/langtools/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java @@ -63,9 +63,9 @@ > void checkClassFile(final Path cfilePath) throws Except ClassModel classFile = ClassFile.of().parse(cfilePath); for (MethodModel method : classFile.methods()) { if ((method.flags().flagsMask() & ClassFile.ACC_BRIDGE) != 0) { - Assert.checkNonNull(method.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS), + Assert.checkNonNull(method.findAttribute(Attributes.runtimeVisibleAnnotations()), "Annotations hasn't been copied to bridge method"); - Assert.checkNonNull(method.findAttribute(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS), + Assert.checkNonNull(method.findAttribute(Attributes.runtimeVisibleParameterAnnotations()), "Annotations hasn't been copied to bridge method"); } } diff --git a/test/langtools/tools/javac/T6970173/DebugPointerAtBadPositionTest.java b/test/langtools/tools/javac/T6970173/DebugPointerAtBadPositionTest.java index 350d03c8c3bb0..56813905ca563 100644 --- a/test/langtools/tools/javac/T6970173/DebugPointerAtBadPositionTest.java +++ b/test/langtools/tools/javac/T6970173/DebugPointerAtBadPositionTest.java @@ -94,8 +94,8 @@ void checkClassFile(final File cfile, String methodToFind) throws Exception { for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString(methodToFind)) { methodFound = true; - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); Assert.check(lnt.lineNumbers().size() == expectedLNT.length, foundLNTLengthDifferentThanExpMsg); int i = 0; diff --git a/test/langtools/tools/javac/T7008643/InlinedFinallyConfuseDebuggersTest.java b/test/langtools/tools/javac/T7008643/InlinedFinallyConfuseDebuggersTest.java index 5f76442471397..839c835c8007c 100644 --- a/test/langtools/tools/javac/T7008643/InlinedFinallyConfuseDebuggersTest.java +++ b/test/langtools/tools/javac/T7008643/InlinedFinallyConfuseDebuggersTest.java @@ -101,8 +101,8 @@ void checkClassFile(final File cfile, String methodToFind) throws Exception { for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString(methodToFind)) { methodFound = true; - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); Assert.check(lnt.lineNumbers().size() == expectedLNT.length, "The LineNumberTable found has a length different to the expected one"); int i = 0; diff --git a/test/langtools/tools/javac/T7053059/DoubleCastTest.java b/test/langtools/tools/javac/T7053059/DoubleCastTest.java index 84c39a6cb1670..2aaf5d40f39af 100644 --- a/test/langtools/tools/javac/T7053059/DoubleCastTest.java +++ b/test/langtools/tools/javac/T7053059/DoubleCastTest.java @@ -68,7 +68,7 @@ public static void main(String... cmdline) throws Exception { static void check(MethodModel m) throws Exception { boolean last_is_cast = false; ClassEntry last_ref = null; - CodeAttribute ea = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute ea = m.findAttribute(Attributes.code()).orElseThrow(); for (int i = 0; i < ea.elementList().size(); ++i) { CodeElement ce = ea.elementList().get(i); if (ce instanceof TypeCheckInstruction ins && ins.opcode() == Opcode.CHECKCAST) { diff --git a/test/langtools/tools/javac/T7093325.java b/test/langtools/tools/javac/T7093325.java index 948d775c578e7..0a8fac0692b01 100644 --- a/test/langtools/tools/javac/T7093325.java +++ b/test/langtools/tools/javac/T7093325.java @@ -167,7 +167,7 @@ void verifyBytecode(Result> result) { return; } - CodeAttribute code = test_method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = test_method.findAttribute(Attributes.code()).orElse(null); if (code == null) { fail("Code attribute not found in method test()"); diff --git a/test/langtools/tools/javac/T7165659/InnerClassAttrMustNotHaveStrictFPFlagTest.java b/test/langtools/tools/javac/T7165659/InnerClassAttrMustNotHaveStrictFPFlagTest.java index fc4aae5a0ae46..d7b823d94ec2f 100644 --- a/test/langtools/tools/javac/T7165659/InnerClassAttrMustNotHaveStrictFPFlagTest.java +++ b/test/langtools/tools/javac/T7165659/InnerClassAttrMustNotHaveStrictFPFlagTest.java @@ -48,7 +48,7 @@ private void run() throws Exception { void analyzeClassFile(File path) throws Exception { ClassModel classFile = ClassFile.of().parse(path.toPath()); - InnerClassesAttribute innerClasses = classFile.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute innerClasses = classFile.findAttribute(Attributes.innerClasses()).orElse(null); assert innerClasses != null; for (InnerClassInfo classInfo : innerClasses.classes()) { Assert.check(classInfo.flagsMask() != ClassFile.ACC_STRICT, diff --git a/test/langtools/tools/javac/T8019486/WrongLNTForLambdaTest.java b/test/langtools/tools/javac/T8019486/WrongLNTForLambdaTest.java index 7c334d35f7c92..24c9b81c96471 100644 --- a/test/langtools/tools/javac/T8019486/WrongLNTForLambdaTest.java +++ b/test/langtools/tools/javac/T8019486/WrongLNTForLambdaTest.java @@ -163,8 +163,8 @@ void checkClassFile(final File cfile, String methodToFind, int[][] expectedLNT) for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString(methodToFind)) { methodFound = true; - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); Assert.check(lnt.lineNumbers().size() == expectedLNT.length, "The LineNumberTable found has a length different to the expected one"); int i = 0; diff --git a/test/langtools/tools/javac/T8022186/DeadCodeGeneratedForEmptyTryTest.java b/test/langtools/tools/javac/T8022186/DeadCodeGeneratedForEmptyTryTest.java index d3b6851f87bac..8dd87820423ac 100644 --- a/test/langtools/tools/javac/T8022186/DeadCodeGeneratedForEmptyTryTest.java +++ b/test/langtools/tools/javac/T8022186/DeadCodeGeneratedForEmptyTryTest.java @@ -64,7 +64,7 @@ void checkClassFile(final Path path) throws Exception { constantPool = classFile.constantPool(); for (MethodModel method: classFile.methods()) { if (method.methodName().equalsString("methodToLookFor")) { - CodeAttribute codeAtt = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAtt = method.findAttribute(Attributes.code()).orElseThrow(); codeAtt.elementList().stream() .filter(ce -> ce instanceof Instruction) .forEach(ins -> checkIndirectRefToString((Instruction) ins)); diff --git a/test/langtools/tools/javac/T8024039/NoDeadCodeGenerationOnTrySmtTest.java b/test/langtools/tools/javac/T8024039/NoDeadCodeGenerationOnTrySmtTest.java index 27d01bbf27b49..36afea59094fb 100644 --- a/test/langtools/tools/javac/T8024039/NoDeadCodeGenerationOnTrySmtTest.java +++ b/test/langtools/tools/javac/T8024039/NoDeadCodeGenerationOnTrySmtTest.java @@ -106,7 +106,7 @@ void checkClassFile(final File cfile, String[] methodsToFind) throws Exception { for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString(methodToFind)) { numberOfmethodsFound++; - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); Assert.check(code.exceptionHandlers().size() == expectedExceptionTable.length, "The ExceptionTable found has a length different to the expected one"); int i = 0; diff --git a/test/langtools/tools/javac/T8028504/DontGenerateLVTForGNoneOpTest.java b/test/langtools/tools/javac/T8028504/DontGenerateLVTForGNoneOpTest.java index 90352ba6702b3..150b0fc8c7cbc 100644 --- a/test/langtools/tools/javac/T8028504/DontGenerateLVTForGNoneOpTest.java +++ b/test/langtools/tools/javac/T8028504/DontGenerateLVTForGNoneOpTest.java @@ -52,9 +52,9 @@ void run() throws Exception { void checkClassFile(final File cfile) throws Exception { ClassModel classFile = ClassFile.of().parse(cfile.toPath()); for (MethodModel method : classFile.methods()) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = method.findAttribute(Attributes.code()).orElse(null); if (code != null) { - if (code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElse(null) != null) { + if (code.findAttribute(Attributes.localVariableTable()).orElse(null) != null) { throw new AssertionError("LVT shouldn't be generated for g:none"); } } diff --git a/test/langtools/tools/javac/T8180141/MissingLNTEntryForBreakContinueTest.java b/test/langtools/tools/javac/T8180141/MissingLNTEntryForBreakContinueTest.java index 5ca65bf9ad871..1a095ab5301e6 100644 --- a/test/langtools/tools/javac/T8180141/MissingLNTEntryForBreakContinueTest.java +++ b/test/langtools/tools/javac/T8180141/MissingLNTEntryForBreakContinueTest.java @@ -92,8 +92,8 @@ void testFor(String id, String statement) throws Throwable { ClassModel classFile = ClassFile.of().parse(file.toPath()); for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString("foo")) { - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); checkLNT(lnt, MyAttr.lineNumber); } } diff --git a/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java b/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java index 504057ed7be7a..1cd9ee211e0e1 100644 --- a/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java +++ b/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java @@ -88,8 +88,8 @@ void test() throws Throwable { ClassModel classFile = ClassFile.of().parse(file.toPath()); for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString("foo")) { - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); checkLNT(lnt, MyAttr.lineNumber); } } diff --git a/test/langtools/tools/javac/T8210435/NoLocalsMustBeReservedForDCEedVarsTest.java b/test/langtools/tools/javac/T8210435/NoLocalsMustBeReservedForDCEedVarsTest.java index 69819dd845ef3..35ccb627b4402 100644 --- a/test/langtools/tools/javac/T8210435/NoLocalsMustBeReservedForDCEedVarsTest.java +++ b/test/langtools/tools/javac/T8210435/NoLocalsMustBeReservedForDCEedVarsTest.java @@ -68,7 +68,7 @@ void run() throws Exception { ClassModel classFile = ClassFile.of().parse(cfile.toPath()); for (MethodModel method: classFile.methods()) { if (method.methodName().stringValue().equals("foo")) { - CodeAttribute codeAttr = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute codeAttr = method.findAttribute(Attributes.code()).orElse(null); assert codeAttr != null; Assert.check(codeAttr.maxLocals() == 0, "max locals found " + codeAttr.maxLocals()); } diff --git a/test/langtools/tools/javac/T8222949/TestConstantDynamic.java b/test/langtools/tools/javac/T8222949/TestConstantDynamic.java index 79e1fbb047ff0..d6f728eda5a3b 100644 --- a/test/langtools/tools/javac/T8222949/TestConstantDynamic.java +++ b/test/langtools/tools/javac/T8222949/TestConstantDynamic.java @@ -186,7 +186,7 @@ void verifyBytecode(Result> res) { fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; @@ -216,7 +216,7 @@ void verifyBytecode(Result> res) { return; } - BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bsm_attr.bootstrapMethods().size() != 1) { fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); @@ -251,7 +251,7 @@ void verifyBytecode(Result> res) { return; } - LineNumberTableAttribute lnt = ea.findAttribute(Attributes.LINE_NUMBER_TABLE).orElse(null); + LineNumberTableAttribute lnt = ea.findAttribute(Attributes.lineNumberTable()).orElse(null); if (lnt == null) { fail("No LineNumberTable attribute"); diff --git a/test/langtools/tools/javac/TryWithResources/TwrSimpleClose.java b/test/langtools/tools/javac/TryWithResources/TwrSimpleClose.java index 45e30cd451678..4c1e3a4827518 100644 --- a/test/langtools/tools/javac/TryWithResources/TwrSimpleClose.java +++ b/test/langtools/tools/javac/TryWithResources/TwrSimpleClose.java @@ -101,7 +101,7 @@ void run(String trySpec, int expectedCloseCount) throws Exception { ClassModel cf = ClassFile.of().parse(new ByteArrayInputStream(data).readAllBytes()); for (MethodModel m : cf.methods()) { - CodeAttribute codeAttr = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = m.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : codeAttr.elementList()) { if (ce instanceof InvokeInstruction ins && ins.opcode() == Opcode.INVOKEVIRTUAL) { MemberRefEntry method = ins.method(); diff --git a/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java b/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java index 30d8a579b40ce..0bc65af8aa165 100644 --- a/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java +++ b/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java @@ -63,21 +63,21 @@ public static void main(String... args) throws Exception { if (methodName.equals("toString") || methodName.equals("hashCode") || methodName.equals("equals") || methodName.equals("main")) { // ignore } else if (methodName.equals("")) { - var paAnnos = mm.findAttribute(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS).orElseThrow().parameterAnnotations(); + var paAnnos = mm.findAttribute(Attributes.runtimeVisibleParameterAnnotations()).orElseThrow().parameterAnnotations(); Assert.check(paAnnos.size() > 0); for (var pa : paAnnos) { Assert.check(pa.size() == 1); Assert.check(Objects.equals(pa.get(0).classSymbol().descriptorString(), "LParameterAnnotation;")); } } else { - var annos = mm.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElseThrow().annotations(); + var annos = mm.findAttribute(Attributes.runtimeVisibleAnnotations()).orElseThrow().annotations(); Assert.check(annos.size() == 1); Assert.check(Objects.equals(annos.get(0).classSymbol().descriptorString(), "LMethodAnnotation;")); } } Assert.check(cm.fields().size() > 0); for (FieldModel fm : cm.fields()) { - var annos = fm.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElseThrow().annotations(); + var annos = fm.findAttribute(Attributes.runtimeVisibleAnnotations()).orElseThrow().annotations(); Assert.check(annos.size() == 1); Assert.check(Objects.equals(annos.getFirst().classSymbol().descriptorString(), "LFieldAnnotation;")); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java index 2f6ac3a47172e..6d2aabaee80c6 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java @@ -197,15 +197,15 @@ void checkFields(ClassModel classFile, int... positions) { // utility methods void findAnnotations(ClassModel cm, AttributedElement m, List annos) { - findAnnotations(cm, m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, annos); - findAnnotations(cm, m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, annos); + findAnnotations(cm, m, Attributes.runtimeVisibleTypeAnnotations(), annos); + findAnnotations(cm, m, Attributes.runtimeInvisibleTypeAnnotations(), annos); } > void findAnnotations(ClassModel cf, AttributedElement m, AttributeMapper attrName, List annos) { Attribute attr = m.findAttribute(attrName).orElse(null); addAnnos(annos, attr); if (m instanceof MethodModel) { - CodeAttribute cattr = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cattr = m.findAttribute(Attributes.code()).orElse(null); if (cattr != null) { attr = cattr.findAttribute(attrName).orElse(null); addAnnos(annos, attr); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/VariablesDeclaredWithVarTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/VariablesDeclaredWithVarTest.java index ffd45ddfca41c..7384f4bd5d733 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/VariablesDeclaredWithVarTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/VariablesDeclaredWithVarTest.java @@ -110,15 +110,15 @@ void checkClassFile(final File cfile, int... taPositions) throws Exception { } void findAnnotations(ClassModel cf, MethodModel m, List annos) { - findAnnotations(cf, m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, annos); - findAnnotations(cf, m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, annos); + findAnnotations(cf, m, Attributes.runtimeVisibleTypeAnnotations(), annos); + findAnnotations(cf, m, Attributes.runtimeInvisibleTypeAnnotations(), annos); } > void findAnnotations(ClassModel cf, AttributedElement m, AttributeMapper attrName, List annos) { Attribute attr = m.findAttribute(attrName).orElse(null); addAnnos(annos, attr); if (m instanceof MethodModel) { - CodeAttribute cattr = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cattr = m.findAttribute(Attributes.code()).orElse(null); if (cattr != null) { attr = cattr.findAttribute(attrName).orElse(null); addAnnos(annos, attr); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java index bf2bfd2a370f5..64c33ed9fd94c 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java @@ -100,7 +100,7 @@ public static void main(String args[]) throws Exception { static void testAnonymousClassDeclaration() throws Exception { ClassModel cm = ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest$1.class")); RuntimeVisibleTypeAnnotationsAttribute rvta = - cm.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null); + cm.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null); assert rvta != null; assertEquals( Set.of( @@ -115,7 +115,7 @@ static void testTopLevelMethod() throws Exception { ClassModel cm = ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest.class")); MethodModel method = findMethod(cm, "f"); Set annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr = method.findAttribute(Attributes.code()).orElse(null); assertEquals( Set.of("@LAnonymousClassTest$TA;(0) NEW, offset=0, location=[INNER_TYPE]"), annotations.stream().map(a -> annotationDebugString(cm, cAttr, a)).collect(toSet())); @@ -126,7 +126,7 @@ static void testInnerClassMethod() throws Exception { ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest$Inner.class")); MethodModel method = findMethod(cm, "g"); Set annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr = method.findAttribute(Attributes.code()).orElse(null); // The annotation needs two INNER_TYPE type path entries to apply to // AnonymousClassTest$Inner$1. assertEquals( @@ -141,7 +141,7 @@ static void testQualifiedSuperType() throws Exception { ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest.class")); MethodModel method = findMethod(cm, "g"); Set annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr = method.findAttribute(Attributes.code()).orElse(null); // Only @TA(4) is propagated to the anonymous class declaration. assertEquals( Set.of("@LAnonymousClassTest$TA;(4) NEW, offset=0, location=[INNER_TYPE]"), @@ -152,7 +152,7 @@ static void testQualifiedSuperType() throws Exception { ClassModel cm = ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest$2.class")); RuntimeVisibleTypeAnnotationsAttribute rvta = - cm.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null); + cm.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null); assert rvta != null; assertEquals( Set.of( @@ -168,14 +168,14 @@ static void testInstanceAndClassInit() throws Exception { ClassModel cm = ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest.class")); MethodModel method = findMethod(cm, ""); Set annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr1 = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr1 = method.findAttribute(Attributes.code()).orElse(null); assertEquals( Set.of("@LAnonymousClassTest$TA;(5) NEW, offset=4, location=[INNER_TYPE]"), annotations.stream().map(a -> annotationDebugString(cm, cAttr1, a)).collect(toSet()) ); method = findMethod(cm, ""); annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr2 = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr2 = method.findAttribute(Attributes.code()).orElse(null); assertEquals( Set.of("@LAnonymousClassTest$TA;(6) NEW, offset=16, location=[INNER_TYPE]"), annotations.stream().map(a -> annotationDebugString(cm, cAttr2, a)).collect(toSet()) ); @@ -184,14 +184,14 @@ static void testInstanceAndClassInit() throws Exception { // Returns the Method's RuntimeVisibleTypeAnnotations, and asserts that there are no RVTIs // erroneously associated with the Method instead of its Code attribute. private static Set getRuntimeVisibleTypeAnnotations(MethodModel method) { - if (method.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null) != null) { + if (method.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null) != null) { throw new AssertionError( "expected no RuntimeVisibleTypeAnnotations attribute on enclosing method"); } - CodeAttribute code = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = method.findAttribute(Attributes.code()).orElse(null); assert code != null; RuntimeVisibleTypeAnnotationsAttribute rvta = - code.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null); + code.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null); assert rvta != null; return new HashSet<>(rvta.annotations()); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java index 4926e15b25845..11abffa8c9186 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java @@ -88,10 +88,10 @@ void test(MethodModel mm ) { // 'local' determines whether to look for annotations in code attribute or not. void test(AttributedElement m, Boolean local) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, local); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, local); - test(m, Attributes.RUNTIME_VISIBLE_ANNOTATIONS, local); - test(m, Attributes.RUNTIME_INVISIBLE_ANNOTATIONS, local); + test(m, Attributes.runtimeVisibleTypeAnnotations(), local); + test(m, Attributes.runtimeInvisibleTypeAnnotations(), local); + test(m, Attributes.runtimeVisibleAnnotations(), local); + test(m, Attributes.runtimeInvisibleAnnotations(), local); } // Test the result of MethodModel.findAttribute according to expectations @@ -164,7 +164,7 @@ > Attribute extractAnnotation(AttributedElement m, Att CodeAttribute cAttr; Attribute attr = null; if (local) { - cAttr = m.findAttribute(Attributes.CODE).orElse(null); + cAttr = m.findAttribute(Attributes.code()).orElse(null); if (cAttr != null) { attr = cAttr.findAttribute(annName).orElse(null); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java index 13082ba9dad9d..ffab642c1d59c 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java @@ -71,8 +71,8 @@ ClassModel getClassFile(String name) throws IOException { void testDeclaration(AttributedElement m) { - testDecl(m, Attributes.RUNTIME_VISIBLE_ANNOTATIONS); - testDecl(m, Attributes.RUNTIME_INVISIBLE_ANNOTATIONS); + testDecl(m, Attributes.runtimeVisibleAnnotations()); + testDecl(m, Attributes.runtimeInvisibleAnnotations()); } // test the result of AttributedElement.findAttribute according to expectations diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java index 59ed653927bd1..fc232d06b6457 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java @@ -63,10 +63,10 @@ public class TestAnonInnerClasses extends ClassfileTestHelper { File testSrc = new File(System.getProperty("test.src")); AttributeMapper [] AnnoAttributes = new AttributeMapper[]{ - Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, - Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, - Attributes.RUNTIME_VISIBLE_ANNOTATIONS, - Attributes.RUNTIME_INVISIBLE_ANNOTATIONS + Attributes.runtimeVisibleTypeAnnotations(), + Attributes.runtimeInvisibleTypeAnnotations(), + Attributes.runtimeVisibleAnnotations(), + Attributes.runtimeInvisibleAnnotations() }; // template for source files @@ -175,7 +175,7 @@ > void test(AttributedElement m) { ((MethodModel) m).methodName().stringValue() : ((FieldModel) m).fieldName().stringValue(); attr = m.findAttribute(AnnoType).orElse(null); //fetch index annotations from code attribute. - CAttr = m.findAttribute(Attributes.CODE).orElse(null); + CAttr = m.findAttribute(Attributes.code()).orElse(null); if (CAttr != null) { cattr = CAttr.findAttribute(AnnoType).orElse(null); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java index 741747a9b4cd0..048c1836664ab 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java @@ -88,7 +88,7 @@ > void test(String clazz, AttributedElement m, AttributeM memberName = mm.methodName().stringValue(); if(codeattr) { //fetch index of and code attribute and annotations from code attribute. - cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + cAttr = mm.findAttribute(Attributes.code()).orElse(null); if(cAttr != null) { attr = cAttr.findAttribute(name).orElse(null); } @@ -99,7 +99,7 @@ > void test(String clazz, AttributedElement m, AttributeM case FieldModel fm -> { memberName = fm.fieldName().stringValue(); if(codeattr) { - cAttr = fm.findAttribute(Attributes.CODE).orElse(null); + cAttr = fm.findAttribute(Attributes.code()).orElse(null); if(cAttr != null) { attr = cAttr.findAttribute(name).orElse(null); } @@ -207,14 +207,14 @@ public void run() { assert cm != null; if(clazz.startsWith("Test1")) { for (FieldModel fm: cm.fields()) - test(clazz, fm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, false); + test(clazz, fm, Attributes.runtimeVisibleTypeAnnotations(), false); for (MethodModel mm: cm.methods()) - test(clazz, mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, false); + test(clazz, mm, Attributes.runtimeVisibleTypeAnnotations(), false); } else { for (FieldModel fm: cm.fields()) - test(clazz, fm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, true); + test(clazz, fm, Attributes.runtimeVisibleTypeAnnotations(), true); for (MethodModel mm: cm.methods()) - test(clazz, mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, true); + test(clazz, mm, Attributes.runtimeVisibleTypeAnnotations(), true); } } report(); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TypeAnnotationPropagationTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TypeAnnotationPropagationTest.java index ae92d7aae0446..9f7873bb2c0b7 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TypeAnnotationPropagationTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TypeAnnotationPropagationTest.java @@ -58,9 +58,9 @@ public void run() throws Exception { } assert f != null; - CodeAttribute cattr = f.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cattr = f.findAttribute(Attributes.code()).orElse(null); assert cattr != null; - RuntimeVisibleTypeAnnotationsAttribute attr = cattr.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null); + RuntimeVisibleTypeAnnotationsAttribute attr = cattr.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null); assert attr != null; List annosPosition = ((TypeAnnotation.LocalVarTarget) attr.annotations().get(0).targetInfo()).table(); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java b/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java index 7e35a081de71d..e2e69a01a491c 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java @@ -37,8 +37,8 @@ public static List extendedAnnotationsOf(ClassModel cm) { /////////////////// Extract type annotations ////////////////// private static void findAnnotations(ClassModel cm, List annos) { - findAnnotations(cm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, annos); - findAnnotations(cm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, annos); + findAnnotations(cm, Attributes.runtimeVisibleTypeAnnotations(), annos); + findAnnotations(cm, Attributes.runtimeInvisibleTypeAnnotations(), annos); for (FieldModel f : cm.fields()) { findAnnotations(f, annos); @@ -49,8 +49,8 @@ private static void findAnnotations(ClassModel cm, List annos) { } private static void findAnnotations(AttributedElement ae, List annos) { - findAnnotations(ae, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, annos); - findAnnotations(ae, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, annos); + findAnnotations(ae, Attributes.runtimeVisibleTypeAnnotations(), annos); + findAnnotations(ae, Attributes.runtimeInvisibleTypeAnnotations(), annos); } // test the result of Attributes.getIndex according to expectations @@ -78,7 +78,7 @@ private static > void findAnnotations(AttributedElement m } else throw new AssertionError(); } if (m instanceof MethodModel mm) { - CodeAttribute cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr = mm.findAttribute(Attributes.code()).orElse(null); if (cAttr != null) { Attribute attr2 = cAttr.findAttribute(attrName).orElse(null);; if (attr2 != null) { diff --git a/test/langtools/tools/javac/cast/intersection/DuplicatedCheckcastTest.java b/test/langtools/tools/javac/cast/intersection/DuplicatedCheckcastTest.java index e8e947d408cba..544314832e8de 100644 --- a/test/langtools/tools/javac/cast/intersection/DuplicatedCheckcastTest.java +++ b/test/langtools/tools/javac/cast/intersection/DuplicatedCheckcastTest.java @@ -100,7 +100,7 @@ private void duplicateCheckCastHelper(String source, String expected1, String ex ArrayList checkCastList = new ArrayList<>(); for (MethodModel method : cf.methods()) { if (method.methodName().equalsString("test")) { - CodeAttribute code_attribute = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = method.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : code_attribute.elementList()) { if (ce instanceof Instruction instruction && Opcode.CHECKCAST == instruction.opcode()) { checkCastList.add(instruction); diff --git a/test/langtools/tools/javac/classfiles/InnerClasses/SyntheticClasses.java b/test/langtools/tools/javac/classfiles/InnerClasses/SyntheticClasses.java index bab02ade067a5..eca1b840b3a81 100644 --- a/test/langtools/tools/javac/classfiles/InnerClasses/SyntheticClasses.java +++ b/test/langtools/tools/javac/classfiles/InnerClasses/SyntheticClasses.java @@ -47,14 +47,14 @@ private void run() throws IOException { for (File classFile : Objects.requireNonNull(testClasses.listFiles(f -> f.getName().endsWith(".class")))) { ClassModel cf = ClassFile.of().parse(classFile.toPath()); if (cf.thisClass().asInternalName().matches(".*\\$[0-9]+")) { - EnclosingMethodAttribute encl = cf.findAttribute(Attributes.ENCLOSING_METHOD).orElse(null); + EnclosingMethodAttribute encl = cf.findAttribute(Attributes.enclosingMethod()).orElse(null); if (encl != null) { if (encl.enclosingMethodName().isPresent()) throw new IllegalStateException("Invalid EnclosingMethod.method: " + encl.enclosingMethodName().get().stringValue() + "."); } } - InnerClassesAttribute attr = cf.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute attr = cf.findAttribute(Attributes.innerClasses()).orElse(null); if (attr != null) { for (InnerClassInfo info : attr.classes()) { if (cf.majorVersion() < 51) diff --git a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultTest.java b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultTest.java index d099c4940f9a2..d9a3320ecc231 100644 --- a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultTest.java @@ -77,7 +77,7 @@ private void test(String template, Map replacements, boolean has String methodName = method.methodName().stringValue(); printf("Testing method : %s\n", methodName); AnnotationDefaultAttribute attr = - method.findAttribute(Attributes.ANNOTATION_DEFAULT).orElse(null); + method.findAttribute(Attributes.annotationDefault()).orElse(null); if (hasDefault && !checkNotNull(attr, "Attribute is not null") || !hasDefault && checkNull(attr, "Attribute is null")) { diff --git a/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java b/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java index d34d3a7db0570..b555014bebe67 100644 --- a/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java @@ -163,7 +163,7 @@ private void testEnclosingMethodAttribute() { checkEquals(countEnclosingMethodAttributes(classFile), 1l, "number of the EnclosingMethod attribute in the class is one : " + clazz); - EnclosingMethodAttribute attr = classFile.findAttribute(Attributes.ENCLOSING_METHOD).orElse(null); + EnclosingMethodAttribute attr = classFile.findAttribute(Attributes.enclosingMethod()).orElse(null); if (!checkNotNull(attr, "the EnclosingMethod attribute is not null : " + className)) { // stop checking, attr is null. test case failed diff --git a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java index f9227dde4df6f..be4a5aaea91e0 100644 --- a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java @@ -72,15 +72,15 @@ protected void test(List testCases) throws Exception { classFile = ClassFile.of().parse(input.readAllBytes()); } for (MethodModel m : classFile.methods()) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElse(null); assert code_attribute != null; assertEquals( - countAttributes(Attributes.LINE_NUMBER_TABLE, code_attribute), + countAttributes(Attributes.lineNumberTable(), code_attribute), 1, "Can be more than one LNT attribute, but javac should generate only one."); - LineNumberTableAttribute tableAttribute = code_attribute.findAttribute(Attributes.LINE_NUMBER_TABLE).orElse(null); + LineNumberTableAttribute tableAttribute = code_attribute.findAttribute(Attributes.lineNumberTable()).orElse(null); assert tableAttribute != null; checkAttribute(testCase, tableAttribute, code_attribute.codeLength()); Set methodCoveredLines = diff --git a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java index dade8e984304f..934a0ef09e76a 100644 --- a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java +++ b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java @@ -24,10 +24,10 @@ public static void main(String[] args) throws IOException { Set expectedLineNumbers = new HashSet<>(Arrays.asList(49, 50, 47, 48)); for (MethodModel m : someTestIn.methods()) { if (m.methodName().equalsString("method")) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElse(null); assert code_attribute != null; for (Attribute at : code_attribute.attributes()) { - if (Attributes.LINE_NUMBER_TABLE.equals(at)) { + if (Attributes.lineNumberTable().equals(at)) { assert at instanceof LineNumberTableAttribute; LineNumberTableAttribute att = (LineNumberTableAttribute) at; Set actualLinesNumbers = Arrays.stream(att.lineNumbers().toArray(new LineNumberInfo[0])) diff --git a/test/langtools/tools/javac/classfiles/attributes/LocalVariableTable/LocalVariableTestBase.java b/test/langtools/tools/javac/classfiles/attributes/LocalVariableTable/LocalVariableTestBase.java index 9d2e19c86bafa..7bda1500b3e2f 100644 --- a/test/langtools/tools/javac/classfiles/attributes/LocalVariableTable/LocalVariableTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/LocalVariableTable/LocalVariableTestBase.java @@ -104,7 +104,7 @@ public void test(String methodName, Map expectedLocals2Types, Ma String mName = m.methodName().stringValue(); if (methodName.equals(mName)) { System.out.println("Testing local variable table in method " + mName); - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElse(null); assert code_attribute != null; List variableTables = getVariableTables(code_attribute); generalLocalVariableTableCheck(variableTables); diff --git a/test/langtools/tools/javac/classfiles/attributes/Module/ModuleTestBase.java b/test/langtools/tools/javac/classfiles/attributes/Module/ModuleTestBase.java index 8f7e5c042504d..490e585e06a53 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Module/ModuleTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/Module/ModuleTestBase.java @@ -70,7 +70,7 @@ protected void run() throws Exception { protected void testModuleAttribute(Path modulePath, ModuleDescriptor moduleDescriptor) throws Exception { ClassModel classFile = ClassFile.of().parse(modulePath.resolve("module-info.class")); - ModuleAttribute moduleAttribute = classFile.findAttribute(Attributes.MODULE).orElse(null); + ModuleAttribute moduleAttribute = classFile.findAttribute(Attributes.module()).orElse(null); assert moduleAttribute != null; testModuleName(moduleDescriptor, moduleAttribute); testModuleFlags(moduleDescriptor, moduleAttribute); diff --git a/test/langtools/tools/javac/classfiles/attributes/Signature/Driver.java b/test/langtools/tools/javac/classfiles/attributes/Signature/Driver.java index 4e565cde4239a..72f7d2a6b9b6b 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Signature/Driver.java +++ b/test/langtools/tools/javac/classfiles/attributes/Signature/Driver.java @@ -134,7 +134,7 @@ public void test() throws TestFailedException { // test class signature testAttribute( className, - () -> classFile.findAttribute(Attributes.SIGNATURE).orElse(null), + () -> classFile.findAttribute(Attributes.signature()).orElse(null), getClassExpectedSignature(className, clazz).get(className)); testFields(getExpectedFieldSignatures(clazz), classFile); @@ -173,7 +173,7 @@ private void testMethods(Map expectedSignatures, Clas } testAttribute( methodName, - () -> method.findAttribute(Attributes.SIGNATURE).orElse(null), + () -> method.findAttribute(Attributes.signature()).orElse(null), expectedSignatures.get(methodName)); foundMethods.add(methodName); } @@ -204,7 +204,7 @@ private void testFields(Map expectedSignatures, Class printf("Testing field %s\n", fieldName); testAttribute( fieldName, - () -> field.findAttribute(Attributes.SIGNATURE).orElse(null), + () -> field.findAttribute(Attributes.signature()).orElse(null), expectedSignatures.get(fieldName)); foundFields.add(fieldName); } diff --git a/test/langtools/tools/javac/classfiles/attributes/SourceFile/NoSourceFileAttribute.java b/test/langtools/tools/javac/classfiles/attributes/SourceFile/NoSourceFileAttribute.java index af9e603c964b6..d4a4972f135da 100644 --- a/test/langtools/tools/javac/classfiles/attributes/SourceFile/NoSourceFileAttribute.java +++ b/test/langtools/tools/javac/classfiles/attributes/SourceFile/NoSourceFileAttribute.java @@ -48,7 +48,7 @@ public static void main(String[] args) throws Exception { public void test() throws IOException { assertNull( - ClassFile.of().parse(getClassFile(NoSourceFileAttribute.class).toPath()).findAttribute(Attributes.SOURCE_FILE).orElse(null), + ClassFile.of().parse(getClassFile(NoSourceFileAttribute.class).toPath()).findAttribute(Attributes.sourceFile()).orElse(null), "Classfile should have no SourceFile attribute when compiled without debug information."); } } diff --git a/test/langtools/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java b/test/langtools/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java index f827873588ec6..52d53f9dce4e3 100644 --- a/test/langtools/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java @@ -108,7 +108,7 @@ private void assertAttributePresent(ClassModel classFile, String fileName) throw SourceFileAttribute attribute = sourceFileAttributes.get(0); - assertEquals(attribute.attributeName(), Attributes.SOURCE_FILE.name(), "Incorrect attribute name"); + assertEquals(attribute.attributeName(), Attributes.sourceFile().name(), "Incorrect attribute name"); assertEquals(attribute.sourceFile().stringValue(), fileName, "Incorrect source file name"); assertEquals(((BoundAttribute)attribute).payloadLen(), 2, "Incorrect attribute length"); diff --git a/test/langtools/tools/javac/classfiles/attributes/Synthetic/SyntheticTestDriver.java b/test/langtools/tools/javac/classfiles/attributes/Synthetic/SyntheticTestDriver.java index 406df68a7fe21..4db2585355ef8 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Synthetic/SyntheticTestDriver.java +++ b/test/langtools/tools/javac/classfiles/attributes/Synthetic/SyntheticTestDriver.java @@ -118,7 +118,7 @@ public void test(int expectedNumberOfSyntheticClasses) throws TestFailedExceptio foundClasses.add(className); if (testAttribute( classFile, - () -> classFile.findAttribute(Attributes.SYNTHETIC).orElse(null), + () -> classFile.findAttribute(Attributes.synthetic()).orElse(null), classFile.flags()::flags, expectedClasses.keySet(), className, @@ -136,7 +136,7 @@ public void test(int expectedNumberOfSyntheticClasses) throws TestFailedExceptio foundMethods.add(methodName); if (testAttribute( classFile, - () -> method.findAttribute(Attributes.SYNTHETIC).orElse(null), + () -> method.findAttribute(Attributes.synthetic()).orElse(null), method.flags()::flags, expectedMethods, methodName, @@ -162,7 +162,7 @@ public void test(int expectedNumberOfSyntheticClasses) throws TestFailedExceptio foundFields.add(fieldName); if (testAttribute( classFile, - () -> field.findAttribute(Attributes.SYNTHETIC).orElse(null), + () -> field.findAttribute(Attributes.synthetic()).orElse(null), field.flags()::flags, expectedFields, fieldName, diff --git a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java index a36a84e5e8f9e..970628be5750a 100644 --- a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java @@ -96,11 +96,11 @@ private void testAttributes( Map actualInvisible = collectAnnotations( member, attributedElement, - Attributes.RUNTIME_INVISIBLE_ANNOTATIONS); + Attributes.runtimeInvisibleAnnotations()); Map actualVisible = collectAnnotations( member, attributedElement, - Attributes.RUNTIME_VISIBLE_ANNOTATIONS); + Attributes.runtimeVisibleAnnotations()); checkEquals(actualInvisible.keySet(), member.getRuntimeInvisibleAnnotations(), "RuntimeInvisibleAnnotations"); diff --git a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java index baf3a599095d2..ef9bd07cd6942 100644 --- a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java @@ -104,10 +104,10 @@ public void test() throws TestFailedException { protected void testAttributes( TestCase.TestMethodInfo testMethod, MethodModel method) { - RuntimeInvisibleParameterAnnotationsAttribute invAttr = method.findAttribute(Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS).orElse(null); - checkNull(invAttr, String.format("%s should be null", Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS)); - RuntimeVisibleParameterAnnotationsAttribute vAttr = method.findAttribute(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS).orElse(null); - checkNull(vAttr, String.format("%s should be null", Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS)); + RuntimeInvisibleParameterAnnotationsAttribute invAttr = method.findAttribute(Attributes.runtimeInvisibleParameterAnnotations()).orElse(null); + checkNull(invAttr, String.format("%s should be null", Attributes.runtimeInvisibleParameterAnnotations())); + RuntimeVisibleParameterAnnotationsAttribute vAttr = method.findAttribute(Attributes.runtimeVisibleParameterAnnotations()).orElse(null); + checkNull(vAttr, String.format("%s should be null", Attributes.runtimeVisibleParameterAnnotations())); } public String generateLambdaSource(TestCase.TestMethodInfo method) { diff --git a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java index 04b1ba2dd54dc..b8c90faf52bec 100644 --- a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java @@ -67,12 +67,12 @@ protected void testAttributes( classFile, testMethod, method, - Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS); + Attributes.runtimeInvisibleParameterAnnotations()); List> actualVisible = collectAnnotations( classFile, testMethod, method, - Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS); + Attributes.runtimeVisibleParameterAnnotations()); List parameters = testMethod.parameters; for (int i = 0; i < parameters.size(); ++i) { diff --git a/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java b/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java index 3f3a5f2a984c9..b3e7339b24087 100644 --- a/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java @@ -84,7 +84,7 @@ private void test(String package_info, String src) { new String[]{"package-info.java", package_info}, new String[]{"notDeprecated.java", src}) .getClasses().get(CLASS_NAME)); - DeprecatedAttribute attr = cm.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = cm.findAttribute(Attributes.deprecated()).orElse(null); checkNull(attr, "Class can not have deprecated attribute : " + CLASS_NAME); } catch (Exception e) { addFailure(e); diff --git a/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java b/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java index ebe77e6905676..425760ea137c6 100644 --- a/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java @@ -243,7 +243,7 @@ private void test(String src) { .findFirst().orElse(null); echo("Testing outer class : " + outerClassName); ClassModel cf = readClassFile(classes.get(outerClassName)); - DeprecatedAttribute attr = cf.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = cf.findAttribute(Attributes.deprecated()).orElse(null); testAttribute(outerClassName, attr, cf); testInnerClasses(cf, classes); testMethods(cf); @@ -255,13 +255,13 @@ private void test(String src) { private void testInnerClasses(ClassModel cf, Map classes) throws IOException { - InnerClassesAttribute innerAttr = cf.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute innerAttr = cf.findAttribute(Attributes.innerClasses()).orElse(null); assert innerAttr != null; for (InnerClassInfo innerClass : innerAttr.classes()) { String innerClassName = innerClass.innerClass().name().stringValue(); echo("Testing inner class : " + innerClassName); ClassModel innerCf = readClassFile(classes.get(innerClassName)); - DeprecatedAttribute attr = innerCf.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = innerCf.findAttribute(Attributes.deprecated()).orElse(null); assert innerClass.innerName().isPresent(); String innerClassSimpleName = innerClass.innerName().get().stringValue(); testAttribute(innerClassSimpleName, attr, innerCf); @@ -276,7 +276,7 @@ private void testMethods(ClassModel cf) { for (MethodModel m : cf.methods()) { String methodName = m.methodName().stringValue(); echo("Testing method : " + methodName); - DeprecatedAttribute attr = m.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = m.findAttribute(Attributes.deprecated()).orElse(null); testAttribute(methodName, attr, cf); } } @@ -285,7 +285,7 @@ private void testFields(ClassModel cm) { for (FieldModel f : cm.fields()) { String fieldName = f.fieldName().stringValue(); echo("Testing field : " + fieldName); - DeprecatedAttribute attr = f.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = f.findAttribute(Attributes.deprecated()).orElse(null); testAttribute(fieldName, attr, cm); } } diff --git a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesHierarchyTest.java b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesHierarchyTest.java index eb7e6f2e2df58..124f46acded94 100644 --- a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesHierarchyTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesHierarchyTest.java @@ -98,7 +98,7 @@ private void test() throws TestFailedException { continue; } ClassModel cf = readClassFile(currentClassName); - InnerClassesAttribute attr = cf.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute attr = cf.findAttribute(Attributes.innerClasses()).orElse(null); checkNotNull(attr, "Class should not contain " + "inner classes attribute : " + currentClassName); checkTrue(innerClasses.containsKey(currentClassName), diff --git a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesIndexTest.java b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesIndexTest.java index 826365a8011a0..96f2efc6ea6e4 100644 --- a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesIndexTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesIndexTest.java @@ -69,7 +69,7 @@ public void test() throws TestFailedException { try { addTestCase("Source is InnerClassesIndexTest.java"); ClassModel classFile = readClassFile(InnerClassesIndexTest.class); - InnerClassesAttribute attr = classFile.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute attr = classFile.findAttribute(Attributes.innerClasses()).orElse(null); Set foundClasses = new HashSet<>(); assert attr != null; diff --git a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesTestBase.java b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesTestBase.java index ca818817b6d69..26972de3544ea 100644 --- a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesTestBase.java @@ -195,7 +195,7 @@ private void test(String classToTest, TestCase test, String...skipClasses) { Map> class2Flags = test.getFlags(); ClassModel cm = readClassFile(compile(getCompileOptions(), test.getSource()) .getClasses().get(classToTest)); - InnerClassesAttribute innerClasses = cm.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute innerClasses = cm.findAttribute(Attributes.innerClasses()).orElse(null); int count = 0; for (Attribute a : cm.attributes()) { if (a instanceof InnerClassesAttribute) { diff --git a/test/langtools/tools/javac/classfiles/attributes/innerclasses/NoInnerClassesTest.java b/test/langtools/tools/javac/classfiles/attributes/innerclasses/NoInnerClassesTest.java index 540bd09a18f49..35d65208bc5df 100644 --- a/test/langtools/tools/javac/classfiles/attributes/innerclasses/NoInnerClassesTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/innerclasses/NoInnerClassesTest.java @@ -47,6 +47,6 @@ public static void main(String[] args) throws IOException { public void test() throws IOException { ClassModel classModel = readClassFile("NoInnerClassesTest"); - assertNull(classModel.findAttribute(Attributes.INNER_CLASSES).orElse(null), "Found inner class attribute"); + assertNull(classModel.findAttribute(Attributes.innerClasses()).orElse(null), "Found inner class attribute"); } } diff --git a/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java b/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java index 8711118b8fd4c..8b5e4e7b695dd 100644 --- a/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java +++ b/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java @@ -165,12 +165,12 @@ public static CallSite bootstrap(Lookup lookup, String name, MethodType type) th Path testClass = classes.resolve("Test.class"); ClassModel cf = ClassFile.of().parse(testClass); - BootstrapMethodsAttribute bootAttr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bootAttr = cf.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bootAttr.bootstrapMethodsSize() != 1) { throw new AssertionError("Incorrect number of bootstrap methods: " + bootAttr.bootstrapMethodsSize()); } - CodeAttribute codeAttr = cf.methods().get(1).findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = cf.methods().get(1).findAttribute(Attributes.code()).orElseThrow(); Set seenBootstraps = new HashSet<>(); Set seenNameAndTypes = new HashSet<>(); Set seenNames = new HashSet<>(); diff --git a/test/langtools/tools/javac/code/CharImmediateValue.java b/test/langtools/tools/javac/code/CharImmediateValue.java index 24f60c5d53920..44e2744b74e5b 100644 --- a/test/langtools/tools/javac/code/CharImmediateValue.java +++ b/test/langtools/tools/javac/code/CharImmediateValue.java @@ -133,7 +133,7 @@ public static String run() { Path testClass = classes.resolve("Test.class"); ClassModel cf = ClassFile.of().parse(testClass); - CodeAttribute codeAttr = cf.methods().get(1).findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = cf.methods().get(1).findAttribute(Attributes.code()).orElseThrow(); boolean seenCast = false; for (CodeElement i : codeAttr.elementList()) { if (i instanceof Instruction ins && ins.opcode() == Opcode.I2C) { diff --git a/test/langtools/tools/javac/defaultMethods/TestDefaultBody.java b/test/langtools/tools/javac/defaultMethods/TestDefaultBody.java index 5cad9ed6293ca..ec4e8b7b558b7 100644 --- a/test/langtools/tools/javac/defaultMethods/TestDefaultBody.java +++ b/test/langtools/tools/javac/defaultMethods/TestDefaultBody.java @@ -67,7 +67,7 @@ void verifyDefaultBody(File f) { MethodModel testMethod = null; CodeAttribute codeAttr = null; for (MethodModel m : cf.methods()) { - codeAttr = m.findAttribute(Attributes.CODE).orElse(null); + codeAttr = m.findAttribute(Attributes.code()).orElse(null); String mname = m.methodName().stringValue(); if (mname.equals(TEST_METHOD_NAME)) { testMethod = m; diff --git a/test/langtools/tools/javac/defaultMethods/super/TestDirectSuperInterfaceInvoke.java b/test/langtools/tools/javac/defaultMethods/super/TestDirectSuperInterfaceInvoke.java index 5e171b3cdf0fd..8be378eaf7b2a 100644 --- a/test/langtools/tools/javac/defaultMethods/super/TestDirectSuperInterfaceInvoke.java +++ b/test/langtools/tools/javac/defaultMethods/super/TestDirectSuperInterfaceInvoke.java @@ -86,7 +86,7 @@ void verifyDefaultBody(String classFile) { try { final ClassModel cf = ClassFile.of().parse(file.toPath()); for (MethodModel m : cf.methods()) { - CodeAttribute codeAttr = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = m.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : codeAttr.elementList()) { if (ce instanceof InvokeInstruction instr && instr.opcode() == Opcode.INVOKESPECIAL) { MemberRefEntry ref = instr.method(); diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index 716301a913ff1..c1c0a0fc9acb5 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -118,7 +118,6 @@ compiler.warn.illegal.char.for.encoding compiler.warn.incubating.modules # requires adjusted classfile compiler.warn.invalid.archive.file compiler.warn.invalid.utf8.in.classfile # bad class file -compiler.warn.is.preview # difficult to produce reliably despite future changes to java.base compiler.warn.is.preview.reflective # difficult to produce reliably despite future changes to java.base compiler.warn.output.file.clash # this warning is not generated on Linux compiler.warn.override.bridge diff --git a/test/langtools/tools/javac/diags/examples/ImplicitClass.java b/test/langtools/tools/javac/diags/examples/ImplicitClass.java index c032bdefeffcd..30285293b1836 100644 --- a/test/langtools/tools/javac/diags/examples/ImplicitClass.java +++ b/test/langtools/tools/javac/diags/examples/ImplicitClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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,9 +21,10 @@ * questions. */ - // key: compiler.misc.feature.implicit.classes - // key: compiler.warn.preview.feature.use.plural - // options: -source ${jdk.version} --enable-preview -Xlint:preview +// key: compiler.misc.feature.implicit.classes +// key: compiler.warn.preview.feature.use.plural +// key: compiler.warn.is.preview +// options: -source ${jdk.version} --enable-preview -Xlint:preview public static void main(String... args) { } diff --git a/test/langtools/tools/javac/expression/_super/NonDirectSuper/NonDirectSuper.java b/test/langtools/tools/javac/expression/_super/NonDirectSuper/NonDirectSuper.java index 05942c567222b..e48793020588f 100644 --- a/test/langtools/tools/javac/expression/_super/NonDirectSuper/NonDirectSuper.java +++ b/test/langtools/tools/javac/expression/_super/NonDirectSuper/NonDirectSuper.java @@ -61,7 +61,7 @@ void verifyInvokeSpecialRefToObject(File clazz) { try { final ClassModel cf = ClassFile.of().parse(clazz.toPath()); for (MethodModel m : cf.methods()) { - CodeAttribute codeAttr = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = m.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : codeAttr.elementList()) { if (ce instanceof InvokeInstruction instr && (instr.opcode() == Opcode.INVOKESPECIAL || instr.opcode() == Opcode.INVOKEVIRTUAL)) { diff --git a/test/langtools/tools/javac/file/SymLinkTest.java b/test/langtools/tools/javac/file/SymLinkTest.java index f9dea1d8bc3c3..45405aac2ee1a 100644 --- a/test/langtools/tools/javac/file/SymLinkTest.java +++ b/test/langtools/tools/javac/file/SymLinkTest.java @@ -95,7 +95,7 @@ void test(Path base, String name) throws Exception{ .writeAll(); ClassModel cf = ClassFile.of().parse(classes.resolve("HelloWorld.class")); - SourceFileAttribute sf = cf.findAttribute(Attributes.SOURCE_FILE).orElseThrow(); + SourceFileAttribute sf = cf.findAttribute(Attributes.sourceFile()).orElseThrow(); String sourceFile = sf.sourceFile().stringValue(); if (!"HelloWorld.java".equals(sourceFile)) { diff --git a/test/langtools/tools/javac/flow/LVTHarness.java b/test/langtools/tools/javac/flow/LVTHarness.java index 6e8afef990311..cd4374d93e2b7 100644 --- a/test/langtools/tools/javac/flow/LVTHarness.java +++ b/test/langtools/tools/javac/flow/LVTHarness.java @@ -138,8 +138,8 @@ void checkClassFile(File file) throws IOException { } void checkMethod(MethodModel method, AliveRanges ranges) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); - LocalVariableTableAttribute lvt = code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); + LocalVariableTableAttribute lvt = code.findAttribute(Attributes.localVariableTable()).orElseThrow(); List infoFromRanges = convertToStringList(ranges); List infoFromLVT = convertToStringList(lvt); diff --git a/test/langtools/tools/javac/lambda/ByteCodeTest.java b/test/langtools/tools/javac/lambda/ByteCodeTest.java index 7a5943935bebf..df5c8df1ff9aa 100644 --- a/test/langtools/tools/javac/lambda/ByteCodeTest.java +++ b/test/langtools/tools/javac/lambda/ByteCodeTest.java @@ -423,7 +423,7 @@ public String visit(PoolEntry c, int index) { } private Map readBSM() { - BootstrapMethodsAttribute bsmAttr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElse(null); + BootstrapMethodsAttribute bsmAttr = cf.findAttribute(Attributes.bootstrapMethods()).orElse(null); if (bsmAttr != null) { Map out = new HashMap<>(bsmAttr.bootstrapMethodsSize()); diff --git a/test/langtools/tools/javac/lambda/LocalVariableTable.java b/test/langtools/tools/javac/lambda/LocalVariableTable.java index 3a6367511994b..e78fed1288aab 100644 --- a/test/langtools/tools/javac/lambda/LocalVariableTable.java +++ b/test/langtools/tools/javac/lambda/LocalVariableTable.java @@ -90,13 +90,13 @@ void check(Class c) throws Exception { return; } - CodeAttribute code = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = m.findAttribute(Attributes.code()).orElse(null); if (code == null) { error("Code attribute not found"); return; } - LocalVariableTableAttribute lvt = code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElse(null); + LocalVariableTableAttribute lvt = code.findAttribute(Attributes.localVariableTable()).orElse(null); if (lvt == null) { error("LocalVariableTable attribute not found"); return; diff --git a/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java b/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java index c8b405b706adf..1220bf4dfa415 100644 --- a/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java +++ b/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java @@ -112,7 +112,7 @@ void verifyBytecode() { File compiledTest = new File("Test.class"); try { ClassModel cf = ClassFile.of().parse(compiledTest.toPath()); - BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); int length = bsm_attr.bootstrapMethodsSize(); if (length != 1) { throw new Error("Bad number of method specifiers " + diff --git a/test/langtools/tools/javac/lambda/TestInvokeDynamic.java b/test/langtools/tools/javac/lambda/TestInvokeDynamic.java index 56bb63fc2c990..05c304cdd31c0 100644 --- a/test/langtools/tools/javac/lambda/TestInvokeDynamic.java +++ b/test/langtools/tools/javac/lambda/TestInvokeDynamic.java @@ -265,7 +265,7 @@ void verifyBytecode(Result> res) { fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; @@ -289,7 +289,7 @@ void verifyBytecode(Result> res) { } BootstrapMethodsAttribute bsm_attr = cm - .findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + .findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bsm_attr.bootstrapMethodsSize() != 1) { fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); @@ -337,7 +337,7 @@ void verifyBytecode(Result> res) { return; } - LineNumberTableAttribute lnt = ea.findAttribute(Attributes.LINE_NUMBER_TABLE).orElse(null); + LineNumberTableAttribute lnt = ea.findAttribute(Attributes.lineNumberTable()).orElse(null); if (lnt == null) { fail("No LineNumberTable attribute"); diff --git a/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java index dd63748936102..c19c848ee6845 100644 --- a/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java +++ b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java @@ -218,7 +218,7 @@ void verifyBytecode(Result> res) { fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; @@ -243,7 +243,7 @@ void verifyBytecode(Result> res) { return; } - BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bsm_attr.bootstrapMethodsSize() != 1) { fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); diff --git a/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java index 2ac3e322970e6..326de3168b39a 100644 --- a/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java +++ b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java @@ -220,7 +220,7 @@ void verifyBytecode(Result> res) { fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; @@ -245,7 +245,7 @@ void verifyBytecode(Result> res) { return; } - BootstrapMethodsAttribute bsm_attr = cm.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm_attr = cm.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bsm_attr.bootstrapMethodsSize() != 1) { fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); diff --git a/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java b/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java index fddf11b57e4f0..8d948c55e7d70 100644 --- a/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java +++ b/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java @@ -145,7 +145,7 @@ public static void main(String[] args) throws Exception { if (cm.thisClass().asInternalName().equals("com/sun/tools/javac/comp/Deduplication$R")) { continue; } - BootstrapMethodsAttribute bsm = cm.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm = cm.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); for (BootstrapMethodEntry b : bsm.bootstrapMethods()) { bootstrapMethodNames.add( ((MethodHandleEntry)b.arguments().get(1)) diff --git a/test/langtools/tools/javac/launcher/ModuleSourceLauncherTests.java b/test/langtools/tools/javac/launcher/ModuleSourceLauncherTests.java index 908674eb6920a..ebb39e2dccf47 100644 --- a/test/langtools/tools/javac/launcher/ModuleSourceLauncherTests.java +++ b/test/langtools/tools/javac/launcher/ModuleSourceLauncherTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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,7 +23,7 @@ /* * @test - * @bug 8304400 + * @bug 8304400 8332226 * @summary Test source launcher running Java programs contained in one module * @modules jdk.compiler/com.sun.tools.javac.launcher * @run junit ModuleSourceLauncherTests @@ -112,6 +112,8 @@ public static void main(String... args) throws Exception { Files.writeString(barFolder.resolve("Bar.java"), "package bar; public record Bar() {}"); var bazFolder = Files.createDirectories(base.resolve("baz")); Files.writeString(bazFolder.resolve("baz.txt"), "baz"); + var badFolder = Files.createDirectories(base.resolve(".bad")); + Files.writeString(badFolder.resolve("bad.txt"), "bad"); Files.writeString(base.resolve("module-info.java"), """ @@ -140,8 +142,11 @@ public static void main(String... args) throws Exception { assertEquals("m", module.getName()); var reference = module.getLayer().configuration().findModule(module.getName()).orElseThrow().reference(); try (var reader = reference.open()) { + var actual = reader.list().toList(); assertLinesMatch( """ + .bad/ + .bad/bad.txt bar/ bar/Bar.class bar/Bar.java @@ -152,8 +157,8 @@ public static void main(String... args) throws Exception { foo/Main.java module-info.class module-info.java - """.lines(), - reader.list()); + """.lines().toList(), + actual, "Actual lines -> " + actual); } } diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 6534f9f4dd09b..5f558d421ff0f 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -743,8 +743,8 @@ public void testNoDuplicateIncubatorWarning(Path base) throws Exception { private static void markModuleAsIncubator(Path moduleInfoFile) throws Exception { ClassModel cf = ClassFile.of().parse(moduleInfoFile); ModuleResolutionAttribute newAttr = ModuleResolutionAttribute.of(WARN_INCUBATING); - byte[] newBytes = ClassFile.of().transform(cf, ClassTransform.dropping(ce -> ce instanceof Attributes) - .andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(newAttr)))); + byte[] newBytes = ClassFile.of().transform(cf, + ClassTransform.endHandler(classBuilder -> classBuilder.with(newAttr))); try (OutputStream out = Files.newOutputStream(moduleInfoFile)) { out.write(newBytes); } diff --git a/test/langtools/tools/javac/linenumbers/ConditionalLineNumberTest.java b/test/langtools/tools/javac/linenumbers/ConditionalLineNumberTest.java index 2727c9bdbd82e..c44def8498775 100644 --- a/test/langtools/tools/javac/linenumbers/ConditionalLineNumberTest.java +++ b/test/langtools/tools/javac/linenumbers/ConditionalLineNumberTest.java @@ -54,7 +54,7 @@ static List findEntries() throws IOException { ClassModel self = ClassFile.of().parse(ConditionalLineNumberTest.class.getResourceAsStream("ConditionalLineNumberTest.class").readAllBytes()); for (MethodModel m : self.methods()) { if (m.methodName().equalsString("method")) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElse(null); assert code_attribute != null; for (Attribute at : code_attribute.attributes()) { if (at instanceof LineNumberTableAttribute) { diff --git a/test/langtools/tools/javac/linenumbers/FinallyLineNumberTest.java b/test/langtools/tools/javac/linenumbers/FinallyLineNumberTest.java index 0a6f23593c1b1..d150c6bb4b7f3 100644 --- a/test/langtools/tools/javac/linenumbers/FinallyLineNumberTest.java +++ b/test/langtools/tools/javac/linenumbers/FinallyLineNumberTest.java @@ -83,7 +83,7 @@ static List findEntries() throws IOException { ClassModel self = ClassFile.of().parse(FinallyLineNumberTest.class.getResourceAsStream("FinallyLineNumberTest.class").readAllBytes()); for (MethodModel m : self.methods()) { if (m.methodName().equalsString("method")) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElseThrow(); for (Attribute at : code_attribute.attributes()) { if (at instanceof LineNumberTableAttribute lineAt) { return lineAt.lineNumbers(); diff --git a/test/langtools/tools/javac/linenumbers/NestedLineNumberTest.java b/test/langtools/tools/javac/linenumbers/NestedLineNumberTest.java index 481534ec2a048..108a31c23db02 100644 --- a/test/langtools/tools/javac/linenumbers/NestedLineNumberTest.java +++ b/test/langtools/tools/javac/linenumbers/NestedLineNumberTest.java @@ -30,7 +30,7 @@ static List findEntries() throws IOException { ClassModel self = ClassFile.of().parse(NestedLineNumberTest.Test.class.getResourceAsStream("NestedLineNumberTest$Test.class").readAllBytes()); for (MethodModel m : self.methods()) { if ("".equals(m.methodName().stringValue())) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElseThrow(); for (Attribute at : code_attribute.attributes()) { if (at instanceof LineNumberTableAttribute lineAt) { return lineAt.lineNumbers(); diff --git a/test/langtools/tools/javac/linenumbers/NullCheckLineNumberTest.java b/test/langtools/tools/javac/linenumbers/NullCheckLineNumberTest.java index 91c562b2360e9..d74a0e5667b1f 100644 --- a/test/langtools/tools/javac/linenumbers/NullCheckLineNumberTest.java +++ b/test/langtools/tools/javac/linenumbers/NullCheckLineNumberTest.java @@ -63,7 +63,7 @@ static List findEntries() throws IOException { ClassModel self = ClassFile.of().parse(Objects.requireNonNull(Test.class.getResourceAsStream("NullCheckLineNumberTest$Test.class")).readAllBytes()); for (MethodModel m : self.methods()) { if ("".equals(m.methodName().stringValue())) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElseThrow(); for (Attribute at : code_attribute.attributes()) { if (at instanceof LineNumberTableAttribute lineAt) { return lineAt.lineNumbers().stream() diff --git a/test/langtools/tools/javac/meth/TestCP.java b/test/langtools/tools/javac/meth/TestCP.java index 31a5bd1762f3c..bc574134b89f8 100644 --- a/test/langtools/tools/javac/meth/TestCP.java +++ b/test/langtools/tools/javac/meth/TestCP.java @@ -135,7 +135,7 @@ void verifySigPolyInvokeVirtual(File f, String psType) { if (testMethod == null) { throw new Error("Test method not found"); } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { throw new Error("Code attribute for test() method not found"); } diff --git a/test/langtools/tools/javac/modules/AnnotationsOnModules.java b/test/langtools/tools/javac/modules/AnnotationsOnModules.java index 59b48fd49549c..bfae27d4d21db 100644 --- a/test/langtools/tools/javac/modules/AnnotationsOnModules.java +++ b/test/langtools/tools/javac/modules/AnnotationsOnModules.java @@ -86,7 +86,7 @@ public void testSimpleAnnotation(Path base) throws Exception { .writeAll(); ClassModel cf = ClassFile.of().parse(modulePath.resolve("m1x").resolve("module-info.class")); - RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (annotations == null || annotations.annotations().size() != 1) { throw new AssertionError("Annotations not correct!"); @@ -140,13 +140,13 @@ public void testSimpleJavadocDeprecationTag(Path base) throws Exception { } ClassModel cf = ClassFile.of().parse(modulePath.resolve("A").resolve("module-info.class")); - RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (annotations != null && annotations.annotations().size() > 0) { throw new AssertionError("Found annotation attributes. Expected no annotations for javadoc @deprecated tag."); } - if (cf.findAttribute(Attributes.DEPRECATED).isPresent()) { + if (cf.findAttribute(Attributes.deprecated()).isPresent()) { throw new AssertionError("Found Deprecated attribute. Expected no Deprecated attribute for javadoc @deprecated tag."); } } @@ -191,7 +191,7 @@ public void testEnhancedDeprecatedAnnotation(Path base) throws Exception { } ClassModel cf = ClassFile.of().parse(modulePath.resolve("A").resolve("module-info.class")); - RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (annotations == null ) { throw new AssertionError("Annotations not found!"); @@ -314,7 +314,7 @@ public void testAnnotationWithImport(Path base) throws Exception { .writeAll(); ClassModel cf = ClassFile.of().parse(modulePath.resolve("m1x").resolve("module-info.class")); - RuntimeInvisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + RuntimeInvisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (annotations == null || annotations.annotations().size() != 1) { throw new AssertionError("Annotations not correct!"); @@ -356,7 +356,7 @@ public void testAnnotationWithImportFromAnotherModule(Path base) throws Exceptio .writeAll(); ClassModel cf = ClassFile.of().parse(modulePath.resolve("B").resolve("module-info.class")); - RuntimeInvisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + RuntimeInvisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (annotations == null ) { throw new AssertionError("Annotations not found!"); @@ -431,7 +431,7 @@ public void testAnnotationWithoutTarget(Path base) throws Exception { .writeAll(); ClassModel cf = ClassFile.of().parse(classes.resolve("m1x").resolve("module-info.class")); - RuntimeInvisibleAnnotationsAttribute invisibleAnnotations = cf.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + RuntimeInvisibleAnnotationsAttribute invisibleAnnotations = cf.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (invisibleAnnotations == null) { throw new AssertionError("Annotations not found!"); diff --git a/test/langtools/tools/javac/modules/JavaBaseTest.java b/test/langtools/tools/javac/modules/JavaBaseTest.java index 64f914e5d2fff..188bc4801e5cb 100644 --- a/test/langtools/tools/javac/modules/JavaBaseTest.java +++ b/test/langtools/tools/javac/modules/JavaBaseTest.java @@ -206,7 +206,7 @@ void createClass(Path base, List mods, String target) throws Exception { ClassModel cm1 = ClassFile.of().parse(modules1.resolve("module-info.class")); - ModuleAttribute modAttr1 = cm1.findAttribute(Attributes.MODULE).orElseThrow(); + ModuleAttribute modAttr1 = cm1.findAttribute(Attributes.module()).orElseThrow(); List requires = Arrays.asList(new ModuleRequireInfo[modAttr1.requires().size()]); for (int i = 0; i < modAttr1.requires().size(); ++i) { ModuleRequireInfo e1 = modAttr1.requires().get(i); diff --git a/test/langtools/tools/javac/modules/ModuleVersion.java b/test/langtools/tools/javac/modules/ModuleVersion.java index d6b514eee318c..cbf9b82c54cd8 100644 --- a/test/langtools/tools/javac/modules/ModuleVersion.java +++ b/test/langtools/tools/javac/modules/ModuleVersion.java @@ -114,7 +114,7 @@ public void testMultipleModuleVersions(Path base) throws Exception { private void checkModuleVersion(Path classfile, String version) throws IOException { ClassModel cm = ClassFile.of().parse(classfile); - ModuleAttribute moduleAttribute = cm.findAttribute(Attributes.MODULE).orElse(null); + ModuleAttribute moduleAttribute = cm.findAttribute(Attributes.module()).orElse(null); if (moduleAttribute == null) { throw new AssertionError("Version attribute missing!"); diff --git a/test/langtools/tools/javac/modules/OpenModulesTest.java b/test/langtools/tools/javac/modules/OpenModulesTest.java index 4523b72654802..e21601031e73c 100644 --- a/test/langtools/tools/javac/modules/OpenModulesTest.java +++ b/test/langtools/tools/javac/modules/OpenModulesTest.java @@ -233,7 +233,7 @@ public void testNonZeroOpensInOpen(Path base) throws Exception { Path miClass = m1Classes.resolve("module-info.class"); ClassModel cm = ClassFile.of().parse(miClass); - ModuleAttribute module = cm.findAttribute(Attributes.MODULE).orElseThrow(); + ModuleAttribute module = cm.findAttribute(Attributes.module()).orElseThrow(); ModuleAttribute newModule = ModuleAttribute.of(module.moduleName(), module.moduleFlagsMask() | ClassFile.ACC_OPEN, module.moduleVersion().orElse(null), diff --git a/test/langtools/tools/javac/multicatch/7005371/T7005371.java b/test/langtools/tools/javac/multicatch/7005371/T7005371.java index bf83cd26089b1..c99371642a624 100644 --- a/test/langtools/tools/javac/multicatch/7005371/T7005371.java +++ b/test/langtools/tools/javac/multicatch/7005371/T7005371.java @@ -70,11 +70,11 @@ void verifyLocalVariableTypeTableAttr(File f) { if (testMethod == null) { throw new Error("Missing method: " + TEST_METHOD_NAME); } - CodeAttribute code = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = testMethod.findAttribute(Attributes.code()).orElse(null); if (code == null) { throw new Error("Missing Code attribute for method: " + TEST_METHOD_NAME); } - LocalVariableTypeTableAttribute lvt_table = code.findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE).orElse(null); + LocalVariableTypeTableAttribute lvt_table = code.findAttribute(Attributes.localVariableTypeTable()).orElse(null); if (lvt_table == null) { throw new Error("Missing LocalVariableTypeTable attribute for method: " + TEST_METHOD_NAME); } diff --git a/test/langtools/tools/javac/multicatch/Pos05.java b/test/langtools/tools/javac/multicatch/Pos05.java index 1dade792178ba..16ee54f2ccd23 100644 --- a/test/langtools/tools/javac/multicatch/Pos05.java +++ b/test/langtools/tools/javac/multicatch/Pos05.java @@ -90,7 +90,7 @@ void verifyMulticatchExceptionRanges(File f) { if (testMethod == null) { throw new Error("Test method not found"); } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { throw new Error("Code attribute for test() method not found"); } diff --git a/test/langtools/tools/javac/patterns/Annotations.java b/test/langtools/tools/javac/patterns/Annotations.java index f14ab3fb9708f..a471cc57b63e7 100644 --- a/test/langtools/tools/javac/patterns/Annotations.java +++ b/test/langtools/tools/javac/patterns/Annotations.java @@ -67,8 +67,8 @@ void run() throws Exception { ClassModel cf = ClassFile.of().parse(annotationsClass.readAllBytes()); for (MethodModel m : cf.methods()) { if (m.methodName().equalsString("test")) { - CodeAttribute codeAttr = m.findAttribute(Attributes.CODE).orElseThrow(); - RuntimeInvisibleTypeAnnotationsAttribute annotations = codeAttr.findAttribute(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS).orElseThrow(); + CodeAttribute codeAttr = m.findAttribute(Attributes.code()).orElseThrow(); + RuntimeInvisibleTypeAnnotationsAttribute annotations = codeAttr.findAttribute(Attributes.runtimeInvisibleTypeAnnotations()).orElseThrow(); String expected = "LAnnotations$DTA; pos: [LOCAL_VARIABLE, {start_pc=31, end_pc=38, index=1}], " + "LAnnotations$TA; pos: [LOCAL_VARIABLE, {start_pc=50, end_pc=57, index=1}], "; StringBuilder actual = new StringBuilder(); diff --git a/test/langtools/tools/javac/patterns/LocalVariableTable.java b/test/langtools/tools/javac/patterns/LocalVariableTable.java index 9fa29b09065db..37051daf14213 100644 --- a/test/langtools/tools/javac/patterns/LocalVariableTable.java +++ b/test/langtools/tools/javac/patterns/LocalVariableTable.java @@ -87,13 +87,13 @@ void check(Class c) throws Exception { return; } - CodeAttribute code = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = m.findAttribute(Attributes.code()).orElse(null); if (code == null) { error("Code attribute not found"); return; } - LocalVariableTableAttribute lvt = code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElse(null); + LocalVariableTableAttribute lvt = code.findAttribute(Attributes.localVariableTable()).orElse(null); if (lvt == null) { error("LocalVariableTable attribute not found"); return; diff --git a/test/langtools/tools/javac/patterns/NestedPatternVariablesBytecode.java b/test/langtools/tools/javac/patterns/NestedPatternVariablesBytecode.java index 3759676e2c38c..36068729146b2 100644 --- a/test/langtools/tools/javac/patterns/NestedPatternVariablesBytecode.java +++ b/test/langtools/tools/javac/patterns/NestedPatternVariablesBytecode.java @@ -85,7 +85,7 @@ String test(Object o) { .filter(this::isTestMethod) .findAny() .orElseThrow(); - CodeAttribute code_attribute = testMethod.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = testMethod.findAttribute(Attributes.code()).orElseThrow(); List actualCode = getCodeInstructions(code_attribute); List expectedCode = Arrays.asList( diff --git a/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java b/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java index b7e7df089a574..55444e1d7482e 100644 --- a/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java +++ b/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java @@ -71,7 +71,7 @@ void checkClassFile(File file) throws IOException { ICONST_0 IRETURN """; - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); String actualInstructions = printCode(code); if (!expectedInstructions.equals(actualInstructions)) { throw new AssertionError("Unexpected instructions found:\n" + diff --git a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java index 4186b83f2f10e..3d47c4ac9bc72 100644 --- a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java +++ b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8304487 8325653 + * @bug 8304487 8325653 8332463 * @summary Compiler Implementation for Primitive types in patterns, instanceof, and switch (Preview) * @enablePreview * @compile/fail/ref=PrimitivePatternsSwitchErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW PrimitivePatternsSwitchErrors.java @@ -59,7 +59,7 @@ public static int dominationBetweenBoxedAndPrimitive() { int i = 42; return switch (i) { case Integer ib -> ib; - case byte ip -> ip; // Error - dominated! + case byte ip -> ip; // OK - not dominated! }; } diff --git a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.out b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.out index 1cbf288e774d9..75fd62016a086 100644 --- a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.out +++ b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchErrors.out @@ -1,7 +1,6 @@ PrimitivePatternsSwitchErrors.java:15:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:24:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:31:24: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.Long) -PrimitivePatternsSwitchErrors.java:62:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:70:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:78:18: compiler.err.pattern.dominated PrimitivePatternsSwitchErrors.java:84:18: compiler.err.prob.found.req: (compiler.misc.possible.loss.of.precision: long, byte) @@ -44,4 +43,4 @@ PrimitivePatternsSwitchErrors.java:254:16: compiler.err.not.exhaustive PrimitivePatternsSwitchErrors.java:260:16: compiler.err.not.exhaustive - compiler.note.preview.filename: PrimitivePatternsSwitchErrors.java, DEFAULT - compiler.note.preview.recompile -44 errors +43 errors \ No newline at end of file diff --git a/test/langtools/tools/javac/patterns/T8332463a.java b/test/langtools/tools/javac/patterns/T8332463a.java new file mode 100644 index 0000000000000..96aaad86a855b --- /dev/null +++ b/test/langtools/tools/javac/patterns/T8332463a.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, 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 8332463 + * @summary Byte conditional pattern case element dominates short constant case element + * @compile --enable-preview --source ${jdk.version} T8332463a.java + */ +public class T8332463a { + public int test2() { + Byte i = (byte) 42; + return switch (i) { + case Byte ib -> 1; + case short s -> 2; + }; + } + + public int test4() { + int i = 42; + return switch (i) { + case Integer ib -> 1; + case byte ip -> 2; + }; + } + + public int test3() { + int i = 42; + return switch (i) { + case Integer ib -> 1; + case (byte) 0 -> 2; + }; + } +} diff --git a/test/langtools/tools/javac/patterns/T8332463b.java b/test/langtools/tools/javac/patterns/T8332463b.java new file mode 100644 index 0000000000000..7956fd31f9f38 --- /dev/null +++ b/test/langtools/tools/javac/patterns/T8332463b.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, 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 8332463 + * @summary Byte conditional pattern case element dominates short constant case element + * @enablePreview + * @compile T8332463b.java + * @compile --enable-preview --source ${jdk.version} T8332463b.java + */ +public class T8332463b { + public int test1() { + Byte i = (byte) 42; + return switch (i) { + case Byte ib -> 1; + case (short) 0 -> 2; + }; + } +} diff --git a/test/langtools/tools/javac/patterns/UninitializedThisException.java b/test/langtools/tools/javac/patterns/UninitializedThisException.java new file mode 100644 index 0000000000000..b0acba4e1b174 --- /dev/null +++ b/test/langtools/tools/javac/patterns/UninitializedThisException.java @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2024, 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 8332106 + * @summary Verify the synthetic catch clauses are generated correctly for constructors + * @enablePreview + * @compile UninitializedThisException.java + * @run main UninitializedThisException + */ + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Objects; +import java.util.function.Supplier; + +public class UninitializedThisException extends Base { + + public UninitializedThisException(String s1, String s2) { + super(s1, s2); + } + + public UninitializedThisException(R o1, R o2, R o3) { + out.println("-pre(" + o1.fail() + ")" + + "-nest(" + o2.fail() + ")" + + "-post(" + o3.fail() + ")"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + this(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, R o2, R o3) { + out.println("-nest(" + o2.fail() + ")" + + "-post(" + o3.fail() + ")"); + String val1 = o1; + out.println("check1"); + this(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, String o2, R o3) { + out.println("-pre(" + o1.fail() + ")" + + "-post(" + o3.fail() + ")"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + this(val1, o2); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, R o2, String o3) { + out.println("-pre(" + o1.fail() + ")" + + "-nest(" + o2.fail() + ")"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + this(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, String o2, String o3) { + out.println("-pre(" + o1.fail() + ")"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + this(val1, o2); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, R o2, String o3) { + out.println("-nest(" + o2.fail() + ")"); + String val1 = o1; + out.println("check1"); + this(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, String o2, R o3) { + out.println("-post(" + o3.fail() + ")"); + String val1 = o1; + out.println("check1"); + this(val1, o2); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, R o2, R o3, boolean superMarker) { + out.println("-pre(" + o1.fail() + ")" + + "-nest(" + o2.fail() + ")" + + "-post(" + o3.fail() + ")" + + "-super"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + super(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, R o2, R o3, boolean superMarker) { + out.println("-nest(" + o2.fail() + ")" + + "-post(" + o3.fail() + ")" + + "-super"); + String val1 = o1; + out.println("check1"); + super(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, String o2, R o3, boolean superMarker) { + out.println("-pre(" + o1.fail() + ")" + + "-post(" + o3.fail() + ")" + + "-super"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + super(val1, o2); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, R o2, String o3, boolean superMarker) { + out.println("-pre(" + o1.fail() + ")" + + "-nest(" + o2.fail() + ")" + + "-super"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + super(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, String o2, String o3, boolean superMarker) { + out.println("-pre(" + o1.fail() + ")" + + "-super"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + super(val1, o2); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, R o2, String o3, boolean superMarker) { + out.println("-nest(" + o2.fail() + ")" + + "-super"); + String val1 = o1; + out.println("check1"); + super(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, String o2, R o3, boolean superMarker) { + out.println("-post(" + o3.fail() + ")" + + "-super"); + String val1 = o1; + out.println("check1"); + super(val1, o2); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public static void main(String... args) { + runAndCatch(() -> new UninitializedThisException(new R("", true), new R("", false), new R("", false))); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", true), new R("", false))); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", false), new R("", true))); + new UninitializedThisException(new R("", false), new R("", false), new R("", false)); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", new R("", true), new R("", false))); + runAndCatch(() -> new UninitializedThisException("", new R("", false), new R("", true))); + new UninitializedThisException("", new R("", false), new R("", false)); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), "", new R("", false))); + runAndCatch(() -> new UninitializedThisException(new R("", false), "", new R("", true))); + new UninitializedThisException(new R("", false), "", new R("", false)); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), new R("", false), "")); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", true), "")); + new UninitializedThisException(new R("", false), new R("", false), ""); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), "", "")); + new UninitializedThisException(new R("", false), "", ""); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", new R("", true), "")); + new UninitializedThisException("", new R("", false), ""); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", "", new R("", true))); + new UninitializedThisException("", "", new R("", false)); + + runAndCatch(() -> new UninitializedThisException(new R("", true), new R("", false), new R("", false), true)); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", true), new R("", false), true)); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", false), new R("", true), true)); + new UninitializedThisException(new R("", false), new R("", false), new R("", false), true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", new R("", true), new R("", false), true)); + runAndCatch(() -> new UninitializedThisException("", new R("", false), new R("", true), true)); + new UninitializedThisException("", new R("", false), new R("", false), true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), "", new R("", false), true)); + runAndCatch(() -> new UninitializedThisException(new R("", false), "", new R("", true), true)); + new UninitializedThisException(new R("", false), "", new R("", false), true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), new R("", false), "", true)); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", true), "", true)); + new UninitializedThisException(new R("", false), new R("", false), "", true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), "", "", true)); + new UninitializedThisException(new R("", false), "", "", true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", new R("", true), "", true)); + new UninitializedThisException("", new R("", false), "", true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", "", new R("", true), true)); + new UninitializedThisException("", "", new R("", false), true); + + String actualLog = log.toString().replaceAll("\\R", "\n"); + String expectedLog = EXPECTED_LOG_PATTERN.replace("${super}", "") + + EXPECTED_LOG_PATTERN.replace("${super}", "-super"); + + if (!Objects.equals(actualLog, expectedLog)) { + throw new AssertionError("Expected log:\n" + expectedLog + + ", but got: " + actualLog); + } + } + + static final String EXPECTED_LOG_PATTERN = + """ + -pre(true)-nest(false)-post(false)${super} + -pre(false)-nest(true)-post(false)${super} + check1 + -pre(false)-nest(false)-post(true)${super} + check1 + check2 + -pre(false)-nest(false)-post(false)${super} + check1 + check2 + check3 + + -nest(true)-post(false)${super} + check1 + -nest(false)-post(true)${super} + check1 + check2 + -nest(false)-post(false)${super} + check1 + check2 + check3 + + -pre(true)-post(false)${super} + -pre(false)-post(true)${super} + check1 + check2 + -pre(false)-post(false)${super} + check1 + check2 + check3 + + -pre(true)-nest(false)${super} + -pre(false)-nest(true)${super} + check1 + -pre(false)-nest(false)${super} + check1 + check2 + check3 + + -pre(true)${super} + -pre(false)${super} + check1 + check2 + check3 + + -nest(true)${super} + check1 + -nest(false)${super} + check1 + check2 + check3 + + -post(true)${super} + check1 + check2 + -post(false)${super} + check1 + check2 + check3 + """; + + static final StringWriter log = new StringWriter(); + static final PrintWriter out = new PrintWriter(log); + + static void runAndCatch(Supplier toRun) { + try { + toRun.get(); + throw new AssertionError("Didn't get the expected exception!"); + } catch (MatchException ex) { + //OK + } + } + record R(String s, boolean fail) { + public String s() { + if (fail) { + throw new NullPointerException(); + } else { + return s; + } + } + } +} +class Base { + public Base(String s1, String s2) { + Objects.requireNonNull(s1); + Objects.requireNonNull(s2); + } +} diff --git a/test/langtools/tools/javac/platform/ModuleVersionTest.java b/test/langtools/tools/javac/platform/ModuleVersionTest.java index 1b01fc397e84f..0e8f8b8c05f0b 100644 --- a/test/langtools/tools/javac/platform/ModuleVersionTest.java +++ b/test/langtools/tools/javac/platform/ModuleVersionTest.java @@ -103,7 +103,7 @@ public class Test { ClassModel clazz = ClassFile.of().parse(moduleInfo); assertTrue(clazz.isModuleInfo()); - ModuleAttribute module = clazz.findAttribute(Attributes.MODULE).get(); + ModuleAttribute module = clazz.findAttribute(Attributes.module()).get(); ModuleRequireInfo req = module.requires().get(0); assertEquals("java.base", req.requires().name().stringValue()); assertEquals(expectedVersion, req.requiresVersion().get().stringValue()); diff --git a/test/langtools/tools/javac/processing/RecordGenerationTest.java b/test/langtools/tools/javac/processing/RecordGenerationTest.java new file mode 100644 index 0000000000000..9ee28d264cbeb --- /dev/null +++ b/test/langtools/tools/javac/processing/RecordGenerationTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2024, 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 8332297 + * @summary annotation processor that generates records sometimes fails due to NPE in javac + * @library /tools/lib /tools/javac/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask toolbox.Task + * @build RecordGenerationTest JavacTestingAbstractProcessor + * @run main RecordGenerationTest + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; + +import javax.annotation.processing.FilerException; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedOptions; +import javax.annotation.processing.SupportedAnnotationTypes; + +import javax.lang.model.element.TypeElement; +import javax.tools.StandardLocation; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class RecordGenerationTest { + public static void main(String... args) throws Exception { + new RecordGenerationTest().run(); + } + + Path[] findJavaFiles(Path... paths) throws Exception { + return tb.findJavaFiles(paths); + } + + ToolBox tb = new ToolBox(); + + void run() throws Exception { + Path allInOne = Paths.get("allInOne"); + if (Files.isDirectory(allInOne)) { + tb.cleanDirectory(allInOne); + } + Files.deleteIfExists(allInOne); + tb.createDirectories(allInOne); + + tb.writeJavaFiles(allInOne, + """ + import java.io.IOException; + import java.io.OutputStream; + import java.io.Writer; + import java.nio.file.Files; + import java.nio.file.Path; + import java.nio.file.Paths; + import java.util.Set; + + import javax.annotation.processing.AbstractProcessor; + import javax.annotation.processing.FilerException; + import javax.annotation.processing.RoundEnvironment; + import javax.annotation.processing.SupportedOptions; + import javax.annotation.processing.SupportedAnnotationTypes; + + import javax.lang.model.element.TypeElement; + import javax.tools.StandardLocation; + + @SupportedAnnotationTypes("*") + public class AP extends AbstractProcessor { + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + try (Writer w = processingEnv.getFiler().createSourceFile("ConfRecord").openWriter()) { + w.append("@RecordBuilder public record ConfRecord(int maxConcurrency) implements Conf {}"); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + return true; + } + } + """ + ); + + new JavacTask(tb).options("-d", allInOne.toString()) + .files(findJavaFiles(allInOne)) + .run() + .writeAll(); + + tb.writeJavaFiles(allInOne, + """ + interface Conf { + int maxConcurrency( ); + } + """, + """ + import java.lang.annotation.*; + public @interface RecordBuilder { + } + """ + ); + + Path confSource = Paths.get(allInOne.toString(), "Conf.java"); + new JavacTask(tb).options("-processor", "AP", + "-cp", allInOne.toString(), + "-d", allInOne.toString()) + .files(confSource) + .run() + .writeAll(); + + /* the bug reported at JDK-8332297 was reproducible only every other time this is why we reproduce + * the same compilation command as above basically the second time the compiler is completing the + * record symbol from the class file produced during the first compilation + */ + new JavacTask(tb).options("-processor", "AP", + "-cp", allInOne.toString(), + "-d", allInOne.toString()) + .files(confSource) + .run() + .writeAll(); + } +} diff --git a/test/langtools/tools/javac/processing/model/TestSymtabItems.java b/test/langtools/tools/javac/processing/model/TestSymtabItems.java index ce20063b9b9cb..ba9bb20230bdf 100644 --- a/test/langtools/tools/javac/processing/model/TestSymtabItems.java +++ b/test/langtools/tools/javac/processing/model/TestSymtabItems.java @@ -85,6 +85,10 @@ void run() throws Exception { if (f.getName().toLowerCase().contains("methodhandle")) continue; + // Temporarily ignore java.io.IO: + if (f.getName().equals("ioType")) + continue; + //both noModule and unnamedModule claim the unnamed package, ignore noModule for now: if (f.getName().equals("noModule")) continue; diff --git a/test/langtools/tools/javac/processing/model/element/TestOrigin.java b/test/langtools/tools/javac/processing/model/element/TestOrigin.java index ba4d7ec7ef979..1fae5374bea33 100644 --- a/test/langtools/tools/javac/processing/model/element/TestOrigin.java +++ b/test/langtools/tools/javac/processing/model/element/TestOrigin.java @@ -276,7 +276,7 @@ public void testModuleDirectives(Path base) throws Exception { Path moduleInfo = classes.resolve("module-info.class"); ClassModel cf = ClassFile.of().parse(moduleInfo); - ModuleAttribute module = cf.findAttribute(Attributes.MODULE).orElseThrow(); + ModuleAttribute module = cf.findAttribute(Attributes.module()).orElseThrow(); List newRequires = new ArrayList<>(3); newRequires.add(ModuleRequireInfo.of(module.requires().get(0).requires(), ClassFile.ACC_MANDATED, module.requires().get(0).requiresVersion().orElse(null))); diff --git a/test/langtools/tools/javac/records/RecordCompilationTests.java b/test/langtools/tools/javac/records/RecordCompilationTests.java index 0436169556ff0..9f5e73cc5d0ba 100644 --- a/test/langtools/tools/javac/records/RecordCompilationTests.java +++ b/test/langtools/tools/javac/records/RecordCompilationTests.java @@ -1320,7 +1320,7 @@ void testCheckInitializationOrderInCompactConstructor() throws Exception { ClassModel classFile = ClassFile.of().parse(fileEntry.toPath()); for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString("")) { - CodeAttribute code_attribute = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = method.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : code_attribute.elementList()) { if (ce instanceof Instruction instruction && instruction.opcode() == Opcode.PUTFIELD) { if (putField1 != null && putField2 != null) { diff --git a/test/langtools/tools/javac/records/recordComponent/RecordComponentTypeTest.java b/test/langtools/tools/javac/records/recordComponent/RecordComponentTypeTest.java index f11c464231f3d..015dc805eeadc 100644 --- a/test/langtools/tools/javac/records/recordComponent/RecordComponentTypeTest.java +++ b/test/langtools/tools/javac/records/recordComponent/RecordComponentTypeTest.java @@ -155,7 +155,7 @@ public record RecordComponentUsingGeneratedTypeWithAnnotation(@TestAnnotation Ge } private void checkRuntimeVisibleAnnotation(AttributedElement attributedElement) throws Exception { - RuntimeVisibleAnnotationsAttribute annotations = attributedElement.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElseThrow(); + RuntimeVisibleAnnotationsAttribute annotations = attributedElement.findAttribute(Attributes.runtimeVisibleAnnotations()).orElseThrow(); boolean hasAnnotation = false; for (Annotation annotation : annotations.annotations()) { if (annotation.classSymbol().descriptorString().equals("LTestAnnotation;")) { diff --git a/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java b/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java index 16860d65cc232..6cec46ef2d14b 100644 --- a/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java +++ b/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java @@ -133,7 +133,7 @@ public void testSameCompilationUnitPos2(Path base) throws Exception { private void checkSealedClassFile(Path out, String cfName, List expectedSubTypeNames) throws ConstantPoolException, Exception { ClassModel sealedCF = ClassFile.of().parse(out.resolve(cfName)); Assert.check((sealedCF.flags().flagsMask() & ClassFile.ACC_FINAL) == 0, String.format("class at file %s must not be final", cfName)); - PermittedSubclassesAttribute permittedSubclasses = sealedCF.findAttribute(Attributes.PERMITTED_SUBCLASSES).orElseThrow(); + PermittedSubclassesAttribute permittedSubclasses = sealedCF.findAttribute(Attributes.permittedSubclasses()).orElseThrow(); Assert.check(permittedSubclasses.permittedSubclasses().size() == expectedSubTypeNames.size()); List subtypeNames = new ArrayList<>(); permittedSubclasses.permittedSubclasses().forEach(i -> { @@ -152,7 +152,7 @@ private void checkSubtypeClassFile(Path out, String cfName, String superClassNam if (shouldBeFinal) { Assert.check((subCF1.flags().flagsMask() & ClassFile.ACC_FINAL) != 0, String.format("class at file %s must be final", cfName)); } - Assert.checkNull(subCF1.findAttribute(Attributes.PERMITTED_SUBCLASSES).orElse(null)); + Assert.checkNull(subCF1.findAttribute(Attributes.permittedSubclasses()).orElse(null)); Assert.check(subCF1.superclass().orElseThrow().name().equalsString(superClassName)); } diff --git a/test/langtools/tools/javac/varargs/6199075/T6199075.java b/test/langtools/tools/javac/varargs/6199075/T6199075.java index d2eaab364f5e0..6e77280eea50b 100644 --- a/test/langtools/tools/javac/varargs/6199075/T6199075.java +++ b/test/langtools/tools/javac/varargs/6199075/T6199075.java @@ -226,7 +226,7 @@ void verifyBytecode(VarargsMethod selected) { if (testMethod == null) { throw new Error("Test method not found"); } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { throw new Error("Code attribute for test() method not found"); } diff --git a/test/langtools/tools/javac/varargs/7042566/T7042566.java b/test/langtools/tools/javac/varargs/7042566/T7042566.java index 845cab3bdf847..41c8e9609cacd 100644 --- a/test/langtools/tools/javac/varargs/7042566/T7042566.java +++ b/test/langtools/tools/javac/varargs/7042566/T7042566.java @@ -282,7 +282,7 @@ void verifyBytecode(Result> res, VarargsMetho fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; diff --git a/test/langtools/tools/javap/T6716452.java b/test/langtools/tools/javap/T6716452.java index 4cc8f4ec41d9c..63ccead52e7bb 100644 --- a/test/langtools/tools/javap/T6716452.java +++ b/test/langtools/tools/javap/T6716452.java @@ -51,8 +51,8 @@ public void run() throws Exception { } void test(MethodModel mm) { - test(mm, Attributes.CODE, CodeAttribute.class); - test(mm, Attributes.EXCEPTIONS, ExceptionsAttribute.class); + test(mm, Attributes.code(), CodeAttribute.class); + test(mm, Attributes.exceptions(), ExceptionsAttribute.class); } // test the result of MethodModel.findAttribute, MethodModel.attributes().indexOf() according to expectations diff --git a/test/langtools/tools/javap/classfile/6888367/T6888367.java b/test/langtools/tools/javap/classfile/6888367/T6888367.java index 16bc06321cab3..3e3e3adcd7a67 100644 --- a/test/langtools/tools/javap/classfile/6888367/T6888367.java +++ b/test/langtools/tools/javap/classfile/6888367/T6888367.java @@ -85,7 +85,7 @@ void testMethods(ClassModel cm) throws Exception { void testInnerClasses(ClassModel cm) throws Exception { InnerClassesAttribute ic = - cm.findAttribute(Attributes.INNER_CLASSES).orElse(null); + cm.findAttribute(Attributes.innerClasses()).orElse(null); assert ic != null; for (InnerClassInfo info: ic.classes()) { ClassEntry outerClass = info.outerClass().orElse(null); @@ -106,7 +106,7 @@ void test(String name, ConstantDesc desc, AttributedElement m) { return; System.err.println(name); - SignatureAttribute sa = m.findAttribute(Attributes.SIGNATURE).orElse(null); + SignatureAttribute sa = m.findAttribute(Attributes.signature()).orElse(null); if (sa != null) System.err.println(" signature: " + sa.signature()); @@ -173,7 +173,7 @@ static class AnnotValues { } AnnotValues getAnnotValues(String annotName, AttributedElement m) { - RuntimeInvisibleAnnotationsAttribute annots = m.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + RuntimeInvisibleAnnotationsAttribute annots = m.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (annots != null) { for (Annotation a: annots.annotations()) { if (a.classSymbol().descriptorString().equals("L" + annotName + ";")) { diff --git a/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java b/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java index 1aa3ddbebd8dc..1f5b2f43958d4 100644 --- a/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java +++ b/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java @@ -58,8 +58,8 @@ public void run() throws Exception { } void test(AttributedElement m) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.runtimeVisibleTypeAnnotations()); + test(m, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of AttributedElement.findAttribute according to expectations diff --git a/test/langtools/tools/javap/typeAnnotations/NewArray.java b/test/langtools/tools/javap/typeAnnotations/NewArray.java index 7a5ca4675ce0a..cf08baf29550d 100644 --- a/test/langtools/tools/javap/typeAnnotations/NewArray.java +++ b/test/langtools/tools/javap/typeAnnotations/NewArray.java @@ -52,8 +52,8 @@ public void run() throws Exception { } void test(MethodModel mm) { - test(mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(mm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(mm, Attributes.runtimeVisibleTypeAnnotations()); + test(mm, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of Attributes.getIndex according to expectations @@ -62,7 +62,7 @@ > void test(MethodModel mm, AttributeMapper attr_name) Attribute attr_instance; CodeAttribute cAttr; - cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + cAttr = mm.findAttribute(Attributes.code()).orElse(null); if (cAttr != null) { attr_instance = cAttr.findAttribute(attr_name).orElse(null); if (attr_instance != null) { diff --git a/test/langtools/tools/javap/typeAnnotations/Presence.java b/test/langtools/tools/javap/typeAnnotations/Presence.java index 7b144457070b4..2fb488e705e96 100644 --- a/test/langtools/tools/javap/typeAnnotations/Presence.java +++ b/test/langtools/tools/javap/typeAnnotations/Presence.java @@ -59,8 +59,8 @@ public void run() throws Exception { } void test(AttributedElement m) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.runtimeVisibleTypeAnnotations()); + test(m, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of AttributedElement.findAttribute according to expectations @@ -80,7 +80,7 @@ > void test(AttributedElement m, AttributeMapper attr_ } } if (m instanceof MethodModel) { - attr_instance = m.findAttribute(Attributes.CODE).orElse(null); + attr_instance = m.findAttribute(Attributes.code()).orElse(null); if(attr_instance!= null) { CodeAttribute cAttr = (CodeAttribute)attr_instance; attr_instance = cAttr.findAttribute(attr_name).orElse(null); diff --git a/test/langtools/tools/javap/typeAnnotations/PresenceInner.java b/test/langtools/tools/javap/typeAnnotations/PresenceInner.java index a47a5ea9f539a..ccb795346166c 100644 --- a/test/langtools/tools/javap/typeAnnotations/PresenceInner.java +++ b/test/langtools/tools/javap/typeAnnotations/PresenceInner.java @@ -71,8 +71,8 @@ public void run() throws Exception { } void test(AttributedElement m) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.runtimeVisibleTypeAnnotations()); + test(m, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of AttributedElement.findAttribute according to expectations diff --git a/test/langtools/tools/javap/typeAnnotations/TypeCasts.java b/test/langtools/tools/javap/typeAnnotations/TypeCasts.java index 6d318107c92d1..c8ee0fde965b2 100644 --- a/test/langtools/tools/javap/typeAnnotations/TypeCasts.java +++ b/test/langtools/tools/javap/typeAnnotations/TypeCasts.java @@ -55,8 +55,8 @@ public void run() throws Exception { } void test(MethodModel mm) { - test(mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(mm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(mm, Attributes.runtimeVisibleTypeAnnotations()); + test(mm, Attributes.runtimeInvisibleTypeAnnotations()); } @@ -66,7 +66,7 @@ > void test(MethodModel mm, AttributeMapper attr_name) Attribute attr; CodeAttribute cAttr; - cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + cAttr = mm.findAttribute(Attributes.code()).orElse(null); if (cAttr != null) { attr = cAttr.findAttribute(attr_name).orElse(null); if (attr != null) { diff --git a/test/langtools/tools/javap/typeAnnotations/Visibility.java b/test/langtools/tools/javap/typeAnnotations/Visibility.java index d2f16b49d9b71..ebffbf9176dcc 100644 --- a/test/langtools/tools/javap/typeAnnotations/Visibility.java +++ b/test/langtools/tools/javap/typeAnnotations/Visibility.java @@ -55,8 +55,8 @@ public void run() throws Exception { } void test(MethodModel mm) { - test(mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(mm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(mm, Attributes.runtimeVisibleTypeAnnotations()); + test(mm, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of mm.findAttribute according to expectations diff --git a/test/langtools/tools/javap/typeAnnotations/Wildcards.java b/test/langtools/tools/javap/typeAnnotations/Wildcards.java index 8ef0bb61e075c..6bbabebdd372e 100644 --- a/test/langtools/tools/javap/typeAnnotations/Wildcards.java +++ b/test/langtools/tools/javap/typeAnnotations/Wildcards.java @@ -56,8 +56,8 @@ public void run() throws Exception { System.out.println("PASSED"); } void test(AttributedElement m) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.runtimeVisibleTypeAnnotations()); + test(m, Attributes.runtimeInvisibleTypeAnnotations()); } > void test(AttributedElement m, AttributeMapper attr_name) { Attribute attr_instance = m.findAttribute(attr_name).orElse(null); diff --git a/test/lib/jdk/test/lib/StringArrayUtils.java b/test/lib/jdk/test/lib/StringArrayUtils.java new file mode 100644 index 0000000000000..11124701dceba --- /dev/null +++ b/test/lib/jdk/test/lib/StringArrayUtils.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023, 2024, 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 jdk.test.lib; + +import java.util.ArrayList; + +public class StringArrayUtils { + /** + * The various concat() functions in this class can be used for building + * a command-line argument array for ProcessTools.createTestJavaProcessBuilder(), + * etc. When some of the arguments are conditional, this is more convenient + * than alternatives like ArrayList. + * + * Example: + * + *
    +     *     String args[] = StringArrayUtils.concat("-Xint", "-Xmx32m");
    +     *     if (verbose) {
    +     *         args = StringArrayUtils.concat(args, "-verbose");
    +     *     }
    +     *     args = StringArrayUtils.concat(args, "HelloWorld");
    +     *     ProcessTools.createTestJavaProcessBuilder(args);
    +     * 
    + */ + public static String[] concat(String... args) { + return args; + } + + public static String[] concat(String[] prefix, String... extra) { + String[] ret = new String[prefix.length + extra.length]; + System.arraycopy(prefix, 0, ret, 0, prefix.length); + System.arraycopy(extra, 0, ret, prefix.length, extra.length); + return ret; + } + + public static String[] concat(String prefix, String[] extra) { + String[] ret = new String[1 + extra.length]; + ret[0] = prefix; + System.arraycopy(extra, 0, ret, 1, extra.length); + return ret; + } +} diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java new file mode 100644 index 0000000000000..c39e6bb8e9489 --- /dev/null +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.java @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2023, 2024, 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 jdk.test.lib.cds; + +import java.io.File; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.StringArrayUtils; + +/* + * This is a base class used for testing CDS functionalities with complex applications. + * You can define the application by overridding the vmArgs(), classpath() and appCommandLine() + * methods. Application-specific validation checks can be implemented with checkExecution(). +*/ +abstract public class CDSAppTester { + private final String name; + private final String classListFile; + private final String classListFileLog; + private final String staticArchiveFile; + private final String staticArchiveFileLog; + private final String dynamicArchiveFile; + private final String dynamicArchiveFileLog; + private final String productionRunLog; + + public CDSAppTester(String name) { + // Old workflow + this.name = name; + classListFile = name() + ".classlist"; + classListFileLog = classListFile + ".log"; + staticArchiveFile = name() + ".static.jsa"; + staticArchiveFileLog = staticArchiveFile + ".log"; + dynamicArchiveFile = name() + ".dynamic.jsa"; + dynamicArchiveFileLog = dynamicArchiveFile + ".log"; + productionRunLog = name() + ".production.log"; + } + + private enum Workflow { + STATIC, // classic -Xshare:dump workflow + DYNAMIC, // classic -XX:ArchiveClassesAtExit + } + + public enum RunMode { + CLASSLIST, + DUMP_STATIC, + DUMP_DYNAMIC, + PRODUCTION; + + public boolean isStaticDump() { + return this == DUMP_STATIC; + } + public boolean isProductionRun() { + return this == PRODUCTION; + } + } + + public final String name() { + return this.name; + } + + // optional + public String[] vmArgs(RunMode runMode) { + return new String[0]; + } + + // optional + public String classpath(RunMode runMode) { + return null; + } + + // must override + // main class, followed by arguments to the main class + abstract public String[] appCommandLine(RunMode runMode); + + // optional + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {} + + private Workflow workflow; + + public final boolean isStaticWorkflow() { + return workflow == Workflow.STATIC; + } + + public final boolean isDynamicWorkflow() { + return workflow == Workflow.DYNAMIC; + } + + private String logToFile(String logFile, String... logTags) { + StringBuilder sb = new StringBuilder("-Xlog:"); + String prefix = ""; + for (String tag : logTags) { + sb.append(prefix); + sb.append(tag); + prefix = ","; + } + sb.append(":file=" + logFile + "::filesize=0"); + return sb.toString(); + } + + private void listOutputFile(String file) { + File f = new File(file); + if (f.exists()) { + System.out.println("[output file: " + file + " " + f.length() + " bytes]"); + } else { + System.out.println("[output file: " + file + " does not exist]"); + } + } + + private OutputAnalyzer executeAndCheck(String[] cmdLine, RunMode runMode, String... logFiles) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(cmdLine); + Process process = pb.start(); + OutputAnalyzer output = CDSTestUtils.executeAndLog(process, runMode.toString()); + for (String logFile : logFiles) { + listOutputFile(logFile); + } + output.shouldHaveExitValue(0); + CDSTestUtils.checkCommonExecExceptions(output); + checkExecution(output, runMode); + return output; + } + + private OutputAnalyzer createClassList() throws Exception { + RunMode runMode = RunMode.CLASSLIST; + String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xshare:off", + "-XX:DumpLoadedClassList=" + classListFile, + "-cp", classpath(runMode), + logToFile(classListFileLog, + "class+load=debug")); + cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); + return executeAndCheck(cmdLine, runMode, classListFile, classListFileLog); + } + + private OutputAnalyzer dumpStaticArchive() throws Exception { + RunMode runMode = RunMode.DUMP_STATIC; + String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xlog:cds", + "-Xlog:cds+heap=error", + "-Xshare:dump", + "-XX:SharedArchiveFile=" + staticArchiveFile, + "-XX:SharedClassListFile=" + classListFile, + "-cp", classpath(runMode), + logToFile(staticArchiveFileLog, + "cds=debug", + "cds+class=debug", + "cds+heap=warning", + "cds+resolve=debug")); + return executeAndCheck(cmdLine, runMode, staticArchiveFile, staticArchiveFileLog); + } + + private OutputAnalyzer dumpDynamicArchive() throws Exception { + RunMode runMode = RunMode.DUMP_DYNAMIC; + String[] cmdLine = new String[0]; + if (isDynamicWorkflow()) { + // "classic" dynamic archive + cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xlog:cds", + "-XX:ArchiveClassesAtExit=" + dynamicArchiveFile, + "-cp", classpath(runMode), + logToFile(dynamicArchiveFileLog, + "cds=debug", + "cds+class=debug", + "cds+resolve=debug", + "class+load=debug")); + } + cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); + return executeAndCheck(cmdLine, runMode, dynamicArchiveFile, dynamicArchiveFileLog); + } + + private OutputAnalyzer productionRun() throws Exception { + RunMode runMode = RunMode.PRODUCTION; + String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-cp", classpath(runMode), + logToFile(productionRunLog, "cds")); + + if (isStaticWorkflow()) { + cmdLine = StringArrayUtils.concat(cmdLine, "-XX:SharedArchiveFile=" + staticArchiveFile); + } else if (isDynamicWorkflow()) { + cmdLine = StringArrayUtils.concat(cmdLine, "-XX:SharedArchiveFile=" + dynamicArchiveFile); + } + + cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); + return executeAndCheck(cmdLine, runMode, productionRunLog); + } + + public void run(String args[]) throws Exception { + String err = "Must have exactly one command line argument of the following: "; + String prefix = ""; + for (Workflow wf : Workflow.values()) { + err += prefix; + err += wf; + prefix = ", "; + } + if (args.length != 1) { + throw new RuntimeException(err); + } else { + if (args[0].equals("STATIC")) { + runStaticWorkflow(); + } else if (args[0].equals("DYNAMIC")) { + runDynamicWorkflow(); + } else { + throw new RuntimeException(err); + } + } + } + + private void runStaticWorkflow() throws Exception { + this.workflow = Workflow.STATIC; + createClassList(); + dumpStaticArchive(); + productionRun(); + } + + private void runDynamicWorkflow() throws Exception { + this.workflow = Workflow.DYNAMIC; + dumpDynamicArchive(); + productionRun(); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/runtime/SwitchSanity.java b/test/micro/org/openjdk/bench/java/lang/runtime/SwitchSanity.java new file mode 100644 index 0000000000000..7d78cb3e2e018 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/runtime/SwitchSanity.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024, 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.java.lang.runtime; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +@Fork(3) +public class SwitchSanity { + + public record A(int a) { } + public record B(int b) { } + public record C(int c) { } + + public Object[] inputs = new Object[10]; + @Setup + public void setup() { + for (int i = 0; i < 10; i++) { + if (i % 2 == 0) { + inputs[i] = new A(i + 17); + } else if (i % 3 == 0) { + inputs[i] = new B(i + 4711); + } else { + inputs[i] = new C(i + 174711); + } + } + } + + @Benchmark + public int switchSum() { + int sum = 0; + for (Object o : inputs) { + sum += switch (o) { + case A a -> a.a; + case B b -> b.b; + case C c -> c.c; + default -> 17; + }; + } + return sum; + } + + public static void main(String[] args) { + SwitchSanity s = new SwitchSanity(); + s.setup(); + System.out.println(s.switchSum()); + } +} diff --git a/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java b/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java index ab6be0e9374e8..33704ad3f9f7d 100644 --- a/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java +++ b/test/micro/org/openjdk/bench/java/util/zip/InflaterInputStreams.java @@ -108,7 +108,10 @@ public void beforeIteration() throws IOException { @Benchmark public void inflaterInputStreamRead() throws IOException { deflated.reset(); - InflaterInputStream iis = new InflaterInputStream(deflated); - while (iis.read(inflated, 0, inflated.length) != -1); + // We close the InflaterInputStream to release underlying native resources of the Inflater. + // The "deflated" ByteArrayInputStream remains unaffected. + try (InflaterInputStream iis = new InflaterInputStream(deflated)) { + while (iis.read(inflated, 0, inflated.length) != -1); + } } } diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java b/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java new file mode 100644 index 0000000000000..94c247c908022 --- /dev/null +++ b/test/micro/org/openjdk/bench/javax/crypto/full/PolynomialP256Bench.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024, 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.javax.crypto.full; + +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.annotations.Benchmark; +import java.math.BigInteger; +import java.util.concurrent.TimeUnit; +import sun.security.util.math.intpoly.MontgomeryIntegerPolynomialP256; +import sun.security.util.math.intpoly.IntegerPolynomialP256; +import sun.security.util.math.MutableIntegerModuloP; +import sun.security.util.math.ImmutableIntegerModuloP; + +@Fork(jvmArgsAppend = {"-XX:+AlwaysPreTouch", + "--add-exports", "java.base/sun.security.util.math.intpoly=ALL-UNNAMED", + "--add-exports", "java.base/sun.security.util.math=ALL-UNNAMED"}, value = 1) +@Warmup(iterations = 3, time = 3) +@Measurement(iterations = 8, time = 2) +@OutputTimeUnit(TimeUnit.SECONDS) +@State(Scope.Thread) +@BenchmarkMode(Mode.Throughput) +public class PolynomialP256Bench { + final MontgomeryIntegerPolynomialP256 montField = MontgomeryIntegerPolynomialP256.ONE; + final IntegerPolynomialP256 residueField = IntegerPolynomialP256.ONE; + final BigInteger refx = + new BigInteger("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16); + final ImmutableIntegerModuloP x = residueField.getElement(refx); + final ImmutableIntegerModuloP X = montField.getElement(refx); + final ImmutableIntegerModuloP one = montField.get1(); + + @Param({"true", "false"}) + private boolean isMontBench; + + @Benchmark + public MutableIntegerModuloP benchMultiply() { + MutableIntegerModuloP test; + if (isMontBench) { + test = X.mutable(); + } else { + test = x.mutable(); + } + + for (int i = 0; i< 10000; i++) { + test = test.setProduct(test); + } + return test; + } + + @Benchmark + public MutableIntegerModuloP benchSquare() { + MutableIntegerModuloP test; + if (isMontBench) { + test = X.mutable(); + } else { + test = x.mutable(); + } + + for (int i = 0; i< 10000; i++) { + test = test.setSquare(); + } + return test; + } + + @Benchmark + public MutableIntegerModuloP benchAssign() { + MutableIntegerModuloP test1 = X.mutable(); + MutableIntegerModuloP test2 = one.mutable(); + for (int i = 0; i< 10000; i++) { + test1.conditionalSet(test2, 0); + test1.conditionalSet(test2, 1); + test2.conditionalSet(test1, 0); + test2.conditionalSet(test1, 1); + } + return test2; + } +}